─━ IT ━─

지에프(GEF)로 그래픽 편집 플러그인을 만들다

DKel 2021. 8. 16. 00:52
반응형
처음에 GEF(Graphical Editing Framework)는, 그 이름과 같이, 모델을 「그래피컬」로 「편집」하는 애플리케이션(또는 플러그 인)을 작성하기 위한 프레임워크입니다.이 기사에서는, 단순한 GEF 애플리케이션의 작성을 통해, GEF의 개략과 그 사용법을 설명합니다.대상 독자 이클립스 플러그인 및 Draw2D를 사용한 어플리케이션을 만들어보신 적 있으신 분.Draw2D 또는 이클립스 플러그인에 대한 내용은 이클립스 도움말 및 API 문서를 참조하십시오.또, Draw2 D에 관한 상세한 것에 대해서는, GEF SDK에 부속하는 Draw2 D의 프로그래머스·가이드를 참조해 주세요.필요한 환경 샘플은, Eclipse SDK 3.0.1, 및 GEF SDK 3.0.1을 사용해 작성했습니다.그 이전 버전에서는 동작하지 않습니다.GEF 어플리케이션의 개요 첫머리에서도 언급했습니다만, GEF는 모델을 그래피컬하게 편집하는 어플리케이션을 작성하기 위한 프레임워크입니다.GEF 는, UML 다이어그램과 같이, 그래피컬하게 표시·편집되는 것에 적절한 모델을 가지는 애플리케이션을 작성하기 위해서 사용됩니다.GEF 애플리케이션은, MVC(Model-View-Controller) 아키텍쳐(archit)에 근거해 작성된, 「EditPartViewer」라고 불리는 뷰어를 중심으로 작성합니다.MVC 아키텍쳐(architecture)는, GUI 애플리케이션을 「모델」, 「뷰」, 「컨트롤러」의 3개의 요소로 분할하는 생각입니다.또한 Edit Part Viewer 에는 뷰로서 Draw2D 의 피규어를 사용하는 「그래피컬 뷰어」와 SWT 의 Tree Item 을 사용하는 「트리 뷰어」의 2 종류가 준비되어 있습니다.이 중 트리뷰어는 주로 GEF어플리케이션에 이클립스의 ′아웃라인′뷰를 제공하기 위해 사용되는 것입니다.MVC 아키텍처(architecture)에서 모델은 애플리케이션에서 취급하는 데이터입니다.또한 뷰는 모델의 정보를 사용자에게 표시하기 위한 객체, 즉 모델의 외관입니다.컨트롤러는 모델과 뷰를 연결시키고 사용자의 입력에 따라 모델을 변경하는 등의 역할을 합니다.GEF는, 모델의 형태에 의존하지 않는 뷰와 컨트롤러, 및 애플리케이션의 동작에 필요한, 기타 부품으로 구성되어 있습니다.즉, GEF 애플리케이션을 작성하려면 , 스스로 모델을 반입할 필요가 있다는 것입니다.이것에 대해서, 뷰와 콘트롤러에 관해서는, GEF에 준비되어 있는 부품을 모델에 맞추어 커스터마이즈 해 사용합니다.GEF어플리케이션에 있어서의 모델, 뷰 및 컨트롤러의 개략은 이하와 같습니다.모델은 GEF어플리케이션으로 표시·편집되는 데이터 그 자체입니다.GEF 애플리케이션에서, 계속 보관 유지되는 데이터는, 모델뿐입니다.뷰 또는 컨트롤러는 편집 동작에 따라서는 파기, 재작성되므로 일시적인 데이터 이외의 정보를 갖게 할 수 없습니다.같은 이유로 모델은 뷰 및 컨트롤러에 대한 정보를 참조하지 않아야 합니다.또한 모델은 자신의 속성이 변경되었을 때 그것을 통지하는 기능을 포함하고 있어야 합니다.전술한 바와 같이 GEF는 모델의 형태에 의존하지 않으므로 상기 조건을 만족시키면 모델의 정의는 기본적으로 자유롭게 실시할 수 있고, 기존 모델을 반입할 수도 있습니다.뷰는 모델의 속성을 사용자에게 보여주는 역할을 합니다.GEF 에서는, 그래피컬 뷰어내에서는 Draw2D 의 피규어(혹은, 피규어를 복수 조합한 것)가 뷰로서 사용되어 트리·뷰어내에서는, SWT 의 TreeItem 이 뷰로서 사용됩니다.GEF어플리케이션에서의 뷰는 모델의 속성을 표시하기 위한 것이므로 모델이나 컨트롤러에 대한 정보는 아무것도 갖게 하지 않도록 합니다.GEF에서는, 컨트롤러를 「Edit Part」라고 부릅니다.Edit Part는 모델의 정보를 바탕으로 뷰를 만듭니다.또한 모델의 정보에 변경이 있을 경우 뷰에 반영시키는 역할도 합니다.MVC 아키텍처(architecture)에서의 컨트롤러는, 이 외에도 유저로부터의 입력을 처리하고, 모델을 변경한다고 하는 역할도 담당합니다만, GEF에서는, 모델의 편집에 관한 기능의 상당수는, EditPart로부터 분리되고 있습니다.위 그림과 같이 Edit Part는 모델과 뷰의 매핑을 하고 이들을 제어하지만 사용자의 모델 변경요구는 Edit Part가 관리하는 모든 Edit Policy에 전달됩니다.Edit Policy는 사용자의 모델 변경 요구를 처리하고 모델 변경을 하기 위한 명령어를 작성합니다.실제로 모델에 변경을 더하는 것은 명령어의 역할입니다.즉, 모델의 편집기능은 Edit Part가 아니고 Edit Part에 설치되는 Edit Policy에 있다는 뜻입니다.GEF애플리케이션에서의 모델의 편집은, 「툴」, 및 액션에 의해서 행해집니다.툴은 사용자가 수행한 마우스 조작이나 키 조작을 Request라고 불리는 모델의 변경요구를 나타내는 개체로 변환합니다.마찬가지로 액션도 실행된 시점에서 Request를 만듭니다.작성된 Request는 해당 시점에서 선택된 (활성) Edit Part로 전송됩니다.Edit Part는 보내온 Request를 자신에게 설치되어 있는 모든 Edit Policy(각 Edit Policy는 Role이라 불리는 문자열을 키로 설치됩니다)에 전달합니다.Request를 넘겨받은 Edit Policy는 해당 Request가 나타내는 모델의 변경 요구에 따른 명령어를 작성합니다.그 후 명령어가 실행되고 모델이 변경됩니다.GEF 애플리케이션으로 모델에 변경을 더할 수 있는 것은, 커맨드 뿐입니다.모델 변경은 위 그림과 같은 흐름으로 이루어집니다.다음으로, 모델의 편집에 관한, GEF의 요소에 대해 채택합니다.Request는 툴이나 액션에 의해 생성되는 모델의 변경요구를 나타내는 객체입니다.Request는 모델에 대해 어떤 편집 동작을 할 것인지를 보여주는 유형과 그 편집 동작에 필요한 정보를 가지고 있습니다.GEF에는 일반적인 편집 동작에 관한 Request 유형과 해당 유형의 Request를 처리하는데 필요한 정보를 설정할 수 있는 Request 클래스가 준비되어 있습니다.예를 들어 ′모델 만들기 도구′를 사용하여 클릭을 한 경우 모델 만들기 도구에 의해 클릭한 포인트에 모델을 새로 만들기 위한 Request가 생성됩니다.이때 작성되는 Request는 REQ_CREATE 타입의 Request입니다.또한 이런 유형의 Request에는 새로 작성되는 모델의 인스턴스와 모델의 작성 위치 및 사이즈와 같은 정보가 설정되어 있습니다.REQ_CREATE 유형의 Request는 이러한 정보를 얻기 위해 CreateRequest 클래스에 캐스트할 수 있습니다.또한 기본 드래그 도구를 사용하여 Edit Part를 드래그한 경우 드래그 도구를 통해 모델의 위치정보를 변경하기 위한 Request가 생성됩니다.이때 생성되는 Request는 REQ_MOVE 혹은 REQ_MOVE_CHILDREN 타입으로 Change Bounds Request 클래스에 캐스트하여 이동위치정보를 얻을 수 있습니다.이러한 Request 유형 또는 그 작업을 수행하는데 필요한 정보는 Edit Policy가 명령어를 작성할 때 사용됩니다.GEF에는 이 밖에도 여러 Request 유형과 해당 유형의 Request를 처리하는데 필요한 정보를 설정할 수 있는 Request 클래스가 준비되어 있습니다.모든 Request 타입 및 Request 클래스에 대해서는, GEF SDK에 부속되는 「GEF Developers Guide」의 「Programmer′s Guide」와 API 문서를 참조해 주세요.그리고 응용 프로그램에 따라서는 자체 Request 유형과 Request 클래스가 필요할 수도 있습니다.Request 유형은 단순한 문자열이므로 Request Constants 인터페이스에 정의된 기존 유형 문자열과 중복되지 않도록 하면 자체 Request 유형을 정의할 수 있습니다.또한 Request 클래스에 관해서는 org.eclipse.gef.Request 클래스의 서브클래스를 작성하여 해당 유형의 Request를 처리하는데 필요한 정보를 유지할 수 있도록 합니다.Edit Policy는 Edit Part가 무엇을 하는지 혹은 Edit Part가 모델을 어떻게 편집하는지와 같은 Edit Part의 동작을 정의하기 위한 플래거블 오브젝트입니다.Edit Part는 Edit Policy를 설치하면 모델의 편집기능을 갖게 됩니다.구체적으로 Edit Policy는 툴 또는 액션에 의해 작성된 모델의 변경 요구(Request)를 처리하고 모델을 변경하기 위한 명령어를 작성하는 역할과 필요에 따라 사용자의 조작 내용을 시각적으로 표현하기 위한 피드백을 표시하는 역할을 합니다.Edit Policy는 하나의 Edit Part에 여러 개 설치할 수 있습니다.각각의 Edit Policy는 ′Role′이라 불리는 문자열에 의해 식별됩니다.앞서 말한 것처럼 Edit Policy에는 편집 동작의 종류에 따라 다양한 타입의 Request가 전송되게 됩니다.모든 유형의 Request를 하나의 Edit Policy로 처리할 수도 있지만, Role을 키로 Edit Policy를 설치하면 Request의 처리를 관련된 Request 유형별로 그룹으로 분할하여 여러 Edit Policy로 나누어 수행할 수 있습니다.또한 Edit Policy는 Role을 키로 동적으로 교체하거나 제거할 수 있습니다.따라서 모델의 상태에 따라 모델의 편집방침을 변경할 수도 있습니다.예를 들어, 모델의 속성에 따라 레이아웃 방법을 XY Layout에서 Flow Layout으로 변경하는 경우가 있다고 하겠습니다.이 경우, XY Layout이면 자녀의 이동은 모델의 위치 정보 변경을 의미하지만, Flow Layout의 경우 자녀의 이동은 모델의 순서 변경을 의미할 것입니다.따라서 자녀의 이동요구를 나타내는 Request(REQ_MOVE_CHILDREN)를 처리하는 방법도, 실행해야 할 명령도 다르게 될 것입니다.이런 경우 레이아웃과 관련된 Request를 한꺼번에 처리하는 Edit Policy를 XY Layout용으로 만들어 두면 레이아웃 변경 시 이러한 Edit Policy를 동적으로 교체하여 모델의 편집방침을 변경할 수 있습니다.또한 레이아웃에 영향을 받지 않는 모델의 변경 요구를 다른 Role을 키로 설치되는 Edit Policy로 처리하도록 해 두면 위와 같은 Edit Policy의 교체가 이루어진다 해도 그 부분의 편집 기능에는 전혀 영향이 없습니다.또한 공통된 편집 동작이 필요한 Edit Part가 있으면 슈퍼클래스에서 공통되는 편집 동작을 정의한 Edit Policy를 설치하고, 서브클래스에서 각각 고유한 편집 동작을 정의한 Edit Policy를 설치하는 것도 가능합니다.처리할 Request 유형을 서로 연관성이 있는 그룹으로 나누어서 각 그룹별로 여러 Edit Policy로 분할하여 처리하도록 해두면 Edit Part가 유연성을 가질 수 있습니다.GEF에는 이러한 Request의 그룹구분을 위한 지침으로서 몇 가지 Role이 정의되어 있습니다.또한 해당 Role로 처리해야 하는 Request 타입과 해당 Request를 처리하기 편리한 Edit Policy도 준비되어 있습니다.GEF가 준비하는 모든 정의된 Role 및 EditPolicy 클래스에 관해서는 GEF SDK의 문서 ′Programmer′s Guide′의 ′Using Edit Policies, Requests, and Roles′ 섹션 이하의 표에 나타나 있습니다.GEF의 문서 기술되어 있는 Role 및 그 Role이 처리해야 하는 Request 타입은 어떻게 Request 타입을 그룹화할 것인지를 나타낸 지침이므로 완전히 이를 따를 필요는 없습니다.또한 Role은 단순한 문자열이기 때문에 Edit Policy 인터페이스에 정의되어 있는 이미 정의된 Role 문자열과 중복되지 않으면 자체 Role을 정의할 수도 있습니다.자체 Edit Policy가 필요하면 Abstract Edit Policy 클래스 등을 확장할 수도 있습니다.명령어는 모델에 대해 수행하는 편집 조작을 캡슐화한 것으로, 사용자의 모델 변경 요구를 실제로 실행하기 위한 것입니다.GEF의 Command 클래스에는 execute(), undo(), redo()와 같은 명령어 실행 및 명령어 취소, 재작업을 하기 위한 메서드가 정의되어 있습니다.따라서 명령어 클래스는 이러한 메서드를 오버라이드하고 모델을 변경하거나 변경을 취소하거나 할 뿐인 단순한 것이 됩니다.또한 모든 명령어는 ′명령어 스택′에 의해 관리됩니다.명령어 스택은 명령어가 실행된 경우에는 execute() 메서드를 호출한 후 Undo용 스택에 명령어를 푸시하고 명령이 취소된 경우에는 Undo용 스택에서 명령어를 팝하여 undo() 메서드를 호출하는 등의 방법으로 편집 조작 취소 및 재시행과 같은 기능 및 문서의 더티 체크 기능을 GEF 어플리케이션에 제공하고 있습니다.GEF 애플리케이션의 작성 여기에서는, 단순한 그림을 편집하기 위한 샘플·애플리케이션을 사용하고, GEF애플리케이션의 실장 방법을 단계 마다 설명합니다.GEF 애플리케이션은 기본적으로, 이하와 같은 순서로 실장합니다.모델의 정의
뷰의 정의
Edit Part 만들기
모델 편집 기능 추가(Edit Policy 작성 및 설치)
Edit Part Viewer 구현모델의 정의는 전술한 바와 같이 모델의 정의는 기본적으로 자유입니다.이 기사의 샘플 GEF 애플리케이션에서는, 아래 그림과 같은 모델이 정의되고 있습니다.모델의 구조는 단순하며 Example Diagram 클래스가 Node Element를 관리하고 Node Element가 Connection Element를 관리하도록 되어 있습니다.Example Diagram 클래스는 모든 모델, 클래스에 대해 직간접적으로 액세스할 수 있습니다.이러한 ′톱레벨′ 모델 클래스는 Edit Part Viewer 에 대한 입력으로 취급됩니다.앞서 말한 것처럼 모델은 자신의 변경을 Edit Part에 통보하는 기능을 가져야 합니다.샘플로 사용하고 있는 모델·클래스에서는, Property Change Support를 사용해 모델의 변경을 통지하는 기능을 실현하고 있습니다.′Model Element.java′ 발췌
abstract public class ModelElement
implements IPropertySource , Serializable {
...
// 모델의 상태 변화를 알려주는 리스너 목록
transient private PropertyChangeSupport listeners
= new PropertyChangeSupport ( this ) ;

public void
addPropertyChangeListener ( PropertyChangeListener l ) {
listeners . addPropertyChangeListener ( l ) ;
}

protected void firePropertyChange (
String propName , Object oldValue , Object newValue ) {
listeners . firePropertyChange ( propName , oldValue , newValue ) ;
}

public void removePropertyChangeListener
( PropertyChangeListener l ) {
listeners . removePropertyChangeListener ( l ) ;
}
...
}}샘플에서 사용하고 있는 모델·클래스는 IProperty Source 인터페이스를 구현하고 있습니다.이것에 의해, GEF 애플리케이션에 프로퍼티·소스·서포트를 추가하고 있습니다.이클립스의 [프로퍼티] 뷰는 워크벤치상의 현재 선택에 대해 속성 소스(IProperty Source 인터페이스를 구현하는 클래스)를 요구합니다.GEF 어플리케이션에서는 Edit Part가 현재의 선택으로서 워크벤치의 셀렉션 서비스에 제공되게 되므로 Edit Part가 속성 소스를 반환하는 역할을 합니다.기본적으로는 EditPart가 속성 소스를 요구받을 때 그 EditPart에 설정되어 있는 모델이 IPropertySource 인터페이스를 구현하고 있으면 모델을 속성 소스로 반환합니다.또 모델이 IAdaptable 인터페이스를 구현하고 있는 클래스이면 getAdapter 메서드를 통해 IPropertySource형 어댑터를 요구하고 그 결과를 반환합니다.속성 소스 지원을 추가하려면 EditPart 클래스에서 getAdapter 메서드를 오버라이드하고 IPropertySource형 어댑터를 반환하도록 하겠습니다.또, 프로퍼티·소스의 상세한 것에 대해서는, 이 샘플의 소스, 및 이클립스 SDK의 「프로퍼티·시트·샘플」등을 참조해 주세요.
반응형