번역 문서 저작권 표시 :
저작자표시-비영리-동일조건 변경 허락 (CC BY-NC-SA)
원문 저작권 표시 :
(Eclipse IDE Plug-in Development: Plug-ins, Features, Update Sites and IDE Extensions, by Lars Vogel (c) 2009 - 2020 vogella GmbHVersion 5.5,31.08.2018, CC BY-NC-SA )
소스 코드의 경우 Eclipse Public License 2.0 를 따른다.

[원문 출처] www.vogella.com/tutorials/EclipsePlugin/article.html


해당 문서의 경우 vogella사의 Eclipse IDE Extensions 
Document 문서 일부를 번역 한 것입니다.
번역본인 해당 문서의 경우 역자에게 있음을 알리며 상업적 이용을 불허합니다. 
번역 작업 시 이클립스 내 고유이름을 가진 값의 경우, 가령 Tab의 명칭 등의 경우 화면에서 표시되는 이름이므로 별도로 번역없이 제공하거나 괄호를 사용하여 동시에 명기한다.
저작자표시-비영리-동일조건 변경 허락 (BY-NC-SA)

www.sogomsoft.co.kr (주) 소곰소프트 

 

이클립스 IDE 플러그인 개발: Plug-ins, Features, Update Sites 와 IDE Extensions

Lars Vogel (c) 2009 - 2020 vogella GmbHVersion 5.5,31.08.2018

이 튜토리얼은 사용자 정의 플러그인으로 이클립스 IDE를 확장 하기 위한 방법을 기술한다. 

 

1. 이클립스 IDE 확장하기

이클립스 플랫폼과 이클립스 IDE는 기능을 추가, 제거, 또는 존재하는 기능을 사용자 정의 하는 것을 가능하게 하는 확장 가능한 프레임워크이다. 

이클립스 IDE의 모든 다운로드는 소프트웨어 개발을 지원하는 것에 맞춰진 특별한 이클립스 어플리캐이션을 볼수 있다. 이클립스 어플리케이션은 플러그인으로 불리는 개별 소프트웨어 컴포너트로 구성되어 있다. 예를 들면, 이클립스 IDE는 JDT 플러그인들을 통해 Java 어플리케션을 개발 하기 위한 기능을 제공한다.

이클립스가 확장가능한 프레임워크로 만들어 졌기 때문에, 플러그인을 사용할 수 있고 다른 플러그인을 확장 할 수 있다. 

개발 하는 동안, 플러그인을 테스트 하고 디버깅하기 위해 이클립스 IDE의 새 인스턴스를 시작할 수 있다. 새 인스턴스는 때때로 런타임 이클립스 내부 인스턴스로 불린다.

플러그인 또는 MANIFEST 파일의 컨텍스트 메뉴에서 Run As  Eclipse Application 을 선택하는 것이 런타임 이클립스를 시작하는 가장 시윈 방법이다. 기본적으로, 이 명령어는 워크스페이스와 대상 환경으로 부터 모든 플러그인을 얻고, 그 플러그인들로 부터 런타임 이클립스를 시작한다. 그 워크스페이스에서 하나가 사용된다.

런타임 이클립스를 디버깅 할 수 있다. 인스펙션 하기를 원하는 소스코드에 브레이크포인트를 넣고, 플러그인을 오른쪽 클릭하고 Debug As  Eclipse Application를 선택한다.

실행 흐름이 프레이크 포인트로 표시된 구문에 도달 했을 때, 실행이 멈추고, 관련된 구문을 디버깅하는 것과 현재 데이타를 검사하는 것을 할 수 있다. 이 투토리얼은 이클립스 IDE를 사용하는 것과 기본적인 자바 개발에 익숙한 것을 가정한다.

2. 이클립스 SDK 다운로드

이클립스 플랫폼에 기능들을 추가 할 계획이라면 마지막 릴리즈 버전을 다운로드 해야 한다. 공식 릴리즈가 안정적 API가 있습니다, 따라서 플러그인과 features를 추가하기 위한 가장 좋은 기초가 됩니다.

 이클립스 IDE는 다른 멋을 지니고 제공됩니다. 어떤 이클립스 패키지에서 필요한 툴들을 설치 할수 있다면, 일반적으로 플러그인 개발을 위한 모든 필요 툴을 포함하는 이클립스 표준 배포판을 다운로드 하는 것이 쉽습니다. 더 만은 툴을 포함한다른 패키지들은 플러그인 개발에 필요하지 않습니다.

이클립스 IDE 다운로드 사이트를 열고 이클립스 Committers패키지를 위한 이클립스 IDE를 다운로드 한다.  .

이클립스는 또한 Eclipse installer 인스톨러를 제공한다. 여러가지 멋을 지닌 이클립스를 다운로드 하기를 원하면, 이 인스톨러는 유용하다.  필요로 하는 공간을 줄인 상용 플러그인을 위한 공유된 설치 풀을 사용 한다. 

3. 싱행 환경구성

3.1. 실행 환경 구성이 무엇인가?

런타임 이클립스는 플러그인의 세트의 선택에 기반한다. 그 플러그인들은 런타임 환경 구성을 통해서 선택된다. 이 런타임 환경 구성은 다음처럼 정의 될수 있다:

  • 플러그인 또는 features 등의 세트

  • 실행환경을 생성하고 업데이트 하는데 사용되는 제품(product)

실행 환경구성은 일번적인 런처를 실행하는 것을 사용하게 될 환경구성을 정의한다. 예를 들면, Java 가상머신 (VM), 플러그인 (classpath) 종속성(dependencies), 등등 에 인수들을 정의 한다. .

테스트를 위한 런타임 이클립스 IDE를 시작하기를 원하면, 워크스페이스 위치를 깨끗하게 하면 다음 실행시 워크스페이스를 선택하기위한 메시지가 나타나게 될 것입니다. 

실행 환경 구성을 다시 보거나 편집하기 위해서는 이클립스 메뉴로 부터 Run  Run Configurations…​ 를 선택하라.

여기에서 Main 탭에 Location에서, 런타임 이클립스가 생성되기 위한 환경 구성 파일이 있는 곳을 지정한다.

3.2. 인수 정의하기

실행환경은 인수(Arguments) 탭에 어프리케이션의 추가적 시작 인수를 추가하는 것을 허용한다. 기본적으로, 이클립스는 이미 몇몇 인수들을 포함한다. 예를 들면, 어플리케이션을 실행하는 아키텍처를 지정하기 위해 -os, -ws 그리고 -arch 같은 파라미터이다.

이클립스 어플리케이션에 시스템 프로퍼티를 전달하기 위해, -D 스위치를 사용하여 런처 파라미터를 추가 할 수 있다. 예를 들면, 만약 -Dmy.product.loglevel=INFO 인수를 추가 한다면, System.getProperties("my.product.loglevel")에 값으로 "INFO" 를 설정할 수있다. .

다음 테이블에 유효한 런처 인수들을 목록화 한다. 

테이블 1. 런처 파라미터 

파라미터 상세설명      
consoleLog 어플리케이션이 시작된 RCP 어플리케이션이 보여줄 이클립스 IDE 콘솔에서 보여질수 있는 표준 출력(System.out)이 기록된다.
nl 어플리케이션을 위해 사용될 로케일을 지정한다. 그 로케일은 언어별 설정을 정의한다. 즉, 사용된 언어과 수, 날짜, 통화 형식이다. 예를 들면 영어를 사용하기 위해  -nl en 로 어플리케이션을 시작하다.  변환된 언어를 테스트하는데 유용하다. 
console 어플리케이션의 상태를 체크 할 수 있는 OSGi 콘솔에 접근하는 것을 제공한다. 
noExit
어플리케이션이 충돌하더라도 열린 OSGi 콘솔을 유지한다.  시작하는 동안 어플리케이션이 충돌 하더라도 어플리케이션을 분석하기 위해 허용한다. 
clearPersistedState 이클립스 4 어플리케이션 모델의 충돌된 런타임 변경을 삭제한다..

3.3. 런처 환경 구성과 이클립스 제품

만약 이클립스 RCP 어플리케이션을 개발 하는 중이라면, 제품 환경 구성 파일에 기반해서 런처 환경 구성을 생성한다. 런처 환경 구성이 제품을 통해 어플리케이션을 시작할때 매번 업데이트 된다. 

어플리케이션을 다시 시작하기 위해 직접 생성된 실행 환경 구성을 사용 한다. 제품에서 변경된 경우에 환경 구성 파일이 고려되지 않는다.

존재하는 실행 환경 구성을 사용하는 것은 방해의 소스와 에러 분석을 하는 시간이 일반적이다. 마지막 환경 구성을 사용하는 것을 보장하기 위해, 제품 파일을 통해서 어플리케이션을 시작한다. 

 

3.4. 일반적인 런처 문제를 위한 체크리스트

이클립스 RCP 어플리케이션의 실행 환경 구성에서 에러들은 문제의 원인이 된다. 이 장은 RCP 어플리케이션을 시작과 관련된 일반적인 문제들이 기술된다. 어플리케이션을 시작하는 동안 직면한 문제의 경우에 참조로 사용 될 수 있다. 

가장 일반적인 문제는 제품에서 필요한 플러그인들이 빠져 있는 것이다. 만약 제품 환경 구성에 기반이 되는 feature들를 사용한다면 MANIFEST.MF파일에서 참조될 모든 플러그인을 권장할 필요가 있고 또한 feature들에 포함된다. 이 오류는 콘솔 뷰에 보고되고, 전형적으로 첫번째 오류 메시지중에 하나이고 스크롤을 올려서 볼 필요가 있다. 

다음 목록은 전형적인 이 메시지를 어떻게 할것인지 다음과 같이 나열되어 있다. (텍스트에 맞게 서식 변경).

org.osgi.framework.BundleException: Could not resolve module: com.vogella.tasks.services [9] Unresolved requirement: Require-Bundle: com.vogella.tasks.events; bundle-version="1.0.0"

빠져있는 플러그인을 식별하고 제품에(만약 제품이 플러그인을 기본으로 하면) 또는 feature들(만약 제품이 feature을 기본으로 하면)에 추가 한다. 

이클립스는 런터 환경 구성을 실행사기 전에 자동으로 빠진 의존관계를 체크 할 수 있다. 플러그인(Plug-ins) 탭에서 Validate Plug-ins 버튼을 누르거나 옵션을 시작하기 전에 자동으로 플러그인들을 검증하는 것을 선택하라. 어플리케이션이 실행 될 때 필요한 프러그인들을 모두 가지고 있는지 체크하게 될 것이다. 

제품 환경 구성 파일에 기반하여 실행 환경이 생성되고 업데이트 되기 때문에 실행 환경에서 의존관계 문제를 수정하는 것을 피해야 한다. 그래서 항상 파생된 정보를 변경하는 대신에 제품 파일이 정확하게 환경 구성하는 것을 권장한다. 그 환경 구성은 제품의 내보내기를 사용되고, 그런 이유로 제품 의존관계에서 오류는 시작 될 수 없는 내보내기로 만들어진 어플리케이션에서 생긴다. 

다음 테이블 목록은 잠재적인 문제와 해결 방법을 나열한다. 

테이블 2. 실행 환경 구성 

문제점 문제점 해결방법    
기동 중에 "Could not resolve module" 메시지를 출력하는 경우.

프로젝트 환경구성에 모든 필수 플러그인들이 포홤 되어 있는지를 체크하라. product 에 모든 필수 플러그인 또는 feature에 의존관계를 정의하였는지 확인하라. 문제를 해결하는 방법을 이술하기 위한 이 섹션의 시작하기를 보라. 

번들은 특정 버전의 Java 가상머신을 필요로 할지 모른다. 즉, 번들이 Java 1.6 을 필요로 할지 모르고, 그러므로 Java 1.5 가상머신에서는 로드되지 않을 것이다. 실행환경(Execution Environments) 섹션에 (실행환경에 개요(Overview) 탭에 MANIFEST.MF 파일에서 필요로 하는 자바 버전을 체크하라.

기동 중에 "java.lang.RuntimeException: No application id has been found." 메시지를 출력하는 경우. 기동 중에 "Could not resolve module" 메시지 오류를 본다. 대부분의 경우에 역시 플러그인이 의존관계를 빠뜨림으로써 발생된다.
오류 메시지는 없지만 이상하게 동작하는 경우. -consoleLog 파라미터를 포함한 환경 구성이 실행되는지 체크라라. 이 옵션은 이클립스 IDE의 콘솔 뷰에 이클립스 기반 어플리케이션으로 부터 에러를 보는 것을 허용한다. 
실행 환경 구성이 자주 필요한 플러그인을 빠뜨리는 경우. product 또는 feature가 모든 필요 의존관계를 포함하는지 확인하라. 
실행 환경에서 product 의존관계 탭에서 변경이 반영이 안된다.(즉, 새 플러그인이 추가 되었지만 실행 환경에서는 추가 되지 않는다.) 만약 product 정의 파일로 부터 직접 product를 시작한다면 product는 존재 하는 실행 환경을 업데이트 한다. 직접 실행 환경을 선택하면, 업데이트 되지 않을 것이다.
이클립스 4 어플리케이션에서 어플리케이션 모델 변경이 반영이 안된다.  어플리케이션내의 시작 시 재저장된 델타 파일에서 이클립스 4 persists 사용자를 변경한다.  개발 하는 동안 런타임 모델에 모델 변경이 정확하게 적용되지 않는 상황으로 이어 질 수있다. 즉, 새 메뉴 엔트리를 정의 하고 그 엔트리가 어플리케이션에 표시되지 않는다. 실행환경의 Main 탭에서 Clear 플래그를 설정하거나 product 환경 구성 파일 또는 실행 환경 구성 파일에 clearPersistedState 파라미터를 추가한다.
서비스, 즉, 키 바인딩 또는 선택 서비스가 이클립스 4 어플리케이션에서 동작하지 않는다. 4.3 이전 릴리즈 된 이클립스에서 모든 파트에서 SWT 컨트롤에 포커스를 놓기 위해서 @Focus 메서드를 구현할 필요가 있다. 이 에러는 이클립스 4.3 또는 더 높은 릴리즈 버전에서는 더 이상 발생하지 않는다. 
이클립스 어플리케이션에서 메뉴 엔트리가 비활성화 되어 있다. 모델 에드온(부가기능)으로 등록된 org.eclipse.e4.ui.internal.workbench.addons 패키지에서 HandlerProcessingAddon 클래스를 확인한다. 번들 심볼릭 명이 org.eclipse.e4.ui.workbench 이다.
"org.eclipse.ant.core.antRunner" 어플리케이션을 레지스터리에서 찾을 수 없거나 어플리케이션을 레지스터리에서 찾을수 없을때 product 환경 구성 파일에서 New…​ 버튼을 눌렀는지 시작 할 어플리케이션으로 E4Application 을 선택했는지 확인하라. org.eclipse.core.runtime.products 확장(extension)의 상세에서 확장(Extentions) 탭에 plugin.xml 파일에 현재 설정을 체크 하라.
기동 또는 검증할 때 " Unresolved requirement: Require-Capability: osgi.extender; filter:='(&(osgi.extender=osgi.component)(version>=1.2)(!(version>=2.0)))' " 메시지 org.apache.felix.src을 product에 의존관계에 추가하라. 검증(Validate ) 버튼으로 product 의 일관성을 체크하라
기동할 때 "Event Admin service is not available, unable to publish event org.osgi.service.event.Event" 메시지 org.eclipse.equinox.even를 product에 의존관계에 추가하라. 검증(Validate ) 버튼으로 product 의 일관성을 체크하라.

4. 연습: 첫번째 플러그인을 생성하고 사용하기

이 연습에서, 마법사를 사용하여 IDE에 확장(extension)을 생성한다. 

4.1. 새 플러그인 프로젝트를 생성한다.

새 플러그인을 생성하기 위해 File > New > Other > Plug-in Development > Plug-in Project 를 선택한다.

프로젝트 이름에 com.vogella.ide.first 를 입력한다..

Next 버튼을 누른다. 다음 페이지에서 아래 스크린샷에 입력된 값을 등록한다. Next 버튼을 누른다.

다음 페이지에서 템플릿 체크박스 중에 하나를 사용하여 플러그인을 생성한다. 4.x API 템플릿을 사용하는 컨트리뷰션 뷰(View contribution using 4.x API )를 선택한다. .

그 후에, Next 버튼 또는 Finish 버튼을 누른다.

만약 Next, 버튼을 눌렀다면 다음과 같이 입력하고, 반면 Finish를 눌렀다면 다음 페이지는 보여지지 않는다.

이 마법사는 선택된 템플릿을 사용하여 새 플러그인을 바로 생성한다. 생성된 파일들을 보기 위해서 프로젝트 탐색기(Project Explorer)를 사용한다.

4.2. 새 플러그인으로 런타임 이클립스 시작하기 

이제 생성된 플러그인으로 런타임 이클립스를 시작해 보자.

현재 IDE의 그 새 플러그인과 모든 대상으로 부터 모든 플러그인으로 런타임 이클립스를 시작한다. 그러기 해 , 그 플러그인 프로젝트에서 오른쪽 마우스를 클릭해서 Run As  Eclipse Application.을 선택한다.

새 예제 뷰를 포함하는 런타임 이클립스를 시작한다..

4.3. 결과 검증

런타임 IDE에 메쥬에서 Window > Show View > Others…​ 를 통해서 샘플 뷰(Sample View) 뷰를 열수 있어야 한다.

5. 사용자 정의 IDE를 정의하기 위해 features 와 products 사용하기

이 예제에서 런타임 이클립스에서 선택된 플러그인들을 환경 구성하고 선택하기 위한 features 와 products를 생성하는 방법을 배우게 된다. 

5.1. 생성하기

File > New > Other…​ > Plug-in Development > Feature Project를 사용해서 com.vogella.ide.feature로 불리는 새 feature 프로젝트를 생성한다. 

마법사의 두번째 페이지에서, feature에 추가하기를 원하는 플러그인을 선택한다. 

그 뒤에 Finish 버튼을 누른다.

5.2. feature 내용 검증하기

feature.xml 파일을 열고 이 에디터에서 포함된 플러그인들(Included Plug-ins) 탭을 선택하고 작업 공간에서 원하는 플러그인들이 이 feature에 포함 되어 있는 것을 확인해라.

그 feature에 플러그인들을 포함시키기 위해 포함된 플러그인(Included Plug-ins) 탭에 플러그인들 추가 되었는지를 확인한다. 이 예시에서 의존관계(Dependencies) 탭을 사용하는 것은 잘못이다. 

5.3. 제품 환경 구성 파일을 포함할 프로젝트 생성하기

File > New > Other…​ > General  Project. 를 사용해서 com.vogella.ide.product 이름으로 새 프로젝트를 생성한다.

프로젝트 이름을 생성한다.

Finish.버튼을 누른다.

5.4. 환경 구성 파일 생성하기

위에서 생성한 프로젝트에서 오른쪽 마우스를 클릭하고 File > New > Other…​ > Plug-in Development > Product Configuration를 선택한다.

com.vogella.ide.productproject 폴더 내부에 ide.product 이름의 product 환경 구성 파일을 생성한다. .

Finish 버튼을 누른다..

새 product 파일이 생성되고 에디터에서 열리게 된다.

5.5. product 환경 구성하기

새 파일을 위한 product 에디터가 열려 있는지 확인하라. product 에디터의 개요(Overview) New…​ 버튼을 누른다.

플러그인 정의 하기(Defining Plug-in)에 com.vogella.ide.first 을 입력한다. 어플리케이션(application)에 org.eclipse.ui.ide.workbench를 사용한다. 다음 스크린샷과 유사하게 이름과 ID를 넣는다.

5.6. 버전 번호를 입력한다. 

product에 버전 1.0.0을 입력한다. 

5.7. features를 포함하는 것으로 입력한다.

product는 features에 기반으로 해야 한다. 이를 위해 개요(Overview) 탭에서 features 옵션을 선택한다.

내용(Contents) 탭을 선택하고 Add…​ 버튼을 통해 다음 features를 추가한다..

  • com.vogella.ide.feature

  • org.eclipse.platform

다음으로 Add Required 버튼을 누른다..

Ctrl + S를 눌러 ide.product 파일을 저장한다.

만약 product에 리스트된 features 중에 하나를 추가 할 수 없다면, product 환경 구성이 features에 기반하는 것을 보장한다.

5.8. 런타임 이클립스를 시작으로 설정을 검증하기

product 파일을 선택하고 Run 버튼을 통해서 이클립스 IDE를 시작한다. .

결과로 런타임 이클립스 IDE가 시작되여야 한다. product에 추가 되여야 하는 그 feature들만을 포함해야 한다. 예를 들면, 현재는 새 Java 프로젝트를 생성할 수 없어야 한다.

5.9. 개발중인 IDE에 Java 툴을 추가 하기

대상 플랫폼에 org.eclipse.jdt.feature.group 을 추가한다. 대상 플랫폼은 다음 목록에 유사하게 해야 한다. 

역자주) 해당 투토리얼에서 Target Profile 파일을 생성 하지 않아서 내용(Contents) 탭에서 Add… 버튼으로 추가 후 테스트 했으며, 별도의 Tartget Profile XML 파일을 생성 후 아래 내용을 입력하거나  File > New > Other…​ > Plug-in Development >  Target Definition으로  생성 후 편집할 수 있다.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
<target name="target-platform">
  <locations>
    <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
      <repository location="http://download.eclipse.org/releases/latest"/>
      <unit id="org.eclipse.equinox.sdk.feature.group" version="0.0.0"/>
      <unit id="org.eclipse.platform.sdk" version="0.0.0"/>
      <unit id="org.eclipse.jdt.feature.group" version="0.0.0"/>
    </location>
  </locations>
</target>

그 다음에, product에 org.eclipse.jdt feature을 추가하고, product 런타임 IDE를 시작한다. 이제 Java 툴이 설치되었다. 예로들면, 새 마법사를 통해 Java 프로젝트를 생성 할수 있는지를 체크 하라.

6. 연습: 3.x 기반 어플리케이션에 e4 part descriptors 추가 하기

이 연습으로 이클립스 3.x RCP 어플리케이션에 모델 기반 파트 컨트리뷰션을 추가 할 수 있다..

6.1. 파트 디스크립터(part descriptor) 추가하기

com.vogella.plugin.partdescriptor 이름으로 간단한 플러그인을 생성한다.

manifest 파일에 다음 의존 관계를 추가한다..

  • org.eclipse.core.runtime,

  • org.eclipse.jface,

  • org.eclipse.e4.ui.model.workbench,

  • org.eclipse.e4.ui.di

다음 클래스를 생성한다.

package com.vogella.ide.ui; 

import javax.annotation.PostConstruct; 
import org.eclipse.e4.ui.di.Focus; 
import org.eclipse.jface.viewers.ArrayContentProvider; 
import org.eclipse.jface.viewers.LabelProvider; 
import org.eclipse.jface.viewers.TableViewer; 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.widgets.Composite; 

public class PartEclipse4x { 
  private TableViewer viewer; 
  
  @PostConstruct 
  public void createPartControl(Composite parent) { 
    viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); 
    viewer.setContentProvider(ArrayContentProvider.getInstance()); 
    viewer.setLabelProvider(new LabelProvider()); 
    viewer.setInput(new String[] {"One", "Two", "Three"}); 
  } 
  
  @Focus public void setFocus() { 
    viewer.getControl().setFocus(); 
  }
}

File > New > Other…​ > Eclipse 4 > Model > New Model Fragment를 사용하여 이 플러그인에 새 모델 fragment 를 추가한다. 

6.2. 검증

이클립스 IDE 인스턴스를 시작하고 빠른 접근 박스(단축키 CTRL+3)를 사용하여 파트를 열수 있는지를 검증한다. .

Window > Show View 메뉴 입장을 통해 이 파트를 열수 있다. 

7. 3.x API로 부터 IEclipseContext에 접근하기

이클립스 IDE IDE에 대해서 중앙 정보를 저장하기 위해 IEclipseContext 데이타 스트럭처를 사용한다. 이클립스 3.x API 를 통해서 또한 이 정보에 접근 할수 있다. .

예를 들면, 이클립스 3.x API 뷰로 부터 내용에 접근하게 하기 위해, 다음 소스 일부를 사용한다. 

// part의 내용 취득
IEclipseContext partContext = getViewSite().getService(IEclipseContext.class); 

// 그 키를 기반으로 내용에서 직접 값에 접근
EModelService service = getViewSite().getService(EModelService.class);

이 소스 일부는 이클립스 3.x API 핸들러를 통한 접근을 보여준다.

// 다음 핸들러가 있다는 것을 가정한다.  
// 활성화 윈도우로 부터 내용 취득
IEclipseContext windowCtx = HandlerUtil.getActiveWorkbenchWindow(event).getService(IEclipseContext.class); 

// 활성화 된 영역으로 부터 내용 취득
IEclipseContext ctx = HandlerUtil.getActivePart(event).getSite().getService(IEclipseContext.class);

8. 이클립스 IDE 또는 3.x RCP 어플리케이션에 모델 엘리먼트 기여하기

8.1. org.eclipse.ui.views 확장포인트(extension point)를 사용해서 Adding 이클립스 3.x 어플리케이션에 이클립스 4.x 파트 추가 하기.

org.eclipse.ui.views 확장점(extension point)를 확장 extension (탭, 테그)에서 e4 파트를 사용 할 수 있다. 이를 보관하기 위해 extension의 내용 메누에 e4view 엔트리를 사용한다. 그 결과 객체는 의존관계 주입(dependency injection)을 통해서 생성된다. 

기존 툴바 뷰 와 뷰 확장점의 경우에 컨트리뷰션이 동작하지 않는다. 예로 e4view에 툴바를 추가하기 위해, 구현체를 삽입할 MToolbar를 얻고 소스코드에 엔트리를 구성한다.

8.2. e4 메뉴 엔트리들 추가하기

메뉴(Menus), 핸들러(handlers) 그리고 커멘드(commands) 모델 fragments을 통해서 이클립스 어플리케이션에 기여(제공)될 수 있다.

역자주) 어플리케이션에 기여한다는 의미는 이클립스 어플리케이션으로 별도의 기능으로 삽입되어 기능등이 개선 또는 추가 될 수 있는 것을 의미 한다. 즉, 기존 이클립스에 일부로 개발되어 포함 제공 될 수 있다는 의미이다

기여하기를 원하는 엘리먼트의 ID를 지정하기 위해 e4 tools로 부터 모델 spy를 사용할 수있다.

일치하는 ID로 상응하는 어플리케이션 모델 엘리먼트에 기여하는 모델 fragment를 생성 할 수 있다. 다음 스크린샷은 이클립스 IDE의 menuContributions feature에 기여(제공)하는 방법을 보여준다. 

메뉴를 기여(제공)할 수 있는 MenuContribution 항목을 추가 한 후에 . 그 부모-ID는 메뉴가 기여(제공)될 메뉴의 ID 여야 한다.

모델 fragment는 org.eclipse.e4.workbench.model 확장점(extension poin)을 통해서 다음 목록에서 표시되는 것처럼 plugin.xml 파일에 등록되어 있어야 한다.

<?xml version="1.0" encoding="utf-8"?>
<plugin>
  <extension id="id1" point="org.eclipse.e4.workbench.model">
    <fragment apply="notexists" uri="fragment.e4xmi"> </fragment>
  </extension>
</plugin>

8.3. 오류 분석

문제가 발생했을 경우에, plugin.xml의 소스 코드를 확인하고 모델 fragment가 포함 되었는지를 검증하라. 참조된 모델 fragment의 이름을 검증하고, 모든 정의된 ID가 실행중인 환경 구성에서 사용가능한지를 확인하라.

8.4. 어플리케이션 윈도우에 e4 툴바 엔트리 추가하기

툴바 컨트리뷰션을 기여할 메뉴와 유사하다. 

이 접근은 현재 뷰 툴바를 위해서 동작하지 않는다. 

8.5. 이클립스 IDE 에 파트 디스크립터를 지원하기

이클립스 IDE는 fragments와 프로세서를 통해 파트 디스크립터 모델의 기여를 지원한다. 

만약 파트 디스크립터를 기여하기 위해 the org.eclipse.e4.legacy.ide.application ID를 사용한다면, Window > Show View > Other…​ 다이얼로그 또는 바로가기를 통해서 뷰가 오픈 될 수 있다.  파트 디스크립터같은 뷰 테그를 필요로 한다. 

4.5 또는 더 높은 런타임에서 실행되는 이클립스 3.x API RCP 어플리케이션 같은 접근을 사용할 수 있다. 

8.6. 모델 snippet을 통해서 이클립스 IDE에 퍼스펙티브 추가하기

모델 fragment 또는 processor는 snippet을 통해 포스펙티브를 추가 기 위해 이클립스 4.x IDE에 퍼스펙티브를 기여 할 수 있다. 이 확장 엘리먼트 id는 xpath:/ 로 일반화 둘수 있고 feature 명이 snippets 이다.

이 접근은 이클립스 4.x 런타임에 실행하는 RCP 어플리케이션 기반 이클립스 3.x API에 퍼스펙티브를 기여하는데 사용 될 수 있다. .

9. 연습: 이클립스 IDE에 새 퍼스펙티브 추가하기

I이 연습에서, 이클립스 IDE에 새 퍼스펙티브를 기여(제공)한다..

9.1. 모델 엘리먼트를 생성하기

com.vogella.contribute.parts 플러그인에서, 다음 모델 fragment를 생성한다..

퍼스펙티브에 적어도 하나의 파트를 추가한다. 

9.2. 검증

이클립스 IDE를 시작하고 퍼스펙티브 스위쳐 다이얼로그를 통해서 새 퍼스펙티브를 열수 있는지를 검증한다. 

10. 추가 연습: 확장점(extension points) 통해서 POJO 뷰 추가 하기 

이 연습에서, org.eclipse.ui.views 확장점(extension point)의 e4view 엘리먼트를 사용하기 대문에 별도의 플러그인을 통해 e4 기반 뷰 확장을 생성한다.

이 확장(extension) 이클립스 IDE에 기여(제공)될 수 있다. (또는 다른 이클립스  3.x API 기반 RCP 어플리케이션).

10.1. 플러그인 생성하기

com.vogella.ide.e4view 이름의 플러그인을 생성한다.  File > New > Other…​ > Plug-in Project을 사용한다.

com.vogella.ide.e4view 프로젝트를 호출하고 다음 스크린샷에 유사하게 옵션을 선택한다. 

10.2. 플러그인 의존관계 조정하기

새 플러그인의 manifest 파일에 의존관계로 org.eclipse.e4.ui.di 를 추가 하라.

10.3. e4 뷰 생성하기

 다음 생성된 SampleE4View를 조정하라.

package com.vogella.ide.e4view.views; 

import javax.annotation.PostConstruct; 
import javax.inject.Inject; 
import org.eclipse.e4.ui.di.Focus; 
import org.eclipse.jface.action.Action; 
import org.eclipse.jface.action.IMenuListener; 
import org.eclipse.jface.action.IMenuManager; 
import org.eclipse.jface.action.MenuManager; 
import org.eclipse.jface.action.Separator; 
import org.eclipse.jface.dialogs.MessageDialog; 
import org.eclipse.jface.viewers.ArrayContentProvider; 
import org.eclipse.jface.viewers.DoubleClickEvent; 
import org.eclipse.jface.viewers.IDoubleClickListener; 
import org.eclipse.jface.viewers.IStructuredSelection; 
import org.eclipse.jface.viewers.ITableLabelProvider; 
import org.eclipse.jface.viewers.LabelProvider; 
import org.eclipse.jface.viewers.TableViewer; 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.graphics.Image; 
import org.eclipse.swt.widgets.Composite; 
import org.eclipse.swt.widgets.Menu; 
import org.eclipse.ui.ISharedImages; 
import org.eclipse.ui.IWorkbench; 
import org.eclipse.ui.IWorkbenchActionConstants; 

public class SampleE4View { 
	/**
     * 확장에 의해 지정된 뷰의 ID. 
     */ 
    public static final String ID = "com.vogella.ide.e4view.views.SampleE4View"; 
    
    @Inject IWorkbench workbench; 
    
    private TableViewer viewer; 
    
    private Action action1; 
    
    private Action action2; 
    
    private Action doubleClickAction; 
    
    class ViewLabelProvider extends LabelProvider implements ITableLabelProvider { 
    	
        @Override 
        public String getColumnText(Object obj, int index) { 
        	return getText(obj); 
        } 
        
        @Override 
        public Image getColumnImage(Object obj, int index) { 
        	return getImage(obj); 
        } 
        
        @Override 
        public Image getImage(Object obj) { 
        	return workbench.getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT); 
        } 
    } 
    
    @PostConstruct 
    public void createPartControl(Composite parent) { 
    	viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); 
        viewer.setContentProvider(ArrayContentProvider.getInstance()); 
        viewer.setInput(new String[] { "One", "Two", "Three" }); 
        viewer.setLabelProvider(new ViewLabelProvider()); 
        
        // 뷰의 컨트롤을 위한 헬프 컨텍스트 ID를 생성한다. 
        workbench.getHelpSystem().setHelp(viewer.getControl(), "com.vogella.ide.e4view.viewer"); 
        makeActions(); 
        hookContextMenu(); 
        hookDoubleClickAction(); 
    } 
    
    private void hookContextMenu() { 
    	MenuManager menuMgr = new MenuManager("#PopupMenu"); 
        menuMgr.setRemoveAllWhenShown(true); 
        menuMgr.addMenuListener(new IMenuListener() { 
        	
            @Override 
            public void menuAboutToShow(IMenuManager manager) { 
            	SampleE4View.this.fillContextMenu(manager); 
            }
            
       	}); 
        Menu menu = menuMgr.createContextMenu(viewer.getControl()); 
        viewer.getControl().setMenu(menu); 
    } 
    
    private void fillContextMenu(IMenuManager manager) { 
    	manager.add(action1); 
        manager.add(action2); 
        // 다른 플러그인이 여기에 액션을 기여(제공) 할 수 있다.
        // (역자주, 내부에 생성된 action1, action2 이외에 기존 다른 플러그인 액션을 사용 할 수 있다)
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); 
    } 
    
    private void makeActions() { 
    	action1 = new Action() { 
        	@Override 
            public void run() { 
            	showMessage("Action 1 executed"); 
            } 
         }; 
         
         action1.setText("Action 1"); 
         action1.setToolTipText("Action 1 tooltip"); 
         action1.setImageDescriptor(workbench.getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK)); 
         
         action2 = new Action() { 
         	@Override 
            public void run() { 
            	showMessage("Action 2 executed"); 
            } 
         }; 
         
         action2.setText("Action 2"); 
         action2.setToolTipText("Action 2 tooltip"); 
         action2.setImageDescriptor(workbench.getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK)); 
         
         doubleClickAction = new Action() { 
         	@Override 
            public void run() { 
            	IStructuredSelection selection = viewer.getStructuredSelection(); 
                Object obj = selection.getFirstElement(); 
                showMessage("Double-click detected on " + obj.toString()); 
            } 
         }; 
         
    } 
    
    private void hookDoubleClickAction() { 
    	viewer.addDoubleClickListener(new IDoubleClickListener() { 
        	@Override 
            public void doubleClick(DoubleClickEvent event) { 
            	doubleClickAction.run(); 
            } 
        });
    } 
    
    private void showMessage(String message) { 
    	MessageDialog.openInformation(viewer.getControl().getShell(), "e4view View", message); 
    } 
    
    @Focus 
    public void setFocus() { 
    	viewer.getControl().setFocus(); 
    } 
}

만약 바로 플러그인을 시작하고 뷰를 연다면, com.vogella.ide.e4view.views.SampleE4View를 org.eclipse.ui.IViewPart로 캐스팅 할 수 없다는 에러 메시지를 받을 것이다. 정확하게 조정된 클래스를 사용하기 위해서 다음단계를 필요로 한다. 

10.4. 확장점(extension point)에서 엔트리 조정하기

org.eclipse.ui.views 확장점(extension point)을 위해 e4view 속성으로 뷰 속성을 교체한다..

plugin.xml 에디터의 확장(Extensions)탭을 사용하라

이미지 문구 번역) view 엔트리를 삭제 하고 새 엘리먼트로 e4view를 추가 한다.

plugin.xml 파일에서 org.eclipse.ui.views 확장을 위한 마지막 관련 소스는 다음과 유사하게 보여야 한다.:

<?xml version="1.0" encoding="UTF-8"?> 
<?eclipse version="3.4"?> 
<plugin> 
   	<extension point="org.eclipse.ui.views"> 
       	<category name="Sample Category" id="com.vogella.ide.e4view"> 
        </category> 
        <e4view category="com.vogella.ide.e4view" 
           		class="com.vogella.ide.e4view.views.SampleE4View" 
                icon="icons/sample.png" 
                id="com.vogella.ide.e4view.e4view1" 
                name="e4view View" restorable="true"> 
        </e4view> 
	</extension> 
        
    <!-- MORE ENTRIES, LEFT OUT FOR BREVITY --> 
</plugin>

10.5. Validate the usage of the e4 뷰의 사용 검증하기

이클립 IDE에서 플러그인을 시작하라 그리고Windows > Show View 메뉴 엔트리를 통해서 뷰를 열수 있는지를 검증하라. 이 뮤는 다음과 유사하게 보일 것이가 항목들상에 컨텍스트 메뉴가 제공되어야 한다. 

모델 지속성 데이타를 보는 것을 피하기 위해, 런타임 환경 구성에 -clearPersistedState 플래그 설정해서 추가한다.

10.6. 퍼스펙티브 확장에 뷰를 추가 하기

퍼스펙트브에 뷰를 추가 하기 위해, 다음 스크린샷에서 표시되는 것처럼 존재하는 org.eclipse.ui.perspectiveExtensions 엔트리를 조정한다. 

이미지 문구 번역) 새 뷰 ID를 사용한다. (com.vogella.ide.e4view.e4view1) 

10.7. 추가 연습: e4 뷰에 툴바 추가하기

현재 확장점(extension point) 처리는 일반 뷰 확장을 제외하고 e4view 확장이 아니다. e4view 에 툴바를 추가 하기 위해, 스스로 관련 정보를 처리 해야 한다. 예를 들면, 주입된 EModelService를 얻을 수 있고,  확장 레지스터 또는 모델 snippet에 기반으로 툴바를 추가한다. 시연의 목적으로 다음처럼 하나의 툴바 엔트리를 간단하게 생성한다.

@PostConstruct 
public void createPartControl(Composite parent, MPart part, EModelService modelService) { 
	viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); 
    viewer.setUseHashlookup(true); 
    
    // 데이타 모델의 빠른 해시 참조를 사용한다. 
    viewer.setContentProvider(ArrayContentProvider.getInstance()); 
    viewer.setInput(new String[] { "One", "Two", "Three" }); 
    viewer.setLabelProvider(new ViewLabelProvider()); 
    
    // 뷰어의 컨트를을 위한 도움말 컨텍스트 ID를 생성한다. 
    workbench.getHelpSystem().setHelp(viewer.getControl(), "com.vogella.ide.e4view.viewer"); 
    makeActions(); 
    hookContextMenu(); 
    hookDoubleClickAction(); 
    
    MToolBar toolbar = modelService.createModelElement(MToolBar.class); 
    MHandledToolItem toolitem = modelService.createModelElement(MHandledToolItem.class); 
    toolitem.setLabel("View Tool Item"); 
    
    // TODO 툴바 아이템을 위한 관련 아이콘과 커멘트를 설정한다. 
    toolbar.getChildren().add(toolitem); part.setToolbar(toolbar); 
}

11. 연습: 이클립 IDE에 e4 메뉴 추가하기

이 연습에서 com.vogella.tasks.ui 플러그인을 통해 IDE에 메뉴와 툴바 컨트리뷰션을 추가 하게 될 것이다..

11.1. 플러그인 의존관계 추가하기

com.vogella.tasks.ui의 manifest 파일에 다음 의존관계가 있는지 확인하라..

  • org.eclipse.e4.core.di,

  • org.eclipse.jface

11.2. 핸들러 클래스 생성하기

생성된 핸들러 클래스에 기반해서 다음 클래스를 생성한다.

package com.vogella.tasks.ui.handlers; 

import org.eclipse.e4.core.di.annotations.Execute; 
import org.eclipse.jface.dialogs.MessageDialog; 
import org.eclipse.swt.widgets.Shell; 

public class TestHandler { 
	
    @Execute 
    public void execute(Shell shell) { 
    	MessageDialog.openInformation(shell, "First", "Hello, e4 API world"); 
    } 
}

11.3. 컨트리뷰션을 위한 모델 fragment를 생성한다.

플러그인 프로넥트의 컨텍스트 메뉴로 부터 New > Other…​ > Eclipse 4  Model > New Model Fragment 를 통해 새 모델 fragment를 생성한다.

이 파일 명은 commands.e4xmi을 입력한다.

Finish 버튼을 누른다..

새 fragment가 plugin.xml에 확장으로 정확하게 등록되었다는 것을 확인 하라.

11.4. 커멘트 컨트리뷰션을 정의하라

xpath:/ 엘리먼트 ID를 사용하여 최상위 레벨 엘리먼트의 커멘트에 커멘트들 기여(제공)하기 위한 모델 fragment 를 생성한다. 

새 컨트리뷰션을 정의 학 ㅣ위해 다음 스크린샷을 사용한다.

persistState 플래그를 false로 설정하는 것을 확인하라. 만약 플러그인이 설치 되지 않았다면 그 엘리먼트가 가능하지 않다.

11.5. 핸들러 컨트리뷰션 정의하기

정의된 커멘트로 핸들러를 추가 하고, 이행으로 TestHandler를 사용한다. 

persistState 플래그를 false로 설정하는 것을 확인하라. 만약 플러그인이 설치 되지 않았다면 그 엘리먼트가 가능하지 않다.

11.6. menuContributions 컨트리뷰션을 정의하기

persistState 플래그를 false로 설정하는 것을 확인하라. 만약 플러그인이 설치 되지 않았다면 그 엘리먼트가 가능하지 않다.

메뉴에 적어도 하나의 메뉴를 추가하고 반면 표시되지는 않을 것이다. 

11.7. 메뉴의 존재 검증하기

이클립스 IDE의 새 인스턴스를 시작하고 메뉴가 보이고 동작하는지를 검증한다. 만약 보이지 않는다면, 잠재적 이슈를 위한 모델 스파이를 통해서 체크하라 

12. 연습: 이클립스 IDE에 트림바(trimbar )를 추가 하기

12.1. trimbar 컨트리뷰션 추가하기

또한 같은 커멘트를 위한 trimbar 컨트리뷰션을 추가 할 수 있다.

persistState 플래그를 false로 설정하는 것을 확인하라. 만약 플러그인이 설치 되지 않았다면 그 엘리먼트가 가능하지 않다.

trimbar를 툴바에 추가하기

컨트리뷰션에 처리된 툴 항목을 추가한다.

12.2. 툴바 컨트리뷰션의 존재를 검증하기 

이클립스 IDE의 새 인스턴스를 시작하고, 새 툴바가 가능한지를 검증한다. 만약 윈도우에 보이지 않는다면, 잠재적이슈를 위해서 모델 spy를 통해서 체크한다.

13. 추가 연습: 툴바 엔트리에 아이콘 추가하기

아이콘 폴더를 생성한다.  새 프로젝트에 아이콘을 저장하기 위해 플러그인 이미지 브라우져(Plug-in Image Browser)를 사용한다.

툴바 엔트리에 이 아이콘을 할당한다. 

14. 리소스와 마커

이클립스는 IResource로 프로젝트, 파일, 폴더, 패키지 같은 리소스를 나타낸다. 

마커(Marker)는 추가적으로 리소스를 위한 정보를 나타낸다. 즉, 에러 마커이다. 이 정보는 리소스(파일) 내 저장이 아니라 워크스페이스 메타데이타에 추가 정보로 저장된다. 

모든 마커는 속성을 가질 수 있다. (key / value 조합). 마커는 표준 뷰에서 표시 될 수 있다. 즉, 테스크(Task), 북마크(Bookmark) 또는 문제점 (Problems) 뷰이다. 그 뷰에서 표시되게 되기 위해, 사전에 정의된 속성을 사용해야 한다.

15. 연습: 리소스를 위한 마커를 생성하기

e4 핸들러 템플릿에 기반한 com.vogella.plugin.markers 플러그인 프로젝트를 생성한다.

이 템플릿은 선택된 리소스 위한 IMarker를 생성하기 위해 사용되어야 하는 AddMarkerHandler 핸들러를 생성하게 될 것이다.

다음 의존 관례를 추가 한다.:

  • org.eclipse.jface

  • org.eclipse.e4.ui.services

  • org.eclipse.e4.core.di.annotations

  • org.eclipse.core.resources

  • org.eclipse.core.runtime

  • org.eclipse.e4.core.services

다음에 AddMarkerHandler 코르를 변경한다.:

package de.vogella.plugin.markers.handler; 

import javax.inject.Named; 
import org.eclipse.core.resources.IMarker; 
import org.eclipse.core.resources.IResource; 
import org.eclipse.e4.core.di.annotations.Execute; 
import org.eclipse.e4.core.services.adapter.Adapter; 
import org.eclipse.e4.ui.services.IServiceConstants; 
import org.eclipse.jface.viewers.IStructuredSelection; 

public class AddMarkerHandler { 
	
    @Execute 
    public void execute(@Named(IServiceConstants.ACTIVE_SELECTION) IStructuredSelection selection, Adapter adapter) { 
    	if (selection == null || selection.isEmpty()) { 
        	return; 
        } 
        
        Object firstElement = selection.getFirstElement(); 
        IResource resource = adapter.adapt(firstElement, IResource.class); 
        
        if (resource != null) { 
        	writeMarkers(resource); 
        } 
	} 
   
	private void writeMarkers(IResource resource) { 
    	try { 
        	IMarker marker = resource.createMarker(IMarker.TASK); 
            marker.setAttribute(IMarker.MESSAGE, "This is a task"); 
            marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); 
        } catch (Exception e) { 
        	e.printStackTrace(); 
        } 
    }
}

fragment.e4xmi 파일에 커멘트의 명이 "Hello World" 에서 "Add Task Marker"로 변경되어야 한다.

만약 실행하고 Java 프로젝트나 다른 IResource를 선택하면 메뉴 엔트리를 클릭한다면 테스트 뷰(Tasks View) 에서 마커를 생성할 수 있다. 

16. 어댑터(Adaptors)

어댑터는 존재하는 뷰를 조정해야 하는 것 없이 이 뷰에서 객체에 대한 정보를 표시하는 것을 돕는다. 

어댑터는 몇몇 장소에서 사용된다. 예를 들면, 아웃라인 뷰에서 데이타가 표시하기 위해 사용 될 수 있다. 예제로 FAQ 언어 에디터를 위한 아웃라인 뷰를 어떻게 생성하는가 를 보라.

17. 연습- 프로퍼티 뷰를 위한 어댑터(Adaptors)

프로퍼티 뷰에 데이타를 보여주기 위해 간단하게 어댑터를 사용하게 될 것이다. 

de.vogella.plugin.adapter 이름의 새 플러그인 프로젝트를 생성한다..

MANIFEST.MF 파일의 의존관계(dependencies) 탭에 다음 의존 관계를 추가한다.:

  • org.eclipse.core.runtime

  • org.eclipse.e4.ui.model.workbench

  • org.eclipse.e4.ui.services

  • org.eclipse.e4.ui.workbench

  • org.eclipse.ui

  • org.eclipse.ui.views

데이타 모델로 다음 Todo 클래스를 생성한다.

package de.vogella.plugin.adapter.model; 

public class Todo { 
	
    private String summary; 
    private String description; 
    private boolean done; 
    
    public String getSummary() { 
    	return summary; 
    } 
    
    public void setSummary(String summary) { 
    	this.summary = summary; 
    } 
    
    public String getDescription() { 
    	return description; 
    } 
    
    public void setDescription(String description) { 
    	this.description = description; 
    } 
    
    public boolean isDone() { 
    	return done; 
    } 
    
    public void setDone(boolean done) { 
    	this.done = done; 
    } 
}

모델 fragment (fragment.e4xmi)를 생성하고 샘플뷰로 불리는 PartDescriptor를 추가한다.

PartDescriptor 구현체를 위한 파트로서 SampleView.java를 생성한다.

package de.vogella.plugin.adapter.views; 

import java.util.ArrayList; 
import java.util.List; 
import javax.annotation.PostConstruct; 
import org.eclipse.e4.ui.workbench.modeling.ESelectionService; 
import org.eclipse.jface.viewers.ArrayContentProvider; 
import org.eclipse.jface.viewers.ISelectionChangedListener; 
import org.eclipse.jface.viewers.ITableLabelProvider; 
import org.eclipse.jface.viewers.LabelProvider; 
import org.eclipse.jface.viewers.SelectionChangedEvent; 
import org.eclipse.jface.viewers.TableViewer; 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.graphics.Image; 
import org.eclipse.swt.widgets.Composite; 
import org.eclipse.ui.ISharedImages; 
import org.eclipse.ui.PlatformUI; 
import de.vogella.plugin.adapter.model.Todo; 

public class SampleView { 
	
    private TableViewer viewer; 
    
    class ViewLabelProvider extends LabelProvider implements ITableLabelProvider { 
    	
        public String getColumnText(Object obj, int index) { 
        	Todo todo = (Todo) obj; 
            return todo.getSummary(); 
        } 
        
        public Image getColumnImage(Object obj, int index) { 
        	return getImage(obj); 
        } 
        
        public Image getImage(Object obj) { 
        	return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT); 
        } 
    } 
    
    /**
     * 뷰를 생성하고 초기화 하기 위해 허용되게 될 콜백이다. 
     */ 
    @PostConstruct 
    public void createPartControl(Composite parent, ESelectionService selectionService) { 
    	
        viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); 
        viewer.setContentProvider(new ArrayContentProvider()); 
        viewer.setLabelProvider(new ViewLabelProvider()); 
        
        viewer.addSelectionChangedListener(new ISelectionChangedListener() { 
        	@Override 
            public void selectionChanged(SelectionChangedEvent event) { 
            	selectionService.setSelection(event.getSelection()); 
            } 
        }); 
        viewer.setInput(getElements()); 
    } 
    
    // 단순한 데이타 모델을 구축한다. 
    private List<Todo> getElements() { 
    	List<Todo> todos = new ArrayList<>(); 
        
        Todo todo = new Todo(); 
        todo.setSummary("First Todo"); 
        todo.setDescription("A very good description"); 
        todo.setDone(true); 
        todos.add(todo); 
        
        todo = new Todo(); 
        todo.setSummary("Second Todo"); 
        todo.setDescription("Second super description"); 
        todos.add(todo); 
       	return todos; 
    } 
}

이렇게 변경한 뒤에, 프로젝트를 실행할 수 있고 뷰을 열고 to-do 항목을 볼수 있어야 한다. 

프로퍼티 뷰에 Todo 값을 표시하기 위해, 프로젝트에 org.eclipse.core.runtime.adapters 확장점(extension point)울 추가 한다.

확장점(extension point)의 데이타는 다음과 같아야 한다.:

<extension point="org.eclipse.core.runtime.adapters"> 
	<factory adaptableType="de.vogella.plugin.adapter.model.Todo" 
    		class="de.vogella.plugin.adapter.TodoAdapterFactory"> 
    	<adapter type="org.eclipse.ui.views.properties.IPropertySource"> 
        </adapter> 
    </factory>
</extension>

프로퍼티 뷰에 확장점을 제공하기 위해 IPropertySource 인터페이스 구현한다.

package de.vogella.plugin.adapter; 

import org.eclipse.ui.views.properties.IPropertyDescriptor; 
import org.eclipse.ui.views.properties.IPropertySource; 
import org.eclipse.ui.views.properties.TextPropertyDescriptor; 
import de.vogella.plugin.adapter.model.Todo; 

public class TodoPropertySource implements IPropertySource { 
	
    private final Todo todo; 
    
    public TodoPropertySource(Todo todo) { 
    	this.todo = todo; 
    } 
    
    @Override 
    public boolean isPropertySet(Object id) { 
    	return false; 
    } 
    
    @Override 
    public Object getEditableValue() { 
    	return this; 
    } 
    
    @Override 
    public IPropertyDescriptor[] getPropertyDescriptors() { 
    	return new IPropertyDescriptor[] { 
        	new TextPropertyDescriptor("summary", "Summary")
            , new TextPropertyDescriptor("description", "Description") 
        };
    } 
    
    @Override 
    public Object getPropertyValue(Object id) { 
    	if (id.equals("summary")) { 
        	return todo.getSummary(); 
        } 
        
        if (id.equals("description")) { 
        	return todo.getDescription(); 
        } 
        
      	return null; 
    } 
    
    @Override 
    public void resetPropertyValue(Object id) { 
    
    } 
    
    @Override 
    public void setPropertyValue(Object id, Object value) { 
        String s = (String) value; 
        if (id.equals("summary")) { 
        	todo.setSummary(s); 
        } 
        
        if (id.equals("description")) { 
        	todo.setDescription(s); 
        } 
    } 
}

IPropertySource 구현체로 팩토리와 TodoPropertySource 클래스를 구현한다..

package de.vogella.plugin.adapter; 

import org.eclipse.core.runtime.IAdapterFactory; 
import org.eclipse.ui.views.properties.IPropertySource; 
import de.vogella.plugin.adapter.model.Todo; 

public class TodoAdapterFactory implements IAdapterFactory { 

	// static final 필드를 사용한다 그래서adapterList는 단지 한번 실행된다. 
    private static final Class<?>[] adapterList = new Class<?>[] { IPropertySource.class }; 
    
    @Override 
    public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) { 
    	if (adapterType== IPropertySource.class && adaptableObject instanceof Todo){ 
        	return adapterType.cast(new TodoPropertySource((Todo) adaptableObject)); 
        } 
        
        return null; 
    } 
    
    @Override 
    public Class<?>[] getAdapterList() { 
    	return adapterList; 
    } 
}

만약 워크벤치를 실행하고 Windows > Show > View > Others > Sample Category > Sample View 를 통해 뷰를 열고 그리고 뷰어에 데이타 엘리먼트를 선택할때 프로퍼티 뷰에 데이타를 볼 수 있어야 한다. 

18. 연습 - 어댑터와 워크벤치라벨프로바이더(WorkbenchLabelProvider)

연습 - 프로퍼티 뷰를 위한 어댑터(Adapters)에서 de.vogella.plugin.adapter 플러그인은 이 연습을 위해 재 사용되어야 한다. 

WorkbenchAdapter Sample로 이름이 지어진 또 Sample Category 라는 카테고리를 가지고 있는 다른 파트디스크립터(PartDescriptor)를 생성하다.

파트디스크립터(PartDescriptor) 구현체를 위한 파트로 SampleWorkbenchAdapterView.java 를 생성한다. 이전 SampleView와 차이점은 단지 IStyledLabelProvider 구현체로 WorkbenchLabelProvider를 가지는 DelegatingStyledCellLabelProvider가 LabelProvider로 사용된다는 것이다.

package de.vogella.plugin.adapter.views; 

import java.util.ArrayList; 
import java.util.List; 
import javax.annotation.PostConstruct; 
import org.eclipse.e4.ui.workbench.modeling.ESelectionService; 
import org.eclipse.jface.viewers.ArrayContentProvider; 
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider; 
import org.eclipse.jface.viewers.ISelectionChangedListener; 
import org.eclipse.jface.viewers.SelectionChangedEvent; 
import org.eclipse.jface.viewers.TableViewer; 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.widgets.Composite; 
import org.eclipse.ui.model.WorkbenchLabelProvider; 
import de.vogella.plugin.adapter.model.Todo; 

public class SampleWorkbenchAdapterView { 
	
    private TableViewer viewer; 
    
    /**
     * 뷰어를 생성하고 초기화하는 것을 허용하게될 콜백이다.
     */ 
    @PostConstruct 
    public void createPartControl(Composite parent, ESelectionService selectionService) { 
    	viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); 
        viewer.setContentProvider(new ArrayContentProvider()); 
        
        // IStyledLabelProvider 구현체로 WorkbenchLabelProvider로 DelegatingStyledCellLabelProvider의 활용한다. 
        viewer.setLabelProvider(new DelegatingStyledCellLabelProvider(new WorkbenchLabelProvider())); 
        viewer.addSelectionChangedListener(new ISelectionChangedListener() { 
        	@Override 
            public void selectionChanged(SelectionChangedEvent event) { 
            	selectionService.setSelection(event.getSelection()); 
            } 
        }); 
        viewer.setInput(getElements()); 
    } 
    
    // 단순 데이타 모델을 구축한다.
    private List<Todo> getElements() { 
    	List<Todo> todos = new ArrayList<>(); 
        
        Todo todo = new Todo(); 
        todo.setSummary("First Todo"); 
        todo.setDescription("A very good description"); 
        todo.setDone(true); 
        todos.add(todo); 
        
        todo = new Todo(); 
        todo.setSummary("Second Todo"); 
        todo.setDescription("Second super description"); 
        todos.add(todo); 
        
        return todos; 
    } 
}

WorkbenchLabelProvider를 사용할 때, 뷰어에서 보여질 수있도록 지원되는 객체는 IWorkbenchAdapter, IWorkbenchAdapter2  IWorkbenchAdapter3 인터페이스를 위한 어댑터 적어도IWorkbenchAdapter를 위한 어뎁터는 제공해야 한다. 3가지 인터페이스는 객체들이 보여져야 하는 방법을 결정하기위해 WorkbenchLabelProvider에 의해서 사용될 수 있다. 

WorkbenchLabelProvider를 사용해서 위해 3개의 어댑터를 제공하기 위해, TodoWorkbenchAdapter가 생성된다. TodoWorkbenchAdapter는 모든 3개의 인터페이스를 구현한 추상 클래스인 WorkbenchAdapter로 부터 얻는다.

package de.vogella.plugin.adapter; 

import org.eclipse.jface.resource.ImageDescriptor; 
import org.eclipse.jface.viewers.StyledString; 
import org.eclipse.jface.viewers.StyledString.Styler; 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.graphics.TextStyle; 
import org.eclipse.swt.widgets.Display; 
import org.eclipse.ui.ISharedImages; 
import org.eclipse.ui.PlatformUI; 
import org.eclipse.ui.model.WorkbenchAdapter; 
import de.vogella.plugin.adapter.model.Todo; 

public class TodoWorkbenchAdapter extends WorkbenchAdapter { 
	
    @Override 
    public ImageDescriptor getImageDescriptor(Object object) { 
    	return PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_ELEMENT); 
    } 
    
    @Override 
    public StyledString getStyledText(Object object) { 
    	if (object instanceof Todo) { 
        	Todo todo = (Todo) object; 
            StyledString styledString = new StyledString(todo.getSummary()); 
            
            if (todo.isDone()) { 
            	Styler styler = new Styler() { 
            		@Override 
                	public void applyStyles(TextStyle textStyle) { 
                    	// 완료된 Todo는 녹색 배경을 가져야 한다.
                   	 textStyle.background = Display.getCurrent().getSystemColor(SWT.COLOR_GREEN); 
                 	} 
               	}; 
                
                styledString.setStyle(0, todo.getSummary().length(), styler); 
            } 
            
            return styledString; 
    	} 
    
    	return super.getStyledText(object); 
    } 
}

이제 TodoAdapterFactory TodoWorkbenchAdapter를 제공하기 위해 확장되어야 한다. 

package de.vogella.plugin.adapter; 

import org.eclipse.core.runtime.IAdapterFactory; 
import org.eclipse.ui.model.WorkbenchAdapter; 
import org.eclipse.ui.views.properties.IPropertySource; 
import de.vogella.plugin.adapter.model.Todo; 

public class TodoAdapterFactory implements IAdapterFactory { 

	// static final 필드를 사용한다 그래서 adapterList는 단지 한번만 실행된다. 
    private static final Class<?>[] adapterList = new Class<?>[] { 
    	IPropertySource.class, WorkbenchAdapter.class 
    }; 
    
    @Override 
    public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) { 
    	
        if (adapterType== IPropertySource.class && adaptableObject instanceof Todo){ 
        	return adapterType.cast(new TodoPropertySource((Todo) adaptableObject)); 
        } else if (adapterType.isAssignableFrom(WorkbenchAdapter.class) && adaptableObject instanceof Todo) { 
        	return adapterType.cast(new TodoWorkbenchAdapter()); 
        } 
        
        return null; 
    } 
    
    @Override 
    public Class<?>[] getAdapterList() { 
    	return adapterList; 
    } 
}

이제 TodoAdapterFactory는 WorkbenchAdapter 객체들을 반환해야 하고, 또 org.eclipse.core.runtime.adapters 확장점(extension point)에 지정되여야 한다.

그 결과는 이것과 유사하게 보여야 한다.:

19. 이클립스 리소스(Resources)

이클립스 리소스에 IResourceChangeListener를 등록 할 수 있다. 예를 들면, 만약 프로젝트를 가지고 있다면, 그 프로젝트에 또는 그 프로젝트로 부터 리소스 리스너를 추가 하더나 제거 할 수 있다. 

// 리스너 추가하기 
project.getWorkspace().addResourceChangeListener(listener); 

// 리스너 제거하기 
project.getWorkspace().removeResourceChangeListener(listener); 

// 리소스 리스너 예제
private IResourceChangeListener listener = new IResourceChangeListener() { 
	public void resourceChanged(IResourceChangeEvent event) { 
    	if (event.getType() == IResourceChangeEvent.PRE_CLOSE || event.getType() == IResourceChangeEvent.PRE_DELETE) {
        	if (event.getResource().equals(project)) { 
            	// 프로젝트 삭제됨 또는 종료됨 
                // 추가 작업 구현
                
           	} 
            return; 
        } 
        
        if (resource == null) 
        	return; 
            
        IResourceDelta delta = event.getDelta().findMember(new Path(resource.getURI().toPlatformString(false))); 
        
        if (delta == null) { 
        	return; 
        } 
        
        if (delta.getKind() == IResourceDelta.REMOVED) { 
        	// 리소스 삭제
            // 추가 작업 구현 
        } 
	} 
};

20. 연습: 플러그인읠 위한 feature 생성하기

20.1. feature 프로젝트 생성하기

플러그인을 위한 feature 프로젝트를 생성하고 그 feature에 플러그인을 추가 할 수 있다. File > New > Other…​ > Plug-in Development > Feature Project를 통해서 feature 프로젝트를 생성한다.

다음 스크린샷을 따라 feature 프로젝트를 생성한다. 

20.2. 카테고리 정의(Category Definition) 생성하기 

feature 프로젝트 내에 File > New > Other…​ > Plug-in development > Category Definition를 메뉴 엔트리를 통해 새 카테고리 정의를 생성할 수 있다.  

New Category 버튼을 누르고 기능을 설명할 이름으로 카테고리를 생성하다. 이 카테고리에 feature를 추가한다.

이미지 문구 번역) 카테고리를 생성하기를 클릭한다. 보여질 이름을 입력한다.

21. 연습: 플러그인의 업데이트 사이트 생성하기

21.1. 업데이트 사이트 생성하기

장비에 로컬 디렉토리에 feature를 위한 업데이트 사이트를 생성 할 수 있다. 그러기 위해, File > Export > Deployable features를 선택한다.

카테고리를 사용하기 위해, 옵션(Options) 탭으로 변경하고 저장소 분류(Categorize repository) 옵션에 category.xml 파일의 경로를 선택한다. 

21.2. 이클립스 업데이트 관리자를 통해서 feature 설치하기

이클립스 IDE에 이 새 feature를 설치 하기 위해 Help > Install New Software…​ 를 통해 이클립스 업데이트 관리자를 사용하라.

로컬 디렉렉토리를 지정해서 업데이트 관리자를 사용하라. 그리고 feature를 선택하고 설치 하라.  feature를 볼수 없을 경우에, 카테고리 플래그로 항목( Group items by category)을 선택 취소를 시도하라. 이렇게 하면, 내보내기 하는 동안 카테고리를 설정하는 것을 잃어버리게 된다.

공개된 접속 URL 하위에 웹서버에 결과 바칠을 올려 놓는다면 , 사용자가 그 URL로 부터 features를 설치 할 수 있을 것이다. 

21.3. 설치 검증하기

설치 후에 이클립스 IDE를 재시작하라. 플러그인이 이클립스 설치에서 가능한지 그리고 사용할 수 있는지 확인하라. 

22. 이클립스 플러그인 개발 리소스

이클립스 플러그인 개발 FAQ

컬러와 폰트 환경 구성 추가하기 blog post

이클립스 기사, 튜토리얼, 시연, 책들에 목록을 가진 Wiki

이클립스 튜토리얼

이클립스에 어뎁터들

이클립스 리소스 델타 튜토리얼

이클립스에서 마커, 어노테이션, 그리고 데코레이션 사용하기 (IBM)

 

+ Recent posts