Eclipse 4 RCP 튜토리얼(완료)

 
아래의 튜토리얼 번역하면서 RCP를 정리해 보고자 한다. 

http://www.vogella.com/tutorials/EclipseRCP/article.html#introduction-to-eclipse-rcp-applications
 
 
 
 

This tutorial gives an overview about creating Eclipse RCP applications.
이 튜토리얼은 Eclipse RCP 애플리케이션을 만들기 위해 필요한 전반적인 것들을 다룬다.

목차:

1. Introduction to Eclipse RCP applications

이클립스 RCP 애플리케이션은 이클립스 플랫폼 기술을 기반으로 하는 stand-alone 형태의 애플리케이션이다. 이 튜토리얼에서는 Eclipse based applications, Eclipse application, Eclipse 4 application, Eclipse RCP application라는 용어들을 같은 의미로 사용한다.

이클립스 IDE 모듈로 이클립스 IDE 버전 2.0 이 시작되었다. 2004년에 이클립스 버전 3.0 이 출시되었다. 이클립스 3.0 이 이클립스 플랫폼 컴포넌트를 재사용할 수 있도록 지원하면서 stand-alone 애플리케이션을 이클립스 IDE 와 동일한 기반기술로 만들 수 있게 되었다. 이 시점에 이클립스 RCP라는 용어가 만들어졌다. 이클립스 RCP는 리치클라이언트플랫폼(Eclipse Rich Client Platform ) 의 줄임말이다. 또한, 이클립스 플랫폼이 feature-rich stand-alone 애플리케이션 개발의 기반으로 사용됨을 의미한다. 
버전 4.0 릴리즈에서는 최신 기술들인 의존성 주입과 css 파일을 통한 선언적으로 스타일을 적용하는 등의 기술들을 가지고 이클립스 프로그래밍 모델을 단순화하고 통일화를 하였다. 

이클립스 RCP 애플리케이션들은 이미 있는 사용자 인터페이스와 내부 프레임워크들로부터 장점들을 가지면서 또한 기존의 플러그인들과 피처들을 재사용할 수 있다.

사용자들은 다음과 같은 이유로 이클립스 RCP를 이용하여 개발하기로 결정한다. 

● 이클립스 플랫폼은 가장 성공적인 java ide 의 기본을 구성하고 있으며 이 때문에 매우 안정적이면서 널리 사용된다.
● 기본적으로, 빠르고 믿을 수 있는 네이티브 사용자 인터페이스를 제공한다.
● 강력한 모듈 접근 방식을 채용하고 있어 개발자가 컴포넌트 기반의 시스템을 설계할 수 있도록 해준다.
● IBM, SAP, Google 같은 회사들이 그들의 제품 기반으로서 이클립스 프레임웍을 사용한다. 그래서 이클립스는 유연하고 빠르며 지속적인 진화가 보장된다.
● 이클립스 플랫폼은 이클립스 프레임웍의 확장과 지원 그리고 정보를 제공하는 많은 개별 커뮤니티를 조성한다. 

이러한 에코시스템을 활용하여 당신이 필요로 하는 리소스들과 정보를 찾는 것이 가능하다.

2. Architecture of Eclipse based applications

하나의 이클립스 RCP 애플리케이션은 여러 개의 개별적인 소프트웨어 컴포넌트들로 구성된다. 이클립스 애플리케이션들은 몇 개의 기본 컴포넌트들을 기반으로 만들어 진다. 다른 컴포넌트들이 이 애플리케이션들을 사용하기도 하고 애플리케이션 위에 확장 기능을 제공하기도 한다.

Eclipse IDE는 소프트웨어 개발 지원해준다는 것에 초점을 맞췄을 때 특별한 이클립스 애플리케이션으로 보일 수 있다. 예를 들어 Java development tools (JDT) 는 Java 애플리케이션을 개발하기 위한 기능을 제공한다

하나의 이클립스 RCP 애플리케이션은 일반적으로 이클립스 IDE에서도 사용되는 동일한 기본 컴포넌트들을 사용한다. 이 기본 컴포넌트들 위에서, 애플리케이션을 특정 컴포넌트들에 추가하는 것이다. 아래 그림이 이를 설명해 준다. 

3. Core components of the Eclipse platform

OSGi (Open Service Gateway initiative)는 컴포넌트 기반 자바 애플리케이션을 개발할 수 있도록 모듈적인 접근을 기술하는 하나의 스펙이다. OSGi 의 프로그래밍 모델은 OSGi 서비스들 같은 소프트웨어 컴포넌트들을 동적으로 정의할 수 있도록 해준다. Equinox는 OSGi 스펙을 구현해 놓은 것으로 이클립스 플랫폼에서 런타임으로 사용된다. Equinox 런타임은 모듈로 된 이클립스 애플리케이션을 실행하기 위해 필요한 API 와 프레임워크를 제공한다. 

SWT는 이클립스에서 사용하는 표준 사용자 인터페이스 라이브러리다 JFace는 SWT 의 상위에서 편리한 API를 제공해 준다. 워크벤치(workbench)는  애플리케이션을 위한 프레임웍을 제공해 주며, 모든 다른 사용자 인터페이스 컴포넌트들의 디스플레이를 책임진다. 

EMF는 Eclipse Modeling Framework 의 약자로서 데이터 모델을 모델화하고 실행 시간에 이 데이터 모델을 사용할 수 있도록 하는 기능을 제공해 준다.

4. Eclipse API and internal API

OSGi 런타임은 개발자가 개발자가 public, provisional, internal API 들처럼 자바 패키지들을 표시할 수 있도록 해준다. internal API는 프라이빗하므로 보이지 않는다. provisional API 들은 개발이 완료되지 않은 API 들을 테스트하기 위한 것으로 보이지만 안정적이지(non-stable) 않다. public API 또는 단순하게 API는 외부에서 볼 수 있으며, 안정적인 API이며, 다른 컴포넌트들이 재사용할 수 있다.

이클립스 플랫폼 프로젝트는 이클립스 개발자들이 모든 자바 클래스들에 접근할 수 있도록 하기 위해  public API 나 provisional API로 패키지를 표시할 수 있다. 이클립스 플랫폼 프로젝트가 하나의 API를 릴리스 하게 되면, 그 플랫폼 프로젝트는 가능한 오랫동안 이 API 가 안정적으로 유지되도록 계획한다. 

만약 API 가 internal이고 접근 가능한 상황이라면, 예를 들어 provisional로 표시되었다면, 해당 플랫폼팀은 향후 이 API를 변경할 수 있다. 만약 우리가 이러한 API를 사용하게 되면 향후, 이클립스 릴리스에서 우리의 애플리케이션의 일부를 수정해야 할 수도 있다는 것을 알아고 준비해야 한다. 

만약 우리가 릴리스되지 않은 API 사용한다면, 우리는 자바 에디터에서 "Discouraged access: The …​is not API (restriction on required project …​)"라는 경고를 보게 된다.

우리는 이 경고 표시를 무시하도록 설정할 수 있다. Window ▸ Preferences ▸ Java ▸ Compiler ▸ Errors/Warnings으로 가서 Discouraged reference (access rules) 항목을 Ignore 으로 설정하면 된다.
선택적으로 프로젝트 별로 이 경고를 끌 수도 있다. 프로젝트를 선택 후, 마우스 우 클릭에 보이는 팝업메뉴에서 Properties ▸ Java Compiler를 선택한 후, 위의 글로벌 세팅 방법과 동일한 경로로 가서 설정을 할 수 있다. 아래의 그림과 같이 Enable project specific settings 체크박스를 선택해야 메뉴가 활성화될 수도 있다.

5. Important configuration files for Eclipse plug-ins

하나의 이클립스 플러그인은  아래의 주요 설정 파일을 갖는다. 이 파일들은 API 들과 그 플러그인의 종속성(dependency) 을 정의하고 있다.

● MANIFEST.MF - OSGi 설정 정보를 포함한다.
● plugin.xml - 이클립스 확장 메커니즘들에 대한 정보를 포함한다.

하나의 이클립스 플러그인은 유일한 식별자(ID)와 노출시킬 API, MANIFEST.MF를 통한 종속성과 같은 메타데이터를 정의한다. 

plugin.xml 파일은 이클립스 API를 생성하거나 기여할 수 있는 가능성을 제공한다. 우리는 이 파일에 extension points 와 extensions 을 추가할 수 있다. Extension-points는 다른 플러그인이 기능을 기여할 수 있도록 하기 위한 인터페이스들을 정의한다. Extensions는 이들 인터페이스들에 기능을 기여한다. 기능은 코드나 논코드가 될 수 있다. 예를 들어 plug-in 은 헬프 콘텐츠를 포함할 수도 있다. 

6. Download the Eclipse Software Development Kit (SDK)

다음은 설명은 Eclipse 4.7 (Oxygen) 을 기준으로 설명한다. 아래의 URL에서 Eclipse SDK 최신 버전을 다운로드하자:
http://download.eclipse.org/eclipse/downloads/
이 웹사이트는 아래의 스크린샷과 비슷할 것이다. 최신 릴리스 버전(번호가 가장 높은 버전) 링크를 클릭하여 다운로드 섹션으로 이동하자.

다운로드 섹션에는 압축되어 있는 여러 아카이브 파일이 있으며, 사용하는 운영체제에 맞는 파일 포맷을 선택하자
● 윈도우즈 사용자는 zip 포맷
● Linux는 tar.gz Mac OSX는  dmg를 사용하자

7. Install the e4 tools

7.1. Using the update manager

e4 Tools는 Eclipse 4 RCP 애플리케이션들을 개발하기 위한 툴들을 제공해 준다. 이 Tools는 이클립스 기본 업데이트 사이트를 통해 설치할 수 있다. 

툴들을 설치하고 이클립스를 재시작하자.

7.2.  Install the e4 spies from Eclipse.org

e4 스파이 툴들은 이클립스 4 RCP 애플리케이션을 분석하는데 도움을 준다. 이 툴들을 설치하기 위해서는  Help ▸ Install new software…​ 통해 이클립스 업데이트 매니저를 오픈한다. 다음 URL 을 통해서 최신 툴을 설치할 수 있다.
http://download.eclipse.org/e4/snapshots/org.eclipse.e4.tools/latest/
다른 버전의 툴들은 Eclipse.org e4tools site에서 찾을 수 있으며. Build Name 링크를 클릭하면 업데이트 사이트 URL 을 찾을 수 있다. (하지만 내가 링크를 타고 들어갔을 때, 해당 화면이 잠깐 보이다가 e4 다운로드 페이지로 강제 이동이 되었다. 다시 시동하면 처음에 보였던 페이지로 가지지 않고 e4 다운로드 페이지로만 이동되고 있다. )

8. Exercise: Create an RCP application with the wizard

이번에  템플릿 기반의 이클립스 RCP 애플리케이션을 생성하는 방법을 알아볼 것이다. 또한 이클립스 IDE를 이용하여 애플리케이션을 시작 시키는 법도 알아볼 것이다. 우리는 이후 챕터에서 여기서 실행된 것들에 대한 모든 상세사항들에 대하여 배울 것이다.

8.1. Create project

이클립스 IDE에서 File ▸ New ▸ Other…​ ▸ Plug-in Development ▸ Plug-in Project 순으로 메뉴를 선택하자.

com.example.e4.rcp 이름의 프로젝트를 생성하자. 설정은 아래화면과 유사하게 설정하자 대부분이 기본설정이다.

마지막 위저드 페이지에서, Create sample content (parts, menu etc.) 라고 보이는 체크박스를 체크하자. 이 체크박스를 체크함으로서 우리가 만든 애플리케이션은 뷰, 메뉴, 툴바등을 포함하는 샘플 컨텐츠를 갖게 된다.

