이클립스 워크벤치에서 perspective라고 하는 것은 툴바와 메뉴에 위치하게될 action들의 사용여부와 view의 초기 레이아웃을 정의하는 역할을 담당한다. 아래의 그림의 우측상단에 VICODE라고 선택되어 있는 부분이 바로 perspective를 의미한다.


이클립스에 기본적으로 제공되는 perspective가 몇가지 있다. Java를 선택하면 자바 어플리케이션을 개발하는데 필요한 action이 메뉴와 툴바에 나타날 것이고, Debug를 선택하면 디버깅을 위한 view들이 화면에 배치되는 것을 확인할 수 있다.

따라서 특정 목적(VICODE의 경우 임베디드 시스템 개발)을 가지는 개발환경을 이클립스에서 구현한다면, 이에 해당하는 action들만을 메뉴나 툴바에 나타내고 특정 정보를 화면에 보여주기 위한 view를 원하는 레이아웃에 따라 배치하고 싶을 것이다.

VICODE perspective를 선택했을 때를 살펴보면, Project 메뉴 아래에 필자가 여기저기서 주워와서 갔다 붙인 조악한 툴바 아이콘을 볼 수 있고 화면의 하단에는 따로 만들어서 추가한 Log, Result view가 존재하는 것을 알 수 있다. 이와 같이 perspective는 플러그인이 제공하는 특정 개발 환경을 정의하는 역할을 한다.

개념의 대한 설명은 여기서 마치고 구현방법을 소개하자면,
다음과 같이 org.eclipse.ui.perspectives 확장점을 이용한다.  

  <!-- VICODE Perspective -->
  <extension
        point="org.eclipse.ui.perspectives">
     <perspective
           class="edu.kaist.vicode.perspective.PerspectiveFactory"
           fixed="true"
           icon="icons/jdg2eProd.gif"
           id="edu.kaist.vicode.perspective"
           name="VICODE"/>
  </extension>

PerspectiveFactory.java의 내용은 다음과 같다.

package edu.kaist.vicode.perspective;import org.eclipse.ui.IFolderLayout;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;
public class PerspectiveFactory implements IPerspectiveFactory {
public static final String ID_VICODE_ACTIONS = "edu.kaist.vicode.actionset";
public static final String ID_VICODE_PROJECT_WIZARD =
  "edu.kaist.vicode.projectwizard";
public static final String ID_VICODE_MODULE_WIZARD =
  "edu.kaist.vicode.modulewizard";
public static final String ID_VICODE_LOG_VIEW = "edu.kaist.vicode.logview";
public static final String ID_VICODE_RESULT_VIEW = "edu.kaist.vicode.resultview";

public void createInitialLayout(IPageLayout layout) {
// Navigator
layout.addView(IPageLayout.ID_RES_NAV, IPageLayout.LEFT, 0.20f,
  IPageLayout.ID_EDITOR_AREA);
// Bottom : Another folder area, to stack additional views
IFolderLayout bottom = layout.createFolder("bottom",
  IPageLayout.BOTTOM, 0.8f, IPageLayout.ID_EDITOR_AREA);
bottom.addView(ID_VICODE_LOG_VIEW);
bottom.addView(ID_VICODE_RESULT_VIEW);
bottom.addView(IPageLayout.ID_PROBLEM_VIEW);

// Add Outline View
layout.addView(IPageLayout.ID_OUTLINE, IPageLayout.RIGHT, 0.80f,
IPageLayout.ID_EDITOR_AREA);
   
// Add new wizard shortcut
layout.addNewWizardShortcut(ID_VICODE_PROJECT_WIZARD);
layout.addNewWizardShortcut(ID_VICODE_MODULE_WIZARD);

// Add our actions
layout.addActionSet(ID_VICODE_ACTIONS);
}
}

위의 VICODE perspective가 선택된 화면과 소스코드를 비교해보면 이해하기가 수월 할 것이다. createInitialLayout() 메서드에서 넘어온 IPageLayout 인스턴스를 이용하여 레이아웃을 지정할 수 있다. 차례로 왼쪽의 Navigator를 추가하고 하단에 3개의 view를 추가한다. 그리고 우측의 Outline view를 정의한 후 추후에 다루게 될 마법사를 추가한다. 마지막으로 action에서 다루었던 action set을 추가한다. action set의 visible 속성이 false로 지정되었다면 이렇게 perspective에서 추가해주어야만 화면에 나타나게된다. 모든 것의 참조는 plugin.xml에서 정의한 ID로 이루어진다.

물론 이미 존재하는 perspective에 자신의 view나 action을 추가할 수 있는데 (JDT를 확장하는 경우) 이럴 때는 org.eclipse.ui.perspectiveExtensions 확장점을 이용해야 한다.

Eclipse 플러그인 개발에서 action이라고 하는 것을 간단히 정의하자면 메뉴나 툴바의 아이콘을 클릭하였을 때 수행되는 어떤 일이라고 이야기 할 수 있다. IDE에서 소스를 편집하는 editor 혹은 무언가 정보를 보여주는 viewer를 제외하면 대부분의 기능이 바로 action의 형태로 기여된다고 할 수 있다.

action에 대해서 공부하기 이전에 알아야 할 것이 있는데 action set 이라고 하는 녀석이다. 이는 menu와 action으로 구성되어 있는 action을 정의하기 위한 논리적인 집합이라고 생각하면 되는데 일단 다음의 plugin.xml의 일부를 읽어보자.

<!-- Action Definition -->
  <extension
        point="org.eclipse.ui.actionSets">
        <actionSet
              id="edu.kaist.vicode.actionset"
              label="Co-Design Actions"
              visible="false">
           <menu
                 id="edu.kaist.vicode.interfacemenu"
                 label="Interface">
              <separator name="actionGroup"/>
           </menu>
            <menu
                 id="edu.kaist.vicode.verificationmenu"
                 label="Verification">
              <separator name="actionGroup"/>
           </menu> 
            <!--  Generate Interface for Simulation -->
           <action
                 class="edu.kaist.vicode.actions.SimulationInterfaceGenAction"
                 disabledIcon="icons/config-linker.gif"
                 enablesFor="1"
                 hoverIcon="icons/config-linker.gif"
                 icon="icons/config-linker.gif"
                 id="edu.kaist.vicode.actions.simulationinterfacegen"
                 label="Generate Interface for Simulation"
                 menubarPath="edu.kaist.vicode.interfacemenu/actionGroup"
                 style="push"
                 toolbarPath="edu.kaist.vicode.interfacemenu"
                 tooltip="Generate Interface for Simulation">
              <!-- Project에 대해서만 적용가능한 Action -->
              <selection class="org.eclipse.core.resources.IProject"/>
           </action>

action에 대한 기여는 action 기여를 위한 확장점(extenstion point)이 있어서 여기에 바로 기여(extenstion)하는 것이 아니라 그 것을 둘러싼 action set에 해당하는 확장점(org.eclipse.ui.actionSets)에 기여 함으로써 이루어진다.

menu는 action의 분류를 제공한다. 아래에 정의되어 있는 각 action들이 UI에 나타나려면 적어도 하나 이상의 menu를 지정해야한다. 위의 플러그인을 수행하면 "Interface"와 "Verification"이라는 최상위 메뉴가 (실제로 그 메뉴에 기여하는 action이 존재하는 경우) 메뉴바에 나타난다. menu의 정의는 메뉴바뿐만 아니라 툴바의 분류가 되기도 하며 어떻게 사용되는지는 action 태그의 menubarPathtoolbarPath에 달려있다.

메뉴는 하나 이상의 separator를 가진다. 쉽게 설명하자면 인터넷 익스플로러에 파일 메뉴를 클릭하면 4가지 그룹의 메뉴가 나타나는 것을 볼 수 있으며 이는 4개의 separator를 하나의 menu 태그에서 정의하는 것으로 구현될 수 있다. 그리고 각각의 action은 그들이 속해야 하는 menubarPath = "menu의 id/separator의 name" 형태로 자신이 UI의 어디에 나타나야 하는지를 지정할 수 있다. 툴바에 기여하는 경우에는 separator를 지정할 필요가 없다.

여기서 action set의 중요한 속성을 하나 살펴보자. Eclipse 플랫폼은 다수의 플러그인을 포함하여 동작하고 있다. 모든 플러그인이 제공하는 action과 menu가 UI에 모두 나타난다고 상상해보면 어떨까?

나중에 perspective에 대한 글에서 자세히 설명하겠지만, 이와 같은 문제를 해결하기 위해서 플러그인이 제공하는 환경과 기능을 관리할 수 있는 perspective라는 개념을 도입하였다. Eclipse 플랫폼에 기본적으로 포함되어 있는 perspective에는 Java, Debug, Resource등이 있다. Java라는 perspective를 선택하면 자바프로그램을 편집하는데 필요한 에디터와 뷰어 그리고 툴바의 아이콘등이 나타나는 것을 알 수 있다. Java와 Resource perspective를 변경하면서 툴바를 살펴보면 그 차이를 알 수 있을 것이다.

action set에서 visible 속성을 이용하여 action set에 포함되는 menu와 action들이 perspective와 상관없이 무조건 UI에 나타날 것인지 아닌지를 true, false로 지정할 수 있다. 다시 말하면 이 값이 true인 경우 항상 action set에 포함되는 것들이 UI에 표현되고, false인 경우에는 특정 perspective에 action set을 포함시켜 그 perspective로 전환되었을 때만 UI에 표현하게 한다. 자세한 내용은 perspective에 대한 글에서 다룰 생각이다.

지금까지는 action set의 구조와 메뉴(menubarPath)와 툴바(toolbarPath)에 각 action이 어떻게 추가될 수 있는지를 살펴보았다. 지금부터는 action 자체에 대해서 살펴보자. action에서 지정되는 클래스는 IWorkbenchWindowActionDelegate 인터페이스를 상속해야 한다.

public class SimulationInterfaceGenAction implements
IWorkbenchWindowActionDelegate {
private IStructuredSelection selection;

public void dispose() {
// TODO Auto-generated method stub
}
public void init(IWorkbenchWindow window) {
// TODO Auto-generated method stub
}
public void run(IAction action)
{
// TODO Auto-generated method stub
IProject project = (IProject) selection.getFirstElement();
...
...
...
}
public void selectionChanged(IAction action, ISelection selection) {
// TODO Auto-generated method stub
if (selection instanceof IStructuredSelection) {
  this.selection = (IStructuredSelection) selection;
}

}
}

action을 구현한 클래스는 위와 같은 구조를 가지게 된다. 툴바의 아이콘이나 메뉴를 클릭하면 해당 action의 run() 메서드가 호출되어 특정 작업이 수행된다. 여기서 추가로 알아야 할 것은 특정 action은 특정 selection과 관계를 맺을 수 있다는 것! 즉 action을 수행하는 대상이 무엇인지 알아야 한다. 예를 들어 JDT에서 메서드의 이름을 바꾸는 리펙토링 액션을 수행한다고 한다면 분명 선택한 메서드가 있을 것이다. 이러한 선택을 selection이라고 하며 selectionChanged() 메서드에서 이 selection을 얻어올 수 있다. 이렇게 얻어온 selection을 통해 특정 영역에 해당하는 action을 수행하게 된다.

action은 selection의 형태에 따라 enable/disable 될 수 있다. 이를테면 어떤 action은 프로젝트(IProject)만을 선택으로 받아들일 수 있고, 어떤 action은 디렉토리(IFolder)에 대해서만 작업을 수행할 수 있다.  이는 plugin.xml에서 selection 태그로 지정할 수 있다. 심지어 name 속성을 이용하면 특정 파일명에 대해서만 action을 제한할 수 있다.

+ Recent posts