위저드는 프로덕트 설정파일에 "clearPersistedState" 플래그 또한 추가한다. 이 플래그는 개발동안에 우리의 애플리케이션모델에서 발생하는 변경들이 항상 보여지도록 보장한다. 추가적인 정보는 13.2.9. Ensure to delete the persisted user interface state at startup(http://www.vogella.com/tutorials/EclipseRCP/article.html#tutorial_clearpesistence_task) 에서 확인하자.
8.2. Launch your Eclipse application via the product file

생성된 프로젝트에서 *.product 파일을 더블클릭하자.

아래의 그림과 같이 Overview 탭으로 이동 후, Launch an Eclipse application 하이퍼링크를 클릭하여 이클립스 애플리케이션을 실행시키자.

8.3. Validating

이클립스 애플리케이션을 시작시킨 결과는 아래의 화면과 같을 것이다.

9. Eclipse 4 application model

9.1. What is the application model?

이클립스 플랫폼은 하나의 애플리케이션의 구조를 기술하기 위해 application model 이라는 추상 디스크립션을 사용한다. 이 애플리케이션 모델은 비주얼 요소들 뿐만 아니라 애플리케이션의 비주얼 적이지 않은 요소들도 포함하고 있다. 

예를들어 윈도우, 파트(뷰나 에디터), 메뉴, 툴바들은 비주얼 파트들이다. 비주얼적인 않은 요소들로는 핸들러, 커맨드, 키바인딩 등이 있다. 

각 모델 요소들은 윈도우의 사이즈 위치등과 같은 현재 상태를 기술해주는 속성들을 갖는다. 애플리케이션 모델은 또한 계층구조를 이용하여 모델 요소들의 관계를 표현한다. 

사용자 인터페이스 위젯들 각각은 하나의 파트안에서 디스플레이 되는 것이며 애플리케이션 모델을 통해 정의되는 것은 아니다. 예를들어 파트 내의 컨텐츠는 직접 코딩을 통해 구성하는 것이다. 

애플리케이션 모델이 하나의 집이라면, 모델은 사용가능한 룸들(파트들)과 그것의 배열방식들(perspectives, part stacks, part sash containers)을 기술 하는 것이다. 그러나 방안의 가구들까지 기술 하지는 않는다. 아래의 그림이 이것을 설명해 준다. 

애플리케이션 모델의 베이스는 일반적으로 하나의 고정된 파일로써 정의 된다. 기본적으로 파일명은Application.e4xmi 로 되어 있으며 플러그인의 메인 디렉토리 안에 있다. (plugin.xml 과 동일한 위치)
이 파일은 애플리케이션이 시작될 때 읽혀지며, 초기 애플리케이션 모델을 구성하는데 사용된다. 사용자가 변경한 사항들은 저장되고 시작시에 다시 적용된다. 

애플리케이션 모델은 확장이 가능한데 예들들어 다른 플러그인들이 model processors 이나 model fragments 를 통해서 기여할 수 있다.

9.2. Connection model elements to classes and resources

모델 요소들은 URI(Uniform Resource Identifier) 통한 정적 리소스나 클래스를 연결 시킬 수 있다. 이렇게 하기 위해 이클립스는 두가지 URI 패턴을 정의한다. 이클립스는 대부분 참조하고 있는 객체들이나 리소스들을 늦게 초기화 한다. 예를들어 어떤 파트에 연결되어 있는 클래스는 파트가 실제 보이게 될 때 초기화 된다. 

다음 테이블에는 지원하는 URI 패턴들을 기술하고 있다. 예제에서 번들이름은 "test" 이다. 

Pattern
Description
bundleclass://Bundle-SymbolicName/package.classname

예:

bundleclass://test/test.parts.MySavePart
자바클래스를 식별하는 사용되며 구성은 다음과 같다. 
"bundleclass://" 부분은 고정값이다. 
"Bundle-SymbolicName" 은 MANIFEST.MF 파일에 정의되어 있다.
Bundle-SymbolicName 다음 "/" 이후에 클래스의 풀 네임이 온다(패키지명 + 클래스명. 
platform:/plugin/Bundle-SymbolicName/path/filename.extension

예:

platform:/plugin/com.example.plugin/icons/save_edit.gif
리소스를 식별하는데 사용되며, 하나의 플러그인내의 리소스를 식별함.
"platform:/plugin/" 은 고정값 이고 다음에 "Bundle-SymbolicName" 이 오며 다음에 파일경로와 파일명이 위치한다.

예를들어  Class URI 속성을 갖는 어떤 파트는 그 속성에 "bundleclass://URI" 방식으로 벨류를 입력하여 Java 클래스를 연결할 수 있다. 이 클래스는 파트의 행위를 제공하게 된다. 이 연결된 객체는 이클립스 프레임웍이 생성시킨다. 이전 설명에서 집/방 을 개념을 이용해서 은유적으로 설명했던 부분을 떠올려 보면, 이 클래스는 가구배치와 방의 레이아웃을 정의할 책임을 갖으며, 사용자와 상호작용 할 객체들이 어떻게 동작해야할지 정의 할 책임또한 갖는다.  

정적 리소스를 연결하기 위한 예로는 Icon URI 속성을 사용하는 파트를 들 수 있다. 이 속성은 파트에 사용되는 아이콘을 연결시킬 수 있다.

9.3. Runtime application model

애플리케이션 실행시간에 생성된 모델 객체들은 런타임 애플리케이션 모델이라고 부른다. 이 런타임 애플리케이션 모델은 동적인데 예를들어 우리는 모델 객체들과 가 객체들의 속성들을 변경할 수 있다. 또한 이 변경사항들은 우리의 애플리케이션에 반영된다. 이클립스 플랫폼은 모델객체들에 등록된 변경 리스너들을 갖으며 당신이 속성들을 변경할 때마다 사용자 인터페이스를 갱신한다.

10. User interface model elements

다음 소개되는 모델 요소들은 우리 애플리케이션의 사용자 인터페이스를 생성하기 위한 기본 요소들이다.

10.1. Window

이클립스 이플리케이션들은 하나이상의 윈도우들로 구성된다. 보통 하나의 애플리케이션은 오직 하나의 윈도우만을 갖지만 거기에 따로 제한은 없다. 예를들어 당신이 여러모니터가 연결되도록 지원하기를 원한다면 말이다.

10.2. Parts

파트(Part)들은 사용자 인터페이스 컴포넌트로서 우리는 파트를 통해서 데이터를 수정하거나 돌아다닐 수 있다. 파트들은 스택처럼 서로 겹쳐 쌓일수도 있고, 컨테이너에 담길수 도 있으며, 이 컨테이너에 의해서 서로 옆으로 나란히 위치시킬 수도 있다. 하나의 파트는 드랍다운 메뉴와 컨텍스메뉴 그리고 툴바를 가질 수 도 있다.

파트들은 뷰나 에디터들로 분류될 수 있다.

일반적으로 하나의 뷰는 계층적 구조일 수도 있는 데이터 집합들을 가지고 작업하기 위해 사용된다. 뷰를 통해 데이터가 변경되면 이 변경 내역은 보통 기저에 있는 데이터 구조에 직접 반영된다. 때로는 하나의 뷰는 선택된 데이터셋용 에디터를 열도록 하기도 한다. 예를들어, 패키지 익스플로러 뷰는 우리가 이클립스 프로젝트 파일들을 탐색할 수 있도록 해준다. 만약 우리가 패키지 익스플로러 뷰를 통해 파일이름을 변경하면 파일시스템상의 파일이름이 바로 변경된다.

에디터들은 보통 단일데이터 요소를 수정하기위해 사용된다. 예를들어 파일의 컨텐츠나 하나의 데이타 객체를 수정하는데 사용되기도 한다. 에디터에서 행해진 변경사항들을 데이터 스트럭쳐에 적용하기 위해 사용자는 명시적으로 에디터 컨텐츠를 저장하는 행위를 해야한다.

예를들어 자바 에디터는 자바 소스파일울 수정하기 위해 사용된다. 소스파일에서 일어난 변경사항들은 사용자가 저장버튼을 클릭함으로써 적용이 된다. dirty 에디터 탭은 수정된 파일이름 왼쪽에 *(asterisk) 가 표시된다. 

10.3. Available part containers

파트들은 윈도우나 퍼스펙티브에 직접 할당될 수 있다. 또한 추가적인 다른 모델 요소들을 통해 파트들을 정렬하거 그룹화 할 수도 있다. 예를들어 파트스택(Part Stack) 이나 파트 새쉬 컨테이너(Part Sash Container) 요소를 사용하여 할 수 있다.

하나의 파트 스택은 여러 파트들 중에 하나의 파트컨텐츠만 보여주고 다른 파트들에 대해서는 타이틀 탭만 표시해 준다. 하나의 파트만 활성화 되어 있으며, 사용자가 다른 그 파트스택의 다른 탭을 선택함으로서 다른 파트가 활성화 되도록 할 수 있다.

하나의 파트 새쉬 컨테이너는 자신이 담고 있는 모든 자식들을 횡으로 나열하거나 종단으로 나열하여 표시해준다.

다음 스크린샷은 두개의 파트 새쉬 칸테이너와 3개의 파트 스택을 사용하는 간단한 이클립스 애플리케이션 레이아웃을 보여준다. 

레이아웃 최상위에는 횡으로 파트를 나열시켜주는 파트새쉬컨테이너가 있으며 이 컨테이너는 다른 파트 새쉬 컨테이너와 하나의 파트스택을 포함한다. 그 다음 래벨에 파트 새쉬 컨테이너는  두개의 파트스택을 포함한다. 다음 그림은 이 구조가 계층적으로 표시된 것이다.

우리는 레이아웃이 가중치를 할당하기 위하 파트 새쉬 컨테이너의 자식들의 "Container Data" 라는 속성값을 사용할 수있다. 이 레이아웃 가중치는 자식 요소들이 파트 새쉬 컨테이너에 할당되어야 하는 상대적인 공간으로 인식된다. 설정은 다음 그림과 같다.

우리가 하나의 요소에 대해 컨테이너 데이터를 설정하면 반드시 다른 모든 요소에도 정의해야 한다. 그렇지 않을 경우 빠진 값들은 매우 큰값으로 인식되어 가용한 모든 공간을 차지하게 된다. 

팁:
컨테이너 데이터 값들의 초기 총합은 새쉬에 있는 엘리먼트들이 움직일 때 관리된다. 잘 분할하고 싶거나 부드럽게 드래깅 하고 싶다면 스크린의 해상도와 유사해야 한다. 너무 낮은 값 예를들어 50/50 과 같은 값은 새쉬당 파트들이 다중 픽셀들로 움직이게 하여 사용자에게 움직임이 끊기는 것처럼 보이게 된다. 예를 들어 10000 값과 같이 충분히 높은 값을 사용해라
10.4. Perspective

파트세트 한묶음은 하나의 퍼스펙티브에 
포함될 수 있다. 퍼스펙티브들은 파트들을 다르게 정렬된 상태로 저장하여 사용될 수 있다. 예를들어 이클립스 IDE는 뷰들을 개발이나 디버깅, 리뷰와 같은 개발자가 작업하거 싶어하는 직무에 맡게 배치하도록 퍼스펙티브를 사용한다.

우리는 애플리케이션 모델의 퍼스펙티브 스택에 퍼스펙티브들을 위치시킬 수 있다. 이클립스 플랫폼이 제공해주는 파트서비스를 통해 퍼스펙티브를 전환시킬 수 있다.

11. Overview of available model objects

이클립스 플랫폼이 시작되면 Application.e4xmi 파일이느 저장되어 있는 사용자 변경사항들 그리고 모델에 기여하는 것들과 같은  애플리케이션 모델에 관한 정보를 파싱한다. 그리고나서 이 정보들을 실행시간동안에 자바객체에 저장해 둔다. 이 객체들은 모델 객체라고 부르며 실행시간에 모델 요소들의 속성들을 표시한다.

다음표는 중요한 모델 객체들의 유형 리스트다.

Model element
Description
MApplication
애플리케이션 객체를 설명한다. 다른 요소들 모두 이 객체에 포함된다. 
MAddon
보통 사용자 인터페이스가 아닌 독립적인 컴포넌트. 애플리케이션 라이프 사이클내에서 발생하는 이벤트들을 등록하고 이 이벤트들을 처리할 수 있다.
MWindow
애플리케이션에 하나의 윈도우를 나타낸다.
MTrimmedWindow
MWindow 와 유사하지만, TrimBars 모델 요소를 이용하여 윈도우에 툴바를 포함할 수 있다. 
MPerspective
윈도우내에 표시될 파트들이 용도에 따라 서로다르게 배치 되도록 할 수 있는 요소다. MPerspectiveStack 내에 있어야 한다. 
MPart
뷰나 에디터 같은 파트 요소다. 
MDrityable
주입될 수 있는 MPart 의 속성이다. true 로 설정하면, 이 속성은 이클립스 플랫폼에게 이 파트가 저장되지 않은 데이터를 포함하고 있다고 알리게 된다.(is dirty). 핸들러에서 우리는 저장이 필요한지를 확인하기 위해 이 속성을 확인할 수 있다.  
MPartDescriptor
MPartDescriptor 는 새 파트를 만들기 위한 템플릿이다. 이클립스 프레임워크는 이 파트 디스크립터 정보를 가지고 새 파트를 만들고 디스플레이 할 수 있다. 
Snippets
Snippets 은 우리가 프로그램을 통해 생성하고 싶은 모델 파트들을 미리 구성하는데 사용될 수 있다. 우리는 하나의 snippet 을 복사하고 그것을 실행시간에 애플리케이션 모델에 추가하기 위해 이클립스 프레임워크를 사용할 수 있다.

12. More to learn about Features and Products

다음 설명은 피쳐 프로젝트들과 프로덕트들을 사용한다. 이 주제에 대한 설명은 Feature projects and Eclipse Products and Deployment  대한 설명을 찾아보자. 

13. Exercise: creating an Eclipse RCP application

13.1. Create an Eclipse plug-in

다음 연습에서 우리는 표준 이클립스 플러그인을 생성한다. 이 플러그인은 나중에 이클립스 RCP 애플리케이션으로 변환된다.

다음 설명에서는 이 플러그인을 애플리케이션 플러그인이라고 부른다. 이 플러그인이 주요 애플리케이션 로직을 포함할 것이기 때문이다.
13.1.1. Creating a plug-in project

이클립스에서  File ▸ New ▸ Other…​ ▸ Plug-in Development ▸ Plug-in Project 의 경로로 메뉴를 선택하자.

프로젝트 이름을  "com.example.e4.rcp.todo으로 하고  Next 버튼을 누르자

다음 위저드 페이지에서는 아래의 그림과 같이 설정하자. "Would you like to create a rich client application?에는 "No" 를 선택하자. "This plug-in will make contributions to the UI"  체크를 해제하자. 

"Finish" 버튼을 누르자. "Finish" 버튼대신 "Next" 버튼을 누를경우, 다른 선택없이도 진행할 수 있는 위저드는 탬플릿 선택 페이지를 보여준다. 

13.1.2. Validate the result

프로젝트를 열고 src 폴더에 생성된 자바 클래스들이 없는 것을 확인하자. 
manifest  파일을고 Dependencies 탭을 열고 리스트에 아무것도 없는지 확인하자.

13.2. From plug-in to Eclipse 4 application

이 챕터에서 우리는 우리가 만들었던 플러그인을 Eclipse RCP 애플리케이션으로 변환시킬 것이다.

13.2.1. Create a project to host the produce configuration file

File ▸ New ▸ Others…​ ▸ General ▸ Project 메뉴 선택을 통해 "com.example.e4.rcp.todo.product " 이름의 프로젝트를 생성하자.

프로젝트 명을 입력하고 "Finish" 버튼을 누르자

13.2.2. Create a product configuration file

프로젝트에서 마우스 우클릭 후,  File ▸ New ▸ Others…​ ▸ Plug-in Development ▸ Product Configuration 순으로 메뉴를 선택하자. 

Product configuration 선택하고 com.example.e4.rcp.todo.product 폴더안에 todo.product 이름의 파일명을 입력하자.

"Finish"버튼을 누르자. 파일이 생성고 에디터가 오픈될 것이다. 
에디터의 "Overview" 탭에서 New 버튼을 누르자

Product Name 으로 "to-do" 으로 입력하자. Defining Plug-in 으로 이전에 만든 플러그인으 "Browser" 클릭하고 찾아 선택하자. Product ID  product 로 하자. 마지막으로 Application 콤보박스는 org.eclipse.e4.ui.workbench.swt.E4Application 으로 선택하자.

13.2.3. Configure the start levels

프로덕트 에디터에서 Configuration 탭으로 이동 후, Add Recommend 버튼을 클릭하자. 이 세팅들은 Maven 이나 Tycho 빌드 시스템에서 사용되므로 그것들을 사용하기 위한 좋은 연습이 될 수 있다. 

13.2.4. Create a feature project

File ▸ New ▸ Other…​ ▸ Plug-in Development ▸ Feature Project 메뉴 선택을 하고 프로젝트 이름을 "com.example.e4.rcp.todo.feature으로 하자. 
 우리는 첫번째 페이지에서 "Finish" 버튼을 선택할 수 있다.

feature.xml file 에디터에서  "Included Plug-ins" 탭을 선택해라 "Add" 버튼을 누르고 "com.example.e4.rcp.todo" 를 이 feature 에 포함시켜라.

당신의 피쳐(feature) 안으로 플러그인을 포함시키기 위해 Included Plug-ins 탭에 플러그인이 추가되어 있는 확인하자. Dependencies 탭의 사용은 이 예제에서는 올바르지 않다.
13.2.5. Enter the feature as content into the produce

todo.product 프로덕트 파일을 열고, features 를 사용하도록 프로덕트 구성 파일을 수정하자.
프로덕트 에디터의 Overview 탭에서 features 옵션을 선택한다. 

Contents 탭을 선택하고 add 버튼을 클릭하여 다음 피쳐들을 추가하자.

● com.example.e4.rcp.todo.feature
● org.eclipse.e4.rcp
● org.eclipse.emf.ecore
● org.eclipse.emf.common

프로덕트에 위의 피쳐 리스트들을 추가할 수 없다면, 프로덕트가 피쳐기반으로 변경되어 있는지 확인해보자
13.2.6. Remove the version dependency from the features in the product

우리의 피쳐 버전들이 다름으로 인한 문제를 피하기 위해, 프로덕트에서 버전넘버를 삭제하자. 프로덕트 컨피규레이션 에디터의 Contents 탭에있는 Properties 버튼을 클릭하여 이 문제를 회피 할 수 있다. 

리스트의 모든 피쳐들의 버전을 제거하자. 결과 화면은 아래와 같을 것이다.

13.2.7. Create an application model

com.example.e4.rcp.todo 플러그인에서 애플리케이션 모델을 생성하자. File ▸ New ▸ Other…​ ▸ Eclipse 4 ▸ Model ▸ New Application Model 을 순서대로 선택하여 위저드를 열자.

아래의 화면과 같이 Container 에는 com.example.e4.rcp.todo 애플리케이션 플러그인을 선택하고, 파일명은 위저드가 제시한대로 사용하자.

Finish 버튼을 누르면,  com.example.e4.rcp.todo 플러그인 내에  Application.e4xmi 파일을 생성하고 그 파일을 오픈해 준다. 

13.2.8. Add a window to the application model

비주얼 컴포넌트 하나를 추가하기 위해 애플리케이션 모델에 윈도우 하나를 추가하자. 

Windows and Dialogs 항목에 마우스 우클릭 후, 아래의 그림과 같이 Trimmed Window 를 선택하자.

ID  맨 끝에 taskmanager 를 입력하고, 윈도우의 위치와 사이즈, 그리로 레이블은 아래의 그림과 같이 입력하자. 

13.2.9. Ensure to delete the persisted user interface state at startup

우리가 애플리케이션을 시작하고 종료하면,  애플리케이션의 마지막 상태는 프레임워크에 의해 저장되고, 다음번에 이 애플리케이션이 시작될 때 그 상태는 복원된다. 이 것은 개발하는 동안에는 그리 좋지 않을 수 있는데 이는 개발하는 애플리케이션모델의 최신상태를 사용해야 하기 때문이다. 우리의 애플리케이션이 항상 최신 상태인 채로 사용될 수 있도록 보장하기 위해서 -clearPersistedState  파라미터를 프로덕트 환경 구성 파일에 추가하자. 

다음 그림은 프로덕트 환경구성 파일의 설정 화면이다. 

파라미터를 정확히 입력 했는지 그리고 "-" 를 붙였는지 확인하자. 반드시 "-clearPersistedState" 이렇게 입력되어야 한다.
13.2.10. Start the application

프로덕트 파일을 열고  Overview 탭을 선택하자.  Testing 부분에 있는 Launch an Eclipse application 하이퍼링크를 클릭하자.

애플리케이션이 시작되는지 확인하자. 움직일 수 있고, 사이즈조정 가능하며, 최대/최소화 및 창 클로즈가 가능한 빈 윈도우가 표시되어야 한다. 

13.3. Modeling a User Interface

이 예제에서는 기본적인 사용자 인터페이스를 갖는 애플리케이션을 생성할 것이다. 예제 끝의 사용자 인터페이스는 아래의 화면과 같을 것이다.

13.3.1. Open the Application.e4xmi file

 Application.e4xmi 파일에 마우스를 우클릭 하고,  Open With ▸ Eclipse 4 model editor 를 선택해서 Eclipse 4 model 에디터에서 이 파일이 열리도록 하자. 

13.3.2. Add part sash and part stack containers

윈도우 하위 메뉴에서  Controls 를 선택하고  part sash container 요소를 추가하자.

아래의 화면과 같이 Orientation  Horizontal 로 변경하고 ID 는 com.example.e4.rcp.todo.partsashcontainer.main 으로 입력하자.

첫번째 자식 요소로 part stack 을  part sash container 에 추가하자. 

부모 part sash container 를 다시 선택하고 다른 part sash container 요소를 추가하자. 그리고 이렇게 추가한 part sash container 에 part stack 2개를 추가하자. 이렇게 수정하면 애플리케이션 모델은 아래의 그림과 같이 될 것이다. 

13.3.3. Create the parts

각 스택에 하나의 part 를 추가하자. ID 와 레이블은 아래의 테이블에 기술된 것을 사용하자. 

레이블이 비어 있다면, 먼저 이름을 입력하고, ID 는 이름을 기반으로 조정하자.

Table 3. Label and ID for the parts

ID Suffix
Label
com.example.e4.rcp.todo.part.todooverview
Overview
com.example.e4.rcp.todo.part.tododetails
Details
com.example.e4.rcp.todo.part.playground
Playground

애플리케이션의 최종 구조는 아래의 그림과 같을 것이다. 아래의 그림에서는 애플케이션 모델 에디터의 상세창에 overview 파트에 대한 상세 데이터를 확인할 수 있다. 

13.3.4. Validate the user interface

프로덕트를 시작하고서 사용자 인터페이스가 우리가 계획한대로 보이는지 확인 하자. 필요하다면 모델을 재 할당 해도 된다. 모델 에디터는 이미 정의된 요소들 간의 드래그앤드롭 기능을 지원한다. 

우리는 지금까지 어떠한 자바 클래스를 만들지 않았음에도 구조를 확인할 수 있다는 것을 알아두자.

13.4. Enter the dependencies

우리의 플러그인 코드내에서 다른 플러그인들의 클래스를 사용하기 위해서는 MANIFEST.MF  파일에 선언을 해야 한다. 이 예제에서 우리는 우리의 API 종속성들을 준비한다. 

13.4.1. Add the plug-in dependencies

우리는 나중에 우리의 플러그인 소스코드에서 다른 이클립스 플러그인의 API 를 사용할 것이다. 이클립스 프로그래밍 모델은 우리가 우리의 새로운 플러그인 내에 플러그인이나 패키지들의 종속성 정의를 필요로 한다. 

 com.example.e4.rcp.todo 플러그인을 애플리케이션 플러그인으로 간단하게 부르고 있다는 것을 참고하자. 

애플리케이션 플러그인에서 META-INF/MANIFEST.MF 파일을 열고 Dependencies 탭을 선택하자. Required Plug-ins 영역에 Add 버튼을 클릭하여 아래의 종속 플러그인들을 추가하자. 
● org.eclipse.core.runtime
● org.eclipse.swt
● org.eclipse.e4.core.di
● org.eclipse.e4.ui.workbench
● org.eclipse.e4.ui.di
● org.eclipse.e4.core.di.extensions

13.4.2. Validating

결과는 아래의 화면과 유사해야 한다.

13.5. Connect Java classes with the parts
13.5.1. Create a new package and some Java classes

우리의 애플리케이션 플러그인에 com.example.e4.rcp.todo.parts 패키지를 생성하자. 

만든 패키지내에  TodoOverviewPartTodoDetailsPartPlaygroundPart 이름의 자바 클래스를 생성하자. 모든 클래스들은 다른 클래스를 확장해서는 안되며, 어떠한 인터페이스도 구현해서는 안된다.

우리는 Application.e4xmi 파일을 오픈한 모델 에디터에서 각 파트의 상세페이지상에 있는 Class URI 하이퍼 링크를 클릭 후, 클래스를 생성할 수 도 있다. 이렇게 하면, 생성된 객체를 모델객체와 연결 시켜준다. 이 작업을 하게 되면 우리는 13.5.2. Connect the Java classes with your parts. 작업을 생략할 수 있다.

다음 코드는  TodoDetailsPart 클래다. 

package com.example.e4.rcp.todo.parts; public class TodoDetailsPart { }
13.5.2. Connect the Java classes with your parts

Application.e4xmi 파일을 열고서 위에서 생성한 3개의 파트 클래스들을 모델 요소들과 연결하자. 우리는  part model 요소의  Class URI 속성을 이용해서 이 작업을 할 수 있다. 

이클립스 4 모델 에디터는 Find 버튼을 통해서 우리가 이미있는 클래스들을 검색할 수 있도록 해준다. Find 버튼을 누르면 처음에는  Contribution Classes 에 아무것도 없으나 Class Name 입력을 시작하면 매치되는 결과를 아래와 같이 표시해 준다. 

아래의 테이블은 각 파트 클래스가 어느 요소들과 연결되어야 하는지에 대한 정보다. 

Table 4. Mapping Java classes with part model element

Class
Part ID suffix
TodoOverviewPart
*.todooverview
TodoDetailsPart
*.tododetails
PlaygroundPart
*.playground

아래의 화면은 overview 파트를 설정한 화면이다.

13.5.3. Validating

애플리케이션을 시작시켜 보자. 시작 하더라도 사용자 인터페이스 상에서의 차이첨은 보지 못할 것이다. 이클립스 런타임이 모델 객체를 생성했다는 것을 확인하기 위해서는 파트클래스들 중 하나에 기본 생성자를 만들고 기본생성자 내에 System.out.println() 구문을 넣고 애플리케이션을 시작시켜서 추가한 구문이 실행되는지 확인해 보자. 

 

14. Exercise: Using the SWT browser widget

14.1. Implementation

이번 예제에서 우리는 구글 맵상에서 도시를 검색하고 표시하는 여러 SWT 위젯들을 사용할 것이다. 

이 예제는 모든 리눅스 시스템에서는 동작하지 않을 수 있는데, 특정 리눅스 버전에서 Browser 위젯이 동작하지 않기 때문인다. 자세한것은 How do I use the WebKit renderer on Linux-GTK for details(http://www.eclipse.org/swt/faq.php#browserwebkitgtk) 에서 확인하자.

이제 PlaygroundPart 클래스를 아래의 화면과 같이 보일 수 있도록 개발해 보자. 

이 예제는 구글이 API 를 변경했을 경우에는 동작하지 않을 수 있다.

텍스트 필드에 검색어를 입력하고 버튼을 누르면, 맵은 입력한 검색어에 해당하는 위치를 중심으로 지도를 표시한다. 입력되는 검색어는 도시이름으로 인식되어 동작한다. 

14.2. Solution

우리의 PlaygroundPart 클래스는 아래의 코드와 같다. 

package com.example.e4.rcp.todo.parts; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import javax.annotation.PostConstruct; import org.eclipse.e4.ui.di.Focus; import org.eclipse.swt.SWT; import org.eclipse.swt.browser.Browser; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; public class PlaygroundPart { private Text text; private Browser browser; @PostConstruct public void createControls(Composite parent) { parent.setLayout(new GridLayout(2, false)); text = new Text(parent, SWT.BORDER); text.setMessage("Enter City"); text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); Button button = new Button(parent, SWT.PUSH); button.setText("Search"); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { String city = text.getText(); if (city.isEmpty()) { return; } try { // not supported at the moment by Google // browser.setUrl("http://maps.google.com/maps?q=" // + URLEncoder.encode(city, "UTF-8") // + "&output=embed"); browser.setUrl("https://www.google.com/maps/place/" + URLEncoder.encode(city, "UTF-8") + "/&output=embed"); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } } }); browser = new Browser(parent, SWT.NONE); browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); } @Focus public void onFocus() { text.setFocus(); } }
14.3. Introduction to dependency injection

의존성 주입에 대한 소개 정보는  Dependency injection in Java  를 참고하자. 

15. Dependency injection and Eclipse

15.1. Define class dependencies in Eclipse

이클립스에서 프로그래밍 모델은 생성자, 메소드, 필드 주입을 지원하며, 이는 Java Specification Request 330(JSR330) 을 따르는 것이다. 또한 이클립스는 의존성 주입을 목적으로 추가적인 애노테이션들을 정의하고 있다. 가장 중요한 애노테이션들은 Annotations to define class dependencies in Eclipse 에서 다루고 있다. 다른 더 특별한 애노테이션들은 각 해당 챕터에서 다루고 있다. 

이클립스 종속성 프레임워크는 주입되는 객체의 키와 타입이 정확한지를 확인한다. 예를들어 우리가 아래의 필드 선언에서 보이는 것 처럼, 'xyz" 키에 해당하는 Todo타입의 객체를 사용하고 싶다고 기술 하면, 프레임워크는 할당할 수 있는 타입 하나를 찾았을 경우에, 하나의 객체만 주입할 것이다. 

@Inject @Named("xyz") Todo todo;
15.2. Annotations to define class dependencies in Eclipse

아래의 테이블은 JSR330 과 이클립스에서 별도로 정의한 것을 기준으로 의존성 주입의 개요를 보여준다. 

Table 5. Basic annotations for dependency injection

Annotation
Description
@javax.inject.Inject
JSR330 에서 정의하고 있으며, 필드, 생성자, 메소드에 추가될 수 있다. 이클립스 프레임워크는 필드나 파라미터 인스턴스들을 해당하는 객체에 주입한다. 
@javax.inject.Named
JSR330 에서 정의하고 있으며, 값을 주입하기 위한 키를 정의한다. 기본적으로, 클래스 풀네임이(qualified class name) 키로 사용된다. 기본값을 위한 여러 키들이 IServiceConstants interface 에 상수로 정의되어 있다. 
@Optional
이클립스 애노테이션은(Eclipse specific annotation) 주입되는 값을 옵셔널로 표시한다. 주어진 키에(또는 타입) 대한 유효한 값이 없을 경우라도 프레임워크는 예외를 던지지 않는다. 

구현 동작은  @Optional 이 위치한 곳에 의존적이다. 아래의 설명은 키를 기준으로 한것으로, 키가 결정될 수 없으면, 다음과 같은 일이 발생한다. 

1. 파라미터에 대해서는 null 값이 주입될 것이다. 
2. 메소드에 대해서는 호출되지 않고 넘어갈 것이다. 
3. 필드들에 대해서는 값들이 주입되지 않을 것이다. 

null 은 context 설정될 수 있는 값으로, context 에서 제거되는 키와는 다르다. 예를들어, context.set(SOMEKEY, null) 이 호출되면, SOMKEY 를 리스닝하고 있는 어떤것이라도 null을 주입할 것이다. 
@GroupUpdates
이클립스 애노테이션은 (Eclipse specific annotation) @Inject 가 일괄 실행되기 위한 업데이트를 표시한다. 우리가 이클립스 컨텍스트 상에서 이러한 객체들을 변경하면,  IEclipseContext 객체의 processWaiting() 메소드는  update 를 시작시킨다. 이 에노테이션은 퍼포먼스 최적화를 위해 플랫폼이 사용하는 것으로 만들어 졌으며, 드믈게 RCP 애플리케이션들에서느 필요할 것이다. 
이클립스 플랫폼은 특별한 목적으로 추가적인 애노테이션들을 지원한다. 예를들어 이벤트들을(이벤트 서비스가 보내는) 받거나 자주하는 작업을 위한 애노테이션들을 지원한다. 이클립스 플래폼에 정의 된 모든 표준 애노테이션들은 요약은 Using annotations to define behavior(http://www.vogella.com/tutorials/EclipseRCP/article.html#eclipse4_annotations) 를 참고하자.
15.3. On which objects does Eclipse perform dependency injection?

이클립스 런타임은 애플리케이션 모델이 참조하는 Java 클래스들의 객체를 생성한다. 이 인스턴스화 작업동안 이클립스 런타임은 클래스에 정의되어 있는 애노테이션들을 스캔한다. 이 애노테이션들을 기준으로 이클립스 프레임워크는 injection 작업을 수행한다. 

이클립스는 우리가 코드에서 new 연산자로 생성한 객체에 대해서는 의존성 주입을 자동을 수행하지 못한다. 

15.4. Dynamic dependency injection based on key/value changes

이클립스 프레임워크는 어떤 객체가 어떤 키와 타입에 대한 종속성을 표현했는지를 추적한다. 어떤 키가 가르키는 값이 변경되면, 이클립스 프레임워크는 해당 타입으로 종속성을 표현했던 객체에 새로운 값을 다시 주입한다. 이것은 애플리케이션들이 리스널들을 추가하고 제거하는 것이 자유로울 수 있다는 것을 의미한다. 

예를들어 우리는  @Inject 를 이용하여 현재의 셀렉션이 주입되기를 원한다고 정의 할 수 있다. 셀렉션이 변경되면, 이클립스 프레임워크는 새로운 값을 주입할 것이다. 

재주입 동작은 @Inject 가 표시된 메소드와 필드에서만 동작한다. 생성자의 파라미터로 주입되는 상황이나  @PostConstruct 로 표시된 메소드들에서는 동작하지 않는데 이 메소드들은 한번만 실행되기 때문이다. 

이것은 이클립스가 키가 가리키는 필드값들을 추적한다는 것을 의미하는 것은 아니다. 예를들어 mykey1 key 는 값으로 Todo 객체를 가리키고 그리고 나서 새로운 객체를 가리킨다면, 클래스 종속성을 갖는 모든 객체들에 값을 재주입하는 작업을 시작할 것이다. 그러나 이미 생성된 Todo 객체의 내부 필드가 변경되는 경우에는 재주입을 시작하지 않는다.

16. The Eclipse context

16.1. What is the Eclipse context?

이클립스 애플리케이션이 시작되는 동안 이클립스 런타임은 IEclipseContext interace 를 구현하는  하나의 객체를 생성한다. 이 객체를 context 또는 Eclipse context 라고 부른다. 

context는 객체들이 특정 키 아래에 위치될 수 있다는 점에서  Map 데이터 구조와 유사하다. 키는 하나의 String 이며, 많은 경우에 풀네임의 클래스 명이 키로 사용된다. 키가 가리키는 값은 다른 객체들안으로 주입될 수 있다. 하지만 map 과 달리, 이클립스 context 는 계층적이며 또한 요청했던 키에 대한 값을 동적으로 계산할 수 있다. 

특정 모델 객첵들에서는(Connecting model elements to classes and resources 를 참고하자) 로컬 context 가 생성된다. 이러한 context 는 하나의 애플리케이션 모델 객체와 연관된다. 

다른 context 객체들은 우리의 애플리케이션 모델 구조를 기반으로 계층적인 트리 구조를 구성하기 위해 연결된다. 이 계층에서 가장 높은 레벨은 application context 이다. 

샘플 context hierarchy 는 아래의 그림과 같다.

객체들은 context 계층에서 다른 레벨에 위치될 수 있다. 이것은 계층에서 같은 키가 다른 객체들을 가리키는 것을 허용한다. 

예를들어, 하나의 파트는  @Inject Composite parent; 와 유사항 필드 선언을 통해서 Composite 객체와 의존성이 있음을 표현할 수 있다. 파트들은 다른 로컬 context 를 가지기 때문에 다른 Composite 객체 타입을 받을 수 있다. 

16.2. Which model elements have a local context?

현재 아래의 모델 요소들이 MContext interface 를 구현하여 자신의 context 를 갖는다. 
● MApplication
● MWindow
● MPerspective
● MPart
● MPopupMenu

16.3. Life cycle of the Eclipse context

 이클립스 프레임워크는 프로세스를 시작하는 동안에 애플리케이션 모델을 기준으로 context 계층을 생성한다. 기본적으로 이클립스 프레임워크는 컨텍스트 안으로 이미 정의해 놓은 키 아래에 특정 객체들을 위치 시킨다. 예를들면 이클립스 프레임워크 기능을 제어하기 위한 서비스들

이클립스 플랫폼은 모델 객체들과 class URI 속성값을 기준으로 생성되는 객체들을 생성한다. 커스텀  context 를 갖는 각 모델 요소들에 대해, 이클립스 프레임워크는 어느 객체들이 모델 객체의 로컬 context 내에서 이용가능해야 할지를 결정한다. 필요하다면, 모델 요소의 Class URI 속성에 기술되어 있는 참조하여 필요한 Java 객체를 생성한다. 이 것은 하나의 파트가 사용자에게 보여질지 에 대한 예이다. 

렌더러 프레임워크는 모델 요소들과 연관되는 로컬 UI context 를 생성할 책임이 있다. 이 프레임워크는 우리가 모델 객체의 UI 구현을 설정할 책일을 갖는 클래스들을 정의할 수 있도록 해준다. 하나의 모델 요소를 책임지는 하나의 클래스를 그 모델에 대한 renderer(렌더러) 라고 부른다. 

예를들어 ContributedPartRenderer 클래스는 파트 모델 객체를 위한 기본 렌더러 이다. 이 렌더러는 모든 part 들에 대한 Composite 을 생성하고 이 Composite 을 그 파트의 로컬 context 안으로 주입한다.

초기 이클립스 컨텍스트 계층생성 이후, 프레임워크나 애플리케이션 코드는 context 내에 저장되어 있는 key-value 쌍을 변경할 수 있다. 이 경우에, 연관된 이클립스 기능으로(예를들어 이클립스 종속성 주입 프레임워크에 의해 생성된) 함께 생성되었던 객체들은 새로운 값으로 갱신된다. 

context 내에 있는 객체들은 메모리에(transient) 저장되어 있다. 예를들어 애플리케이션이 멈추면, context 들은 소멸된다. 

16.4 How are objects selected for dependency injection

On which objects does Eclipse perform dependency injection? 에서 설명했듯이 이클립스가 생성한 하나의 객체는 자신의 클래스 종속성을 기술하기 위해 애노테이션들을 사용할 수 있다. 

이클립스가 생성한 객체들에 의존성을 주입하는 동안, 이클립스 프레임워크는 기술된 키를 이용하여 해당하는 객체를 검색한다. 검색은 애플리케이션 모델과 연관되는 로컬 context 에서 시작한다. 키에 해당하는 객체 없다면, 이클립스는 부모 context 에서 검색을 계속한다. 이 프로세스는 main context 에 이를 때까지 지속된다. 

이후 챕터에서 배우겠지만 이클립스트 context 가 주입될 수 있는 유일한 소스 객체는 아니다. 나중에 다뤄질 예제들로 OSGi 서비스들, preferences, events, custom 객체들이 있다. 검색은 주입 호출자를 위해 대부분 투명하게 발생한다.

16.5. How to access the model objects?

애플리케이션 모델내의 클래스 레퍼런스들에 대하여, 이클립스 프레임워크는 필요할 때 해당하는 객체를 생성한다. 그러한 하나의 객체는 의존성 주입을 통해 해당하는 모델 객체에 접근한다. 

예를들어 파트 구현에서, 우리는  @Inject MPart part; 선언을 통해 파트의 모델정보에 접근할 수 있다. 

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

16.6 Default entries in the Eclipse context

이클립스 프레임워크는 context 내에서 여러 객체들을 생성하며 그것들은 아래와 같다. 

● model objects -  애플리케이션 모델 데이터를 포함한다. 
● services - 이클립스 플랫폼이나 OSGi 서비스 레지스트리를 통해 정의되는 소프트웨어 컴포넌트들
● context 에 명시적으로 추가되는 여러 다른 객체들

context 는 애플리케이션이나 프레임워크에 의해 수정될 수 있다. 이클립스 프레임워크는 자동으로 이클립스 프레임워크가 생성하는 객체들의 종속성을 추적하기 때문에  Dynamic dependency injection based on key / value changes. 에 기술된 대로 그것들을 갱신할 수 있다. 

16.7. Qualifiers for accessing the active part or shell

이클립스 플랫폼은 현재 선택된 파트와 애플리케이션 객체의 IEclipseContext 안으로 액티브 셸을 위치시킨다. 관련되는 키들은 IServiceConstants interface 에 정의된다. 

예를들어 다음 메소드는 우리가 다른 파트에서 현재 엑티브한 파트를 추적할 수 있도록 할 것이다.

// tracks the active part @Inject @Optional public void receiveActivePart( @Named(IServiceConstants.ACTIVE_PART) MPart activePart) { if (activePart != null) { System.out.println("Active part changed " + activePart.getLabel()); } }

active shell 을 추적하기 위해서는  IServiceConstants.ACTIVE_SHELL 키를 사용한다. 

// tracks the active shell @Inject @Optional public void receiveActiveShell( @Named(IServiceConstants.ACTIVE_SHELL) Shell shell) { if (shell != null) { System.out.println("Active shell (Window) changed"); } }
이클립는 메뉴나 툴바 엔트리를 통해서 시작될 수 있는 액션들을 정의하기 위해 핸들러들을 사용한다. 하나의 핸들러 구현 클래스를 위해, 이 식별자들을 반드시 사용할 필요는 없다. 핸들러는 active 애플리케이션 컨텍스트에서 실행되기 때문이다.
16.8. Tracking a child context with @Active

@Active 애노테이션은 우리가 자식 컨텍스트 내에 있는 값들을 추적할 수 있도록 한다. 이클립스 프레임워크는 IEclipseContext 계층내에서 현재 활성화된 브랜치를 지속적으로 추적한다. 예를들어 사용자가 하나의 파트를 선택하면, 루트부터 파트의 IEclipseContext 까지 IEclipseContext 계층으로 된 경로가 현재의 활성화된 브랜치가 된다. 

@Active 를 이용해서 우리는 현재 자식요소의 엑티브 브랜치 내에 있는 값들을 추적할 수 있다. 액티브 브랜치가 변경될 때마다 또는 참조키의 값이 변경될 때 마다 이 값이  @Active 애노테이션을 사용하는 객체 안으로 재 주입되게 된다. 

애노테이션 사용방법은 아래와 같다.

public class MyOwnClass { @Inject void setChildValue( @Optional @Named("key_of_child_value") @Active String value) { this.childValue = value; } }
@Active 애노테이션은 현재 이클립스 프레임워크 자체에서는 사용되지 않으며, 이 튜토리얼의 저자는 이 애노테이션이 사용될 좋은 사용사례를 아직 찾지 못했다.

17. Using annotations to define behavior

17.1. API definition in a framework

우리가 우리의 애플리케이션에서 어떤 프레임워크를 사용하게 되면, 우리는 우리의 애플리케이션이 그 프레임워크와 어떻게 상호작용할 지에 대한 규약이 필요하다. 예를들어, 하나의 Java 객체가 툴바 버튼 클릭에 대한 책임이 있을 경우에(예를들면, 툴바의 버튼이 클릭되었을 때 뭔가 행동을 취해야 할 객체), 프레임워크는 이 객체의 어느 메소드가 호출될 필요가 있는지 알아야 한다. 

이 목적 때문에 모든 프레임워크는  Application Programming Interface (API) 를 정의한다. 이 API 는 우리의 코드가 프레임워크와 어떻게 상호작용 할 수 있는지를 정의한다. API 는 프레임워크가 생성하거나 제어하는 애플리케이션 객체들의 상호작용도 정의 한다. 일반적으로 프레임워크는 이 목적을 위해 상속 또는 애노테이션을 사용한다. 

17.2. API definition via inheritance

API 정의하는 전통적인 방식은 상속을 이용하는 것이다. 이러한 방식은 우리가 프레임워크의 클래스들을 상속받거나 인터페이스들을 구현을 필요로 한다. 이클립스 3.x 플랫폼 API 이런 방식을 이용한다. 
예를들어 이 프레임워크는 구현이 필요한 메소드를 정의해 놓은 추상 클래스를 정의한다. 

위에서 예를든 툴바 버튼 예제를 예로 들면, 버튼이 클릭되면  execute() 메소드가 호출될 수 도 있는데, 이렇게 되려면 프레임워크는 버튼이 클릭되었을 때 이 메소드가 호출되어야 한다는 것을 알고 있어야 한다. 

상속을 통한 API 정의 방식은 API 를 정의하는 단수한 한 방법이며 이러한 방식은 클래스들이 프레임워크에 강하게 결합되게 된다. 예를들어, 프레임워크없이는 만든 클래스들을 테스트하기가 어렵게 된다. 그것은 또안 프레임워크를 확장하고 업데이트하는 것을 어렵게 만들게 되는데 업데이트가 클라이언트에 영향을 미칠 수 도 있기 때문이다. 이러한 이유로 Eclipse 4.x 에서는 더이상 이러한 방식을 사용하지 않는다.

Table 6. Eclipse life cycle annotations for parts

Annotation
Description
@PostConstruct
클래스가 구성되고, 맴버변수와 메소드 인젝션이 수행된 후에 호출된다.
@PreDestroy
클래스가 소멸되기 전에 호출된다. 리소스들을 해제하는데 사용될 수 있다. 
@Focus
파트가 포커싱 될 때마다 호출된다.
@Persist
 이클립스 프레임워크가 파트에 저장요청을 하게 되면 호출된다. 
@PersistState
파트가 인스턴스상태를 저장할수 있도록,  모델객체가 해제되기 전에 호출된다.  이 메소드는 @PreDestroy 메소드가 호출되기전에 호출된다. 

@PostConstruct, @PreDestroy 애노테이션들은 javax.annotation 패키지에 포함된다.  @Persist, @PersistState , @Focus 들은 org.eclipse.e4.ui.di 패키지의 일부이다. 

이클립스는 다른 추가적인 작업을 하는 애노테이션들을 정의하는데 각 챕터에서 다뤄지고 있는 애플리케이션 라이프 싸이클과 커맨드들에 대한 것이다. 

행위(Behavior) 애노테이션들은 프레임워크가 메소드에게 기술되어있는 파라미터들을 제공해줘야 한다는 의미를 내포하고 있다. 프레임워크는 또한 메소드 의존성 주입을 수행 할 수도 있다. 만약 우리가 @Inject 애노테이션을 메소드에 추가한다면 그 메소드는 두번 호출된다, 첫번째는 의존성 주입단계동안이고 그 다음에는 행위 애노테이션을 위한 것이다. 이것은 일반적으로 바람직하지 않으며, 오류이다.
17.4. Use the @PostConstruct method to build the user interface

파트의 사용자 인터페이스는 @PostConstruct 애노테이션을 붙인 메소드에서 구성하는 것을 추천한다. 생성자에서 사용자 인터페이스를 구성할 수도 있으나 필드나 메소드 주입이 그 시점에 끝나지 않았기 때문에 추천하지 않는다. 

@PostConstruct 메소드에서 사용자 인터페이스를 생성하기 위해서는, @Inject 메소드들이 사용자 인터페이스가 아직 생성되지 않았을 수도 있다는 것을 알고 있어야 합니다.  - 이 문장이 무슨 뜻인지는 조금더 생각해 볼 필요가 있다. 아마도 내생각에는  @Inject 메소드들의 인자에 사용자 인터페이스 관련 파라미터가 포함되어 있을 경우 오류가 발생할 수도 있기 때문이지 않을 까 한다. 예를들어 사용자 인터페이스 생성에서는 아직 초기화 하지 않은 컴포넌트가  @Inject 메소드들에 포함될 수 도 있을 것 같다. 

Why is the @PostConstruct method not called?
다음에 나오는 설명은 Eclipse 4.6 (Eclipse Neon) 릴리즈 이전의 이클립스 버전에서만 유효하다. 이클립스 4.6 프레임워크는 자바버전의 @PostContruct 를 사용하기 때문에 여기서 설명하고 있는 문제는 더이상 발생할 수 없다. 

Eclipse 4.6 이전에 Java 7 과 이클립스 플랫폼 둘다 @PostConstruct 애노테이션을 노출 시켰다. 우리의 이클립스 애플리케이션에서 우리는 프레임워크에게 이클립스 플랫폼에서 노출 시킨 애노테이션이 사용되어야 한다는 것을 알려야 한다. org.eclipse.core.runtime 은 수정된 버전에서는 javax.annotation 엑스포트 한다. 만약 어떤 이유들로 인해서 우리가 org.eclipse.core.runtime 에 대한 종속성을 피하기 원한다면, 우리는 javax.annotation 패키지에 패키지 종속성을 정의 할 수 있으며 버전을 1.0.0 으로 설정하자. 이 문제에 대한 상세 정보는 " Eclipse 4 RCP FAQ(http://wiki.eclipse.org/Eclipse4/RCP/FAQ)" 에서 확인하자.

18. Exercise: Using @PostConstruct

18.1. Implement an @PostConstruct method

다음 메소드를 우리의 TodoOverviewPart, TodoDetailsPart, TodoDetailsPart 클래스들에 추가하자우리가 생성자를 통해  클래스들을 생성한 경우에는 생성자들을 제거해도 된다.

import javax.annotation.PostConstruct; import org.eclipse.swt.widgets.Composite; // more code @PostConstruct public void createControls(Composite parent) { System.out.println(this.getClass().getSimpleName() + " @PostConstruct method called."); }
18.2. Validating

애플리케이션을 실행시켜서 @PostConstruct  호출되는지 확인하자

19. Menu and toolbar application objects

19.1. Adding menu and toolbar entries

우리는 애플리케이션 모델을 이용해서 RCP 애플리케이션에 메뉴나 툴바를 추가할  있다 엔트리들은 다양한 위치에 추가할  있다예를들어 윈도우나 파트에 메뉴를 추가할  있다 요소들은 직접 또는 간접적으로 클래스를 연결하는 링크를 정의한다 클래스의 인스턴스는 프레임크가 생성하며 메뉴나 툴바 엔트리들이 선택될 때에 대한 실행책임을 프레임워크가 지는데 이러한 클래스를 handler 클래스라 한다.

19.2. The usage of commands and handlers

The Eclipse application model allows you to specify commands and handlers.
우리는 이클립스모델에 커맨드들과 핸들러들을 정의할  있다

커맨드와 핸들러 모델 사용은 옵셔널이다우리는 Direct MenuItem  Direct ToolItem  사용할  있는데  엔트리들은 클래스를(handler 클래스연결짓는 참조를 정의한다프레임워크는  핸들러 클래스를 생성 애노테이션이 설정된 메소드가 있을경우  메소드들을 호출한다메뉴들과 툴바들은 separator  지원한다(툴바의 세로 라인이나 메뉴내에 그룹을 구분짓는 가로라인)

하나의 커맨에는 save, edit, copy  같은기능을 수행하기 위한 액션들이 정의된다

하나의 커맨드는 구현된 클래스들과는 독립적이다이클립스프레임워크는 표준 커맨드를 제공하지 않는데 예를들어 우리는 애플리케이션 모델에 우리가 필요로 하는 모든 액션들을 생성해야 한다.

커맨드의 행위는 handler  이용해서 정의한다. handler 모델 요소는 contributionURI 속성을 이용해서 연결되는 클래스를 가리킨다 속성은 모델 에디터창에서는 Class URI  표시된다

커맨드들은 Handled MenuItem  Handled ToolItem 요소들에 의해 사용된다직접적으로 메뉴아이템이느 툴아이템으르사영하기 보다는 커맨드를 사용하는 것이 좋다커맨드와 핸들러를 함께 사용하는 방식은 우리가 애플리케이션이나 파트와 같은 다른 스콥들마다 다른 핸들러를 정의할  있도록 한다우리는 핸들러와 연관되는 커맨드들을 키로 바인딩되도록 정의할  있다

19.3. Behavior annotations and dependency injection for handler classes

핸들러 클래스내에는 하나의 메소드에만 @Execute  사용할  있다또한 하나의 메소드에만 @CanExecute  사용할  있다우리가  이상의 메소드에  애노테이션을 사용하게되면 프레임워크는 그것들 중에서 하나만 호출한다이클립스 런타임은 메소드의 파라미터를 제공하기 위해 의존성 주입을 사용한다이런 애노테이션들의 목적은 다음테이블에 기술된다.

Table 7. Behavior annotations for handler classes

Annotation
Description
@Execute
핸들러에서 액션을 책임질 메소드에 표시한다. 프레임워크는 사용자 인터페이스와 관련되는 매뉴 엔트리 등이 선택될 경우 이 메소드를 한번 실행시킨다.
@CanExecute
이클립스 프레임워크가 핸들러가 현재 실행 가능한지를 체크하기 위해 사용할 메소드에 표시해라. 핸들러 클래스의 이 메소드가 false 를 반환하면 이클립스는 해당하는 사용자 인터페이스를 비활성화 시킨다. 예를들어 핸들러 클래스의 @CanExecute 가 표시된 메소드에서 true 를 반환하면 저장 버튼은 활성화 된다. 이 메소드의 기본 반환값은 true 이기 때문에 핸들러 클래스는 항상 실행될 수 있다. @CanExecute 메소드는 반드시 구현할 필요는 없다.

다음예제는 핸들러 클래스의 구현예제를  보여준다

package com.example.e4.rcp.todo.handlers; // import statements cut out // .. public class ExitHandler { @Execute public void execute(IWorkbench workbench) { workbench.close(); } // NOT REQUIRED IN THIS EXAMPLE // just to demonstrates the usage of // the annotation @CanExecute public boolean canExecute() { return true; } }

핸들러 인스턴스는 자신의 이클립스 컨텍스트를 갖지 못한다핸들러는 이클립스 컨텍스트를 가지고 있는 액티브한 모델 요소의 이클립스 컨텍스트와 함께 실행된다. 그 컨텍스트는 대부분의 경우  활성화된 파트의 컨텍스트이다. 

우리는 핸들러 클래스가 실행시간동안 런타임 정보를 사용하도록 하고 싶을 때, 모든 필요한 파라미터들이 @Execute가 표시된 메소드안으로 주입되도록 설정하는 것이 좋다. 

우리가 기대한 값들이 항상 액티브 컨텍스트로부터 가져오도록 보장하기 위해서는 @Execute나 @CanExecute가 표시된 메소드 내에 파라미터로 필요한 값들이 주입되도록 하자.
19.4. Determining the relevant handler for a command

커맨드가 선택되면 런타임은 커맨드에 해당하는 적당한 핸들러를 결정한다. 애플리케이션 모델은 우리가 애플리케이션, 윈도우, 파트에 맞는 핸들러를 생성할 수 있도록 해준다. 

각 커맨드는 주어진 스콥에 대해서 온전한 하나의 핸들러를 가질 수 있다. 이클립스 프레임워크는 모델요소에서 가장 적절한 핸들러를 선택한다. 예를들어, 우리가 "Copy"커맨드에 윈도우와 파트를 위한 두개의 핸들러를 정의 했을 경우, 런타임은 현재 사용자가 선택한 모델요소에 가장 가까운 핸들러를 선택한다. 

참고 캡쳐화면이다. 스콥별 핸들러를 정의할 수 있다.
19.5. Evaluation of @CanExecute

이클립스 컨텍스트 내에서 변경이 일어나면,  @CanExecute가 표시된 메소드가 프레임워크에 의해서 호출된다. 예를들어, 우리가 새로운 파트하나를 선택하면, 그리고 @CanExecute가 표시된 메소드가 "false"를 반환한다면,  프레임워크는 그 커맨드에 연결되는 어떤 메뉴나 아이템들도 비활성화 시킨다. 

우리는 이벤트 브로커를 사용하여 이벤트를 전달함으로서  @CanExecute 메소드들을 다시 실행시키도록 할 수 있다.

// evaluate all @CanExecute methods eventBroker.send(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, UIEvents.ALL_ELEMENT_ID); // evaluate a context via a selector Selector s = (a selector that an MApplicationElement or an ID); eventBroker.send(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, s); //See https://bugs.eclipse.org/bugs/show_bug.cgi?id=427465 for details
19.6. Mnemonics

애플리케이션 모델은 우리가 mnemonics 정의할 수 있도록 해준다. mnemonic 은 우리가 ALT키를 누르고 있을 때, 메뉴에 표시되는 글자(글자밑에 밑줄이 그어져 있다.)를 말한다.  이 기능을 이용하면 사용자는 키보드를 이용하여 빠르게 메뉴들에 접근할 수 있다. 

우리는 label 정의에  ampersand (&)를 이용해서 앞글자가 mnemonics 되도록 기술 할 수 있다. 예를들어 우리가 레이블의 이름을 &Save 이라고 하면, 사용자가 키보드의 ALT키를 누를경우 S 밑에 밑줄이 그어진 글자가 표시될 것이다. 

19.7. Naming schema for command and handler IDs

ID를 명명하는 좋은 방법으로는 우리 프로젝트의 탑 레벨 패키지 이름으로 아이디를 시작하고 소문자만 사용하는 것이다. 

커맨드들과 핸들러들의 아이디는 그것들의 관계를 반영한다. 예를들어 우리가  com.example.contacts.commands.show 라는 ID갖는 커맨드를 구현하면, 우리는 핸들러에 대한 ID 는 com.example.contacts.handler.show를 사용하는 것이 좋다. 하나의 커맨드에 대해 둘 이상의 커맨드가 있을경우, ID 에 목적을 기술하는 또다른 접두어를 추가하자.  예를들어 "com.example.contacts.handler.show.details" 이렇게 지을 수 있을 것이다.

우리가 공통으로 사용될 save, copy와 같은 기능들을 구현한다면, 플랫폼에 미리 정의되어 있는 ID 들을 사용하는 것이 좋은데, 이클립스의 일부 컨트리뷰션들은 이 ID들이 OS와 더 잘 통합될 것으로 예상하기 때문이다. (예를들어, Mac OS에서 환경설정(preferences) 메뉴는 기본적으로 첫번째 메뉴에 위친한다. org.eclipse.ui.IWorkbenchCommandConstants 에서 사용가능한 공통 ID리스트는 아래 테이블과 같다. 

Table 8. Default IDs for commonly used commands

Command
ID
Save
org.eclipse.ui.file.save
Save All
org.eclipse.ui.file.saveAll
Undo
org.eclipse.ui.edit.undo
Redo
org.eclipse.ui.edit.redo
Cut
org.eclipse.ui.edit.cut
Copy
org.eclipse.ui.edit.copy
Paste
org.eclipse.ui.edit.paste
Delete
org.eclipse.ui.edit.delete
Import
org.eclipse.ui.file.import
Export
org.eclipse.ui.file.export
Select All
org.eclipse.ui.edit.selectAll
About
org.eclipse.ui.help.aboutAction
Preferences
org.eclipse.ui.window.preferences
Exit
org.eclipse.ui.file.exit

20. Exercise: Adding menus

이번 예제에서 우리는 애플리케이션에 커맨드와 핸들러를 생성하고 이 커맨드를 이용하여 메뉴 엔트리들을 생성할 것이다. 

20.1. Create command model elements

com.example.e4.rcp.todo 플러그인 프로젝트의 Application.e4xmi 파일을 오픈하고 Commands 항목을 선택하자. 아래의 화면은 Commands를 선택한 모습이다. 

Add 버튼을 누르면 새로운 커맨드를 생성할 수 있다. 이름과 ID는 중요한 필드다. 아래의 테이블에 따라 커맨드를 생성하자. 

Table 9. Commands

ID
Name
org.eclipse.ui.file.saveAll
Save
org.eclipse.ui.file.exit
Exit
New Todo
com.example.e4.rcp.todo.command.remove
Remove Todo
com.example.e4.rcp.todo.command.test
For testing

20.2. Creating the handler classes

핸들러 클래스를 생성할 com.example.e4.rcp.todo.handlers 패키지를 생성하자.
모든 핸들러 클래스들은  @Execute애노테이션을 표시한 execute() 메소드를 구현한다. 

package com.example.e4.rcp.todo.handlers; import org.eclipse.e4.core.di.annotations.Execute; public class SaveAllHandler { @Execute public void execute() { System.out.println((this.getClass().getSimpleName() + " called")); } }

위의 탬플릿을 활용해서 아래의 클래스들도 구현해 보자. 
● SaveAllHandler
● ExitHandler
● NewTodoHandler
● RemoveTodoHandler
● TestHandler

20.3. Creating handler model elements

애플리케이션 모델에 애플리케이션 스콥의 Handlers 엔트리를 선택하고 우리의 커맨드에 맞는 핸들러들을 아래 테이블을 참고해서 생성하자. 핸들러들의 ID 정의하기에는 커맨드와 클래스는 적절한 정보가 된다. 

핸들러 ID에 대해서는 "com.example.e4.rcp.todo.handler"를 접두어로 사용하자. 

Table 10. Handlers

Handler ID
Command
Class
.saveall
Save
SaveAllHandler
.exit
Exit
ExitHandler
.new
New Todo
NewTodoHandler
.remove
Remove Todo
RemoveTodoHandler
.test
For testing
TestHandler

애플리케이션 모델 에디터는 커맨드의 ID와 이름 둘다 보여준다. 클래스 URI 는  bundleclass:// 다음에 오며, 테이블에는 읽기 편하도록 클래스의 이름만 정의한다. 예를들어, save 핸들러의 경우 다음과 같이 보이게 된다. 

20.4. Adding a menu

Application.e4xmi 파일에서 모델내의 TrimmedWindow를 선택하고 Main Menu속성을 체크하자.

메인메뉴 아이디에 "org.eclipse.ui.main.menu"를 할당하자.

메인메뉴의 ID정확한지 확인하자. 나중에 우리는 다른 플러그인을 통해서 해당메뉴에 다른 메뉴를 엔트리를 추가할 것이다.

두개의 메뉴를 추가하자. 하나는 "File", "Edit"이름의 메뉴를 추가하자. 이름은 Label에 입력하면 된다. 

File메뉴의 아이디는  org.eclipse.ui.file.menu으로 설정하고, Edit메뉴는 com.example.e4.rcp.todo.menu.edit로 설정하자. 

File메뉴에 Handled MenuItem요소를 추가하자. 이 아이템은 Command속성을 이용해서 Save커맨드를 가리키도록 하자. 

Save메뉴 아이템 다음에 Separator를 추가하고 그다음에 Exit커맨드용 엔트리를 추가하자. Edit메뉴에 다른 커맨드들도 모두 추가하자. 

20.5. Implement a handler class for exit

핸들러가 동작하는지 테스트하기 위해, 메뉴가 선택되었을 때 애플리케이션이 종료되도록 ExitHandler클래스를 아래와 같이 수정하자. 

package com.example.e4.rcp.todo.handlers; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.e4.ui.workbench.IWorkbench; public class ExitHandler { @Execute public void execute(IWorkbench workbench) { workbench.close(); } }
20.6. Validating

Save메뉴를 선택했을 때, 우리의 save핸들러가 호출되는지 확인하자. Exit메뉴를 통해서 애플리케이션을 종료할 수 있는지도 확인해 보자. 

20.7. Possible issue: Exit menu entry on a MacOS

Mac에서 exit커맨드의 ID를 "org.eclipse.ui.file.exit"으로 사용할 경우 이클립스 프레임워크는 메뉴엔트리를 Mac OS의 기본위치에 매핑시킨다. 따라서 우리는 exit메뉴를 우리가 정의한 위치에서 볼수 없게 된다. 표시되는 위치를 확인해 보자. 

21. Exercise: Adding a toolbar

이번 예제에서는 애플리케이션에 툴바를 추가할 것이다. 

21.1. Adding a toolbar

TrimmedWindow를 선택하고 하위의 TrimBars노드를 선택한다음 Add버튼을 선택하자. 모든 툴바들이 애플리케이션의 상단에 보이도록 하기 위해서 Side속성은 Top으로 설정되어야 한다. 

TrimBar에 ToolBar를 추가하고 이 ToolBar에  Handled ToolItem을 추가하자. Handled ToolItem은 org.eclipse.ui.file.saveAll커맨드를 가리킨다. 그리고 이름은 Save로 하자. 

21.2. Validating

툴바또는 메뉴에서 save메뉴를 선택했을 때, save핸들러가 호출되는지 확인하자. 

22. View, popup and dynamic menus

22.1. View menus

우리는 파트내에 뷰메뉴와 같은 하나의 메뉴를 정의할 수 있다. 애플리케이션모델은 하나이상의 메뉴를 정의 할 수 있도록 되어있지만 이클립스 기본구현은 파트하나당 하나의 메뉴만 지원한다는 것을 알아두자. 뷰메뉴 엔트리를 추가하려면 파트 밑의 Menus엔트리를 선택하고 ViewMenu를 추가하자.

22.2. Popup menu (context menu)

우리는 애플리케이션 모델을 이용하여 SWT컨트롤들에 팝업 메뉴를 정의할 수 있다. 이렇게 하기 위해서는 SWT컨트롤을 담고 있는 파트에 Popup Menu를 생성해야 한다. 

Vogella의 블로그에는 네모칸 표시된 파트의 이름인 To-Dos로 되어 있는데 이전에 작성한 예제와는 다르다. 일단 나는 이전에 만들어둔 플러그인을 기준으로, Overview파트에 작성 하고 있다. 아래의 파트클래스 구현예제를 보면 TodoOverviewPart클래스에 예제코드를 작성하고 있기 때문이다.

팝업메뉴는 아래의 화면과 같이 하나의  HandledMenuItem을 포함하고 있다.

위의 작업 이후, 의존성 주입을 통해 접근할 수 있는 EMenuService서비스를 이용하여 SWT컨트롤에 팝업메뉴를 할당할 수 있으며. 이러한 할당 작업을 위해 이 클래스는 registerContextMenu(control, id)라는 메소드를 제공한다. registerContextMenu의 id파라미터는 반드시 Popup Menu모델의 ID속성이 되어야 한다. 

아래의 수도코드는 팝업메뉴 등록을 위한 예제이다. 팝업메뉴는 SWT컨트롤에 등록되어야 하기 때문에 JFace 뷰어를 사용한다. 아래의 예제코드는 이 컨트롤에 접근하는 방법을 보여준다.

package com.example.e4.rcp.todo.parts; import javax.annotation.PostConstruct; import org.eclipse.e4.ui.services.EMenuService; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; public class TodoOverviewPart { @PostConstruct public void createControls(Composite parent, EMenuService menuService) { // more code... TableViewer viewer = new TableViewer(parent, SWT.FULLSELECTION | SWT.MULTI); // more code // register context menu on the table menuService.registerContextMenu( viewer.getControl(), "com.example.e4.rcp.todo.popupmenu.table"); } }
위의코드는 수도코드다, 그대로 동작하는 코드가 아님을 참고하자. 동작하도록 하기 위해서는 상용된 컨트롤에 대한 종속성들을 추가해주고 코딩 작업을 해줘야 한다.

위의 예제를 구현하기 위해서는 우리의 플러그인의  MANIFEST.MF파일에 org.eclipse.e4.ui.workbench.swtorg.eclipse.e4.ui.services , org.eclipse.e4.ui.model.workbench,org.eclipse.jface플럭드인들을 포함하고 있어야 한다. 

22.3. Dynamic menu and toolbar entries

우리는 DynamicMenuContribution를 이용해서 런타임시에 메뉴와 툴바엔트리들을 생성할 수도 있다. 

이 모델요소는  @AboutToShow애노테이션을 표시한 메소드를 갖는 클래스를 가리킨다. 사용자가 사용자 인터페이스 요소를 선택할 경우에   @AboutToShow이 표시된 메소드가 호출된다. @AboutToHide애노테이션은 메뉴가 숨겨지기전에 호출될 메소드에 표시하기 위해 사용될 수 있다. 우리는 이 메소드들 내에서 동적으로 메뉴 엔트리들을 생성할 수 있다. 

23. Toolbars, ToolControls and drop-down tool items

23.1. Adding toolbars to parts

애플리케이션 모델에 있는 툴바들은  Trimbars모델요소내에 정의된다. 하나의 trimbar(트림바)는 TrimmedWindow요소들에 정의 될 수 있다. 우리는 Side속성을 이용해서 트림바를 윈도우의 top, left, right, bottom에 위치시킬 수 있다. 하나의 뷰에 툴바를 추가하기 위해서는 그 파트에서 Toolbar플래그를 체크하고 애플리케이션 모델에 엔트리들을 생성해줘야 한다. 

아래의 화면은 어떻게 설정하는지를 보여준다.

23.2. ToolControls

ToolControl모델요소는 툴바에 표시될 컨트롤들을 생성할 수 있는 Java클래스를 가리킨다. 

예를들어, 다음 코드는 검색 필드와 같은 모습의 Text필드를 생성하는 코드다. 

package com.example.e4.rcp.todo; import javax.annotation.PostConstruct; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; public class SearchToolItem { @PostConstruct public void createControls(Composite parent) { final Composite comp = new Composite(parent, SWT.NONE); comp.setLayout(new GridLayout()); Text text = new Text(comp, SWT.SEARCH | SWT.ICON_SEARCH | SWT.CANCEL | SWT.BORDER); text.setMessage("Search"); GridDataFactory.fillDefaults().hint(130, SWT.DEFAULT).applyTo(text); } }

우리는 아래의 화면과 같이 윈도우 트림바에  ToolControl를 추가할 수 있다. 

아래의 화면은 RCP애플리케이션에 적용된 모습이다. 

23.3. Drop-down tool items

아래의 스크린샷에 있는 Run As버튼과 유사하게 정의하고(Dropdown 메뉴) 싶다면 툴아이템의 속성 중 Menu속성을 체크하자. 

아래의 화면과 같이 Menu항목을 체크하고 하위에 메뉴를 추가하게 되면, 위와 같은 모습이 된다. 

24. More on commands and handlers

24.1. Passing parameters to commands

우리는 커맨드에 파라미터를 전달할 수도 있다. 파라미터를 전달하기 위해서는 커맨드를 선택하고 파라미터 섹션에 있는  Add 버튼을 선택하자. 

ID는 식별자로서 우리는  @Named애노테이션을 이용해서 주입될 파라미터 벨류를 얻기위에 이 ID를 사용할 수 있다. 

HandledMenuItem 또는 HandledToolItem에 파라미터를 추가하고 위에서정의한 커맨드파라미터 ID를 Name필드에 추가하자. Value필드에 있는 엔트리는 커맨드의 핸들러에 전달된다. 

파라미터의 ID는 중요하다. 이 ID는 @Named애노테이션을 통해 사용되며, 메뉴나 툴바를 정의할 때, Command Parameter ID로서 사용된다. 이 설명에 대한 그림은 아래와 같다.

핸들러 클래스 안으로 주입될 파라미터를 얻기 위해 우리는 @Named애노테이션을 이용하여 파라미터의 ID를 사용한다. 예제는 아래와 같다. 

package com.example.e4.rcp.todo.handlers; import java.util.List; import javax.inject.Named; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.e4.ui.model.application.MApplication; import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective; import org.eclipse.e4.ui.model.application.ui.basic.MWindow; import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.eclipse.e4.ui.workbench.modeling.EPartService; // switcher perspectives based on a command parameter public class PerspectiveSwitchHandler { @Execute public void switchPerspective( MWindow window, EPartService partService, EModelService modelService, @Named("perspective_parameter") String perspectiveId) { // use parameter to find perspectives List<MPerspective> perspectives = modelService.findElements(window, perspectiveId, MPerspective.class, null); // switch to perspective with the ID if found if (!perspectives.isEmpty()) { partService.switchPerspective(perspectives.get(0)); } } }

각 파라미터 이름별로 접근하는 대신  ParameterizedCommand커맨드를 주입하고 API를 이용해 파라미터들에 접근할 수 있는 방법이 있다. 아래의 예제를 참고하자.

package com.example.e4.rcp.todo.handlers; import javax.inject.Named; import org.eclipse.e4.core.di.annotations.Execute; public class TestHandlerWithCommandInjected { private String parametername = "com.example.e4.rcp.todo" + ".commandparameter.input"; @Execute public void execute(ParameterizedCommand command) { Object queryId = command.getParameterMap().get(parametername); // more... } }
24.2. Usage of core expressions

core expressions를 이용하여 메뉴나 툴바 그리고 그것들의 각 엔트리들을 보이거나 보이지 않도록 제약할 수 있다. 우리는 애플리케이션 모델에 있는 해당 속성을 plugin.xml파일에 있는 org.eclipse.core.expressions.definitions확장 포인트에 정의되어 있는 ID에 추가한다. 

이 확장점을 애플리케이션에 추가하고자 한다면,  plugin.xml파일을 열고 에디터에서 Dependencies탭을 선택하자. 그리고 나서 Required Plug-ins부분에서 org.eclipse.core.expressions를 추가하자. 

 Extensions탭을 선택하고, Add버튼을 누른다음 org.eclipse.core.expressions.definitions를 추가하자. 우리는 코어 익스프레션이 애플리케이션 모델내에서 참조될 수 있는 위치에 ID를 정의한다. 

extension에 마우스 우클릭을하여 expression을 구축을 시작하자. 

아래의 예제는 현재 셀렉션타입을 기준으로 메뉴 엔트리의 가시성을 제약하기 위해 사용될수 있다. 우리는 나중에 현재 셀렉션을 설정하는 방법을 배울 것이다. 현재 셀렉션 변수는 org.eclipse.ui.selection으로 함을 알아두자. 이클립스 3.x에서는 이 변수는 selection으로 한다. 

<extension point="org.eclipse.core.expressions.definitions"> <definition id="com.example.e4.rcp.todo.selectionset"> <with variable="org.eclipse.ui.selection"> <iterate ifEmpty="false" operator="or"> <instanceof value="com.example.e4.rcp.todo.model.Todo"> </instanceof> </iterate> </with> </definition> </extension>

우리는 이 코어 표현을 애플리케이션 모델내의 메뉴엔트리에 할당할 수 있으며 모델요소의 가시성을 제약 할때 사용할 수 있다. 

이 접근방식은 Eclipse 3.x에서 core expressions을 정의하는것과 유사하다. 

Eclipse 3.x에서 사용가능한 값들은 ISources에 포함되며, Eclipse core expressions wiki에 문서화되어 있다. 이클립스4는 같은 변수들을 지원하는 것은 아니지만 위키 문서는 도움이 될 수 있다. 

24.3. Evaluate your own values in core expressions

우리는 애플리케이션의  IEclipseContext에 값들을 저장하고서  visible-when을 체크할 때 사용할 수 있다. 

다음 코드는 컨텍스트에  myactivePartId를 키로정하고서 값을 저장하는 핸들러클래스의 예제이다.(우리는 나중에 IEclipseContext수정하는 것에 대하여 배울 것이다.)

@Execute public void execute(IEclipseContext context) { // put an example value in the context context.set("myactivePartId", "com.example.e4.rcp.todo.part.todooverview"); }

아래의 예제는 컨텍스트 내에서 myactivePartId키에 대한 값이 com.example.e4.rcp.ui.parts.todooverview일 경우 true로 평가하는 core expression이다. 

<extension point="org.eclipse.core.expressions.definitions"> <definition id="com.example.e4.rcp.todo.todooverviewselected"> <with variable="myactivePartId"> <equals value="com.example.e4.rcp.todo.part.todooverview"> </equals> </with> </definition> </extension>

이렇게 정의한 core expression은 메뉴 엔트리와 컨트롤 가시성에 할당될 수 있다. 

25. Key bindings

25.1. Using key bindings in your application

우리는 이클립스 애플리케이션 키바인딩(shortcuts)도 정의할 수 있다. 정의하기 위해서는 2단계가 필요한데 첫번째로 애플리케이션 모델에 Binding Context노드에 값을 입력하는 것이다. 

애플리케이션 모델의  BindingTable노드에는 바인딩 컨텍스와 연결될 키바인딩들을 입력해야 한다. 바인딩 테이블은 항상 특정 바인딩 컨텍스트에 할당된다. 하나의 바인딩 컨텍스트에는 여러바인딩 테이블들이 할당될 수 있다. 

바인딩 컨텍스트들은 계층적으로 정의되며, 자식에서 정의한 키 바인딩은 부모에서 정의된 키 바인딩들을 오버라이드 할 수 있다.

비슷하게 들리겠지만, 하나의 바인딩 컨텍스트가 키 바인딩들에 사용되지만, 이클립스 컨텍스트(IEclipseContext)는 의존성 주입을 위한 소스로서 사용된다.
25.2. JFace default values for binding contexts

바인딩 컨텍스트는 ID통해 식별되며, 애플리케이션 모델내의 윈도우나 파트에 할당된다. 바인딩 컨텍스트는 어느 키보드 숏컷이 윈도우에서 사용될 수 있는지 그리고 파트에 사용될 수 있는 숏컷들이 어느 것인지를 정의한다. 

이클립스 JFace는 바인딩 컨텍스트들을 식별하기 위해 미리 정의해둔 ID를 사용한다. 이 ID들은  org.eclipse.jface.contexts.IContextIds클래스를 기준으로 한다. JFace는 다이러그, 윈도우 또는 둘다에 대한 쇼컷들을 구별한다. 

아래의 테이블은 지원되는 ID들과 그 ID에 대한 유효범위를 보여준다.

Table 11. Default BindingContext values

Context ID
Description
org.eclipse.ui.contexts.dialogAndWindow
다이어로그와 윈도우에 유효한 키바인딩 들
org.eclipse.ui.contexts.dialog
다이어로그에 유효한 키 바인딩 들
org.eclipse.ui.contexts.window
윈도우들에 유효한 키바인딩 들

예를들어 ctrl+c(copy)는 어디에서든 사용가능하기 때문에 dialogAndWindows에 정의될 것이다. 그러나 F5(Refresh)는 다이어로그가 아닌 윈도우에서만 정의되어야 할 수도 있다. 

25.3. Define Shortcuts

애플리케이션 모델의  BindingTable노드는 우리가 바인딩 컨텍스트를 기준으로 키바인딩들을 생성할 수 있도록 해준다. 이렇게 하기 위해, 우리는 BindingTable모델 요소를 만들고 ID를 이용해서 바인딩 컨텍스트를 참조하도록 정의할 수 있다. 

키바인딩 엔트리에, 우리는 쇼컷과 연관되는 키 시퀀스와 커맨드를 기술 한다. 

컨트롤(ctrl)키들은 플랫폼마다 다른다. 예를들어 Mac이나 리눅스 시스템상에서 다른다. 우리는 Ctrl을 사용할 수 있지만 이것은 하드코딩이 될 것이다. 따라서 M1-M4까지 메타키들을 사용하는 것이 더 낫다. 

Table 12. Key mapping

Control Key
Mapping for Windows and Linux
Mapping for Mac
M1
Ctrl
Command
M2
Shift
Shift
M3
Alt
Alt
M4
Undefinec
Ctrl

위의 값들은 SWTKeyLookup에 정의되어 있다. 

25.4. Activate bindings

여러개의 유효한 키바인딩들이 정의되어 있다면,  ContextSet클래스는 기본적으로 그것들 중 하나를 활성화 할 책임이 있다. ContextSet은 검색 순서를 결정하기 위해서 바인딩 컨텍스를 계층을 사용한다. 하나의 바인딩 컨텍스트는 자신과(자신이 가지고 있는 레벨 넘버) 루트바인딩 사이에 얼마나 많은 상위의 컨텍스트가 있는지에 따라 특정된다. 가장 특정되는(the most specific, 가장 범위가 좁은것을 의미하는것 같다) 바인딩 컨텍스트가 첫번째로 고려되며, 루트는 가장 마지막에 고려된다. 

 우리는 EContextService의  activateContext(), deactivateContext()메소드를 통해서 바이딩 컨텍스트를 명시적으로 활성화 비활성화를 시킬 수 있다. 

25.5. Key bindings for a part

우리는 특정 바인딩 컨텍스트를 어느 한 파트가 액티브되어 있는 동안에만 활성화되도록 할 수 있다. 

파트에 할당되는 키 바인딩들은 유효하며 또한 현재 활성화된 바인딩 컨텍스트가 제공하는 키 바인딩 또한 유효하다. 파트의 키바인딩과 함께 글로벌 키 바인딩도 활성화 되어 있다. 

26. Enable to start your product with right mouse click

프로덕트에 마우스 우클릭 후  Run-as ▸ Eclipse Application 을 선택해서 프로덕트를 시작시키고 싶을 경우에 우리는 프로덕트 구성파일(product configuration)이 있는 곳의 프로젝트에 pde nature를 추가할 수 있다.

Package Explorer뷰는의 필터 설정에 .*resources 가 체크되어 있을 수 도 있다. 아래의 화면을통해 뷰메뉴의 필터 설정을 수정할 수 있다.

 Package Explorer에서 .(dot)로 시작하는 파일을 필터링 하는 조건들을 제거하자 그러면, 프로덕트 프로젝트에서 .project파일을 확인할 수 있는데 이 파일을 오픈하고 아래와 같이 수정하자. 

<projectDescription> <name>com.example.e4.rcp.todo.product</name> <comment></comment> <projects> </projects> <buildSpec> <buildCommand> <name>org.eclipse.pde.ManifestBuilder</name> <arguments> </arguments> </buildCommand> <buildCommand> <name>org.eclipse.pde.SchemaBuilder</name> <arguments> </arguments> </buildCommand> </buildSpec> <natures> <nature>org.eclipse.pde.PluginNature</nature> </natures> </projectDescription>

수정 후 아래은 화면과 같이 메뉴를 선택해서 실행해 보자

끝났다. 이상 추가적인 정보는 Vogella홈페이지나 다른 경로를 통해서 확인하자. 

 by   성태혁

 

 

 

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
35 [EMF] EMF Tutorial EMF 튜터리얼 file 졸리운_곰 2023.08.23 21
34 Eclipse RAP Tutorial for Beginners - Workbench Application (OLD) file 졸리운_곰 2021.01.30 66
33 Learn Eclipse GMF in 15 minutes file 졸리운_곰 2019.11.27 42
32 [Eclipse] GEF entry series (10, an implementation of the form) file 졸리운_곰 2019.11.25 45
31 GEF Programmer Guide 번역 졸리운_곰 2019.11.25 53
30 Learn Eclipse GMF in 15 minutes file 졸리운_곰 2019.11.20 41
29 RCP 에디터 정리 졸리운_곰 2019.11.20 122
28 다른 그림과 관련하여 GEF 편집기 레이아웃에서 그림의 위치 제한 조건을 동적으로 계산 Dynamically calculating the position constraints for a figure in a GEF editor layout in relation to another figure file 졸리운_곰 2019.11.20 90
27 RCP 등에서 .mf 파일로 다른 프로젝트 익스포트 포함시 라이브러리(메소드)를 찾지 못할 때, Eclipse RCP - cant resolve importing libraries in final build file 졸리운_곰 2019.10.15 181
26 ESE2006-EclipseModelingSymposium15_GMF.pdf file 졸리운_곰 2019.09.21 64
25 GMF_Creation_Review.pdf file 졸리운_곰 2019.09.21 74
24 Eclipse EMF and GMF Tutorial file 졸리운_곰 2019.09.21 46
23 GMF Tutorial/ko file 졸리운_곰 2019.09.20 162
22 Model Driven Architecture approach to domain of graphical editors file 졸리운_곰 2019.09.20 44
21 Single_Sourcing_RAP_RCP_en.pdf file 졸리운_곰 2019.05.15 27
20 Rich client platform 설명 및 배우기 참고 졸리운_곰 2019.05.15 89
19 Rich Ajax Platform, Part 1: 소개 file 졸리운_곰 2019.05.15 127
18 또 하나의 크로스 플랫폼: Eclipse RAP file 졸리운_곰 2019.05.15 143
» Eclipse 4 RCP 튜토리얼(완료) file 졸리운_곰 2019.05.14 682
16 Updating UI in Eclipse RCP 졸리운_곰 2015.11.07 183
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED