Posted by 열혈개발자

GEF 에디터에 ActionBarContributor를 정의하여 Delete 액션을 리타겟 하여 사용하다가 이 GEF에디터를 MultipateEditor로 옮겨야 하게 되었다.
문제는 GEF에디터를 그냥 쓸때는 plug-in.xml에서 에디터의 Contributor를 정의하여 사용하면 문제없이 Delete액션이 작동 하였지만 GEF에디터를 MultipageEditor에 추가하여 사용하면 GEF에디터에 설정해둔 ActionBarContributor는 작동하지 않는다는 것이었다.

이것을 어떻게 해결하느냐..
MultipageEditor에 해당하는 ActionBarContributor를 다시 지정해야 한다. MultipageEditor에 ActionBarContributor를 지정하려면 MultiPageEditorActionBarContributor를 상속한 클래스를 만들어 plug-in.xml에서 지정해주어야 한다. MultiPageEditorActionBarContributor는 abstract클래스로 setActivePage()메소드를 구현해야 하는데 setActivePage에서 activeEditor의 getAdapto메소드의 인자를 ActionRegistry.class를 넣어 호출 하여 활성화 된 에디터의 ActionRegistry를 가져온다.
가져온 registry를 이용하여 actionbar에 추가시킬 액션을 추가하면 문제는 해결된다.


@Override
 public void setActivePage(IEditorPart activeEditor) {
 
  if (activeEditor != null) {
   ActionRegistry registry = (ActionRegistry) activeEditor.getAdapter(ActionRegistry.class);
   
   if (registry != null) {
    IActionBars bars = getActionBars();
   
    for (int i = 0; i < globalActionKeys.size(); i++) {
     String id = (String) globalActionKeys.get(i);
     IAction action = registry.getAction(id);
     
     bars.setGlobalActionHandler(id, action);
     
    }
   
    getActionBars().updateActionBars();
   }
  }
 }

이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 열혈개발자
TAG RCP

Plug-in 개발을 하다 보면 파일로부터 입력 받아야 경우가 발생할 것이다. 이때 파일에 접근하기 위하여 경로를 설정해야 하는데 제일 간단한 방법은 파일의 경로를 절대경로로 "c:\aaa\bbb.txt"식으로 접근하는 방법이다. 그러나 개발하고자 하는 플러그인이 어느 위치에 있을지 알 수 없다. 그러므로 경로가 유동적인 상대경로로 설정하는 것이 더 바람 직 할 것이다.

Java.io.File 같은 경우 상대 경로로 설정하기 위해서는 File file = new file(bbb.txt)과 같이 파일 이름만 생성자의 인자로 사용하거나 경로를 설정하면 프로젝트 경로를 기준으로 설정한 경로를 따라 간다.

Eclipse Plug-in에서는 이것보다 좀더 고급스러운 방법을 지원한다. Bundle과 BundleUtility를 사용하여 InputStream을 생성할 수 있고 이를 이용하여 파일로부터 입력을 받을 수 있다.

Bundle bundle = Platform.getBundle(Application.PLUGIN_ID);

URL fileURL = BundleUtility.find(bundle, "folder/data.dat");


try{

InputStream iStream = fileURL.openStream();

}catch(IOException e){

e.printStackTrace();

}


위와 같이 InputStream을 생성하고 이 입력 스트림을 이용하여 파일로부터 내용을 읽어 들이면 된다.

BundleUtility.find()의 첫 번째 인자는 플러그인 에 해당하는 Bundle이고 두 번째 인자는 읽을 파일 경로이다. 경로는 플러그인 프로젝트 폴더를 루트 폴더로 기준을 잡고 하위 경로를 입력하면 된다.

이렇게 하면 프로젝트 폴더가 어디로 이동하더라도 해당 파일을 읽을 수 있다.


Posted by 열혈개발자
TAG Eclipse, RCP

Wizard 작성시 Wizard에 여러개의 WizardPage를 추가하여 Wizard를 구성한다.
 이때, 각 페이지 별로 페이지의 초기값을 할당해 주어야 할 때가 있다. 그리고 그 값은 이전 페이지에서 사용자가 입력한 내용을 바탕으로 지정해야 할 때가 있다.

 내가 처음에 이 문제에 부디쳤을 때는 각 페이지는 사용자가 next버튼을 클릭해서 페이지가 활성화 될 때 페이지가 생성 될거라 생각하고 페이지의 생성자 부분에서 초기값을 할당해 주면 된다고 생각했다. 그러나 모든 Wizard에 올라가는 모든 페이지들은 Wizard가 생성되는 순간에 이미 모두 생성되에 Wizard를 구성하게되고 Wizard가 화면에 나타나게 되는것이다. 그러므로 페이지의 생성자는 사용자로 부터 입력 받기전에 이미 호출되기 때문에 우리가 원하는 초기화 작업을 할 수없다.

 이를 해결하기 위해서는 DialogPage.setVisible(boolean visible)메소드를 이용하여야 한다. WizardPage는 DialogPage의 하위 클래스 이므로 WizardPage에서 setVisible을 재정의 해야한다. setVisible()메소드는 페이지가 생성되고 난 후 화면에 보여질때 호출 되는 메소드 이다. 이 메소드 내에서 페이지 내 각 컨트롤들의 초기화 작업을 할 수있는것이다.

사용 예)
public void setVisible(boolean visible){
  NewProjectWizard wizard = (NewProjectWizard)getWizard();
  InputProjectNamePage inputProjectNamePage = (InputProjectNamePage)wizard.getPreviousPage(this);
  name.setText(inputProjectNamePage.getProjectName());
 
  super.setVisible(visible);
 }

이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 열혈개발자
TAG RCP, Wizard
번역/수정 자료 입니다.


이클립스 플러그인 및 이클립스RCP에서 IResource인터페이스를 이용하여 Eclipse Workspace상의 자원을 취급하는 방법에 대해서 알아 보자.

  • 이클립스의 Resource

Eclipse의 모든 자원은 Workspace로 불리는 영역에 저장 된다. Workspace는 Eclipse Workbench에 대해서 하나만 존재하여, 폴더나 파일 등의 자원은 이 Workspace상에 맵핑 되지 않으면 Eclipse에서 취급할 수 없다. 또, Workspace에는 항상 하나의 Workspace Root만 존재 한다. 또한, Workspace Root에는 몇 개의 Project가 존재해, 그 Project내에 폴더나 파일이 존재 하게 된다.

또, Project나 폴더, 파일 이라고 하는 Resource는 실제의 파일 시스템에 맵핑 된다. Eclipse의 프로젝트, 폴더, 파일 등의 Resource는 파일시스템의 디렉토리나 파일에 대응한다. 하지만 이러한 Eclipse의 자원을 직접 파일시스템을 이용하여 취급하는 것은 좋지 않다. 반드시 각 자원 마다 할당할 수 있는 Resource의 인터페이스(IResource, IFolder, IFile등..)를 이용하여 취급해야만 한다.

  • Resource의 작성과 획득

위에서 설명한 대로 Resource의 조작은 Resource핸들을 이용해서 수행한다. 통상적으로 Resource의 핸들은 갑자기 작성할 수 없고, 임의의 Resource 핸들을 작성하기 위해서는, 그 Resource의 컨테이너가 되는 Resource의 핸들이 필요하다. 예를 들면, 파일의 Resource를 작성하기 위해서는, 프로젝트나 폴더의 핸들이 필요하다. 또, 폴더를 작성하기 위해서는, 프로젝트나 부모 폴더의 핸들이 필요하다. 또한, 프로젝트를 작성하기 위해서는 Workspace Root의 핸들이 필요하다.

그러면 Workspace Root의 핸들 작성은 어떻가 하는가 하면, Workspace Root는 항상 존재하는 것으로 생성하거나 복사, 이동 할 수없다. 또 Workspace Root의 핸들은 IWorkspaceRoot인터페이스롤 나타내져 플러그인의 코드 어디에서도 아래와 같은 방법으로 취득 할 수 있다.

IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();


이IWorkspaceRoot 오브젝트는, 프로젝트의 컨테이너가 되는 자원의 핸들이기 때문에, IWorkspaceRoot를 취득하면, 프로젝트의 작성이 가능하게 된다. 또, 프로젝트의 핸들은 IProject인터레이스로 나타내지며 폴더와 파일은 각각 IFolder, IFile인터레이스로 나타낸다. 이러한 Resource를 나타내는 인터페이스는 모두 IResource의 하위 인터페이스 들이다.

  • Resource의 작성

우선, 위에서 취득했던 IWorkspaceRoot를 사용해 프로젝트를 작성해 보자.

IProgressMonitor monitor = ……

IWorkspaceRoot root = ResourcePlugin.getWorkspace().getRoot();


//프로젝트 핸들의 작성

IProject project = root.getProject("My Project");


If(!project.exists()){

Project.create(monitor); // 실제 프로젝트 작성

Project.open(monitor); //프로젝트 오픈


……

}

①의 부분에 create()라는 이름의 말 그대로 무언가를 생성하는 메소드가 있다. 그 이전에 getProject()라고 하는 메소드가 있지만 이는 프로젝트의 핸들을 작성하는 메소드이다. 그 다음 create()메소드를 통하여 실제로 디렉토리를 작성하거나 Eclipse의 프로젝트를 작성한다. 즉 IWorkspaceRoot.getProject()메소드에서는 프로젝트의 핸들을 작성하는 것 만으로는 Workspace상에 도 파일시스템상에도 아무 영향이 없다. 또, IWorkspaceRoot.getProject()메소드에는 2종류가 있어서 다음과 같이 정의 되고 있다.

정 의

의 미

IProject getProject(String name)

주로 프로젝트핸들의 작성에 사용된다. 인수 name에 프로젝트명을 지정한다. 이프로젝트명을 가지는 프로젝트가 워크스페이사항에 존재하고 있는 경우에는, 그 프롲게트의 핸들이 리턴되며 존재하지 않는 경우에는 그 프로젝트명을 가지는 프로젝트 핸들이 작성되어 리턴된다. 그러나 이 경우 리턴된 핸들은 이 단계에서는 Workspace상에 맵핑 되지는 않는다.

IProject[] getProject()

Workspace상에 존재하는 모든 프로젝트의 핸들의 배열을 리턴한다.



여기서, getProject(String name)를 사용해서 프로젝트 핸들을 작성 한다고 해도, 실제 프로젝트는 워크스페이스나 파일시스템에 생성되지 않는다. 실제로 프로젝트를 작성 하기위해서는 IProject.create()메소드를 호출 해야 한다. 그리고 create()메소드를 호출하기 전에, getProject()메소드로 저정한 프롲게트명을 가지는 프로젝트가 Workspace상에 이미 존재하고 있을지를 체그할 필요도 있다.(이미 존재 하는 프로젝트 핸들로 create()메소드를 호출하면 예외가 발생한다.)

Create()메소드를 호출한 단계에서 getProject()로 작성한 프로젝트 핸들이 워크스페이스에 추가되어 프로젝트와 맵핑되는 디렉토리가 파일 시스템상에 생성 된다. 그러나 이 단계에도 작성한 프로젝트에 대해 어떠한 조작도 할 수없다. 작성한 프로젝트에 폴더나 파일을 추가하기 위해서는 프로젝트를 여는 작업을 해야 한다. 프로젝트를 열기 위해서는 IProject.open()메소드를 사용한다. 이후, 프로젝트에 Resource 추가 등의 조작이 가능하게 된다. 또, IProject의 create()/open()메소드는 모두 시간이 걸리는 처리 이므로 유저에게 조작의 진행 상황을 보고하는, IProgressMonitor형태의 오브젝트를 인수로 받는다. 이 인수에 null을 지정하면 진행상황은 보고되지 않는다.

이것으로 프롲게트의 작성은 완료 되었다. 프로젝트는 파일 및 폴더의 컨테이너이므로 IProject를 취득하면 폴더와 파일의 작성이 가능하게 된다.

IProject project = ...


// 파일 작성

IFile file = project.getFile("MyFile.file"); // 파일 핸들 작성

file.create(new ByteArrayInputStream(new byte[0]),false,null); // 실제 파일 작성


IFolder folder = project.getFolder("MyFolder"); // 폴더 핸들 작성

folder.create(false,true,null); // 실제 폴더 작성


이러한 파일이나 폴더 역시 프로젝트의 경우와 마찬가지로 getFile(), getFolder()와 같은 메소드로 핸들을 작성한 후 create()메소드로 실제의 Resource를 작성하게 된다. 또, 파일을 작성하기 위한 메소드 IFile.create()의 정의는 아래와 같다.

public void create(InputStream source,

         boolean force,

         IProgressMonitor monitor) throw CoreException


여기서 인수 source는 작성하고자 하는 파일의 내용을 지정한다. 이 인수에 null을 지정하면 파일은 로컬파일이 아닌 것으로 취급 된다. 이 파일이 Workspace상에 존재해도 로컬 파일시스템상에는 존재하지않는 것을 나타낸다. 따라서 로컬 파일시스템에 파일을 작성하는 경우에는 source에 null을 입력하는 것이 아니라 위와 같은 ByteArrayInputStream 오브젝트를 입력한다.

인수 force에는 이 Resource가 파일 시스템과 동기화가 이루어지지 않아도 수정 가능하도록 할지를 지정한다. 이것에 false를 입력하면 같은 이름의 파일이 로컬 파일시스템 상에 없을 경우에만 수정 할 수 있도록 한다. true를 입력하면 같은 이름의 파일이 로컬 파일 시스템에 존재하는 경우라도 soruce에 지정한 내용을 그 파일에 덮어 쓰게 된다.

인수 monitor에는 IProject.create()등의 메소드와 같이 작업의 진행 상황을 사용자에게 알리기 위한 IProgressMonitor를 지정한다. 이 인수에 null을 지정하면 진행상황은 표시되지 않는다.

폴더를 작성하기 위한 IFolder.create()메소드의 정의는 아래와 같다.

public void create(InputStream source,

         boolean local,

         IProgressMonitor monitor) throw CoreException

인수 force와 monitor는 IFile의 경우와 같다. 또 인수 local에는 그 폴더를 로컬로 작성하는지 여부를 지정한다. 이 인수에 false를 지정하면 Workspace상에는 이 폴더가 작성되지만 로컬 파일 시스템 상에는 디렉토리가 생성 되지 않는다.(코드상에서 해당 자원이 로컬인지 확인하려면 IResource.isLocal()메소드를 사용한다.)

이와 같이 Workspace상의 자원이 반드시 로컬 파일 시스템과 동기화가 이루어 지는 것은 아니다. 좀더 구체적인 예를 들면, 패키지 익스플로어에 MyProject라는 프로젝트가 표시되고 있다고하면 이 MyProject라고 하는 Resource는 통상적으로 파일 시스템의 디렉토리에 맵핑되어(생성되어)있을 것이다. 그러나 패키지 익스플로어를 이용하지 않고 탐색기 등을 이용해서 해당 디렉토리를 삭제 했을 경우에 Workspace상에는 프로젝트 핸들이 존재하지만 로컬 파일 시스템에는 존재하지 않는다.

따라서 Resource 핸들을 사용해서 Workspace상의 Resource를 조작하는 경우 에는 create()나 move, delete등의 메소드를 호출하기 전에(이러한 메소드는 핸들에 맵핑된 로컬 파일 시스템의 Resource를 조작한다.)Resource 핸들에 맵핑된 실제의 로컬 파일 시스템상의 자원이 존재하는지 IResource.exists()메소드를 사용하여 체크해야 할 필요가 있다. 이와 비슷하게 IProject의 경우 에 프로젝트가 열려있지 않은경우(IProject.isOpen()==false)에는 그 프로젝트에 몇 개의 Resource가 있다고 해도 IResource.exists()메소드는 false를 리턴한다. 따라서 프로젝트 내의 Resource의 존재의 체크하기 전에IProject.open()메소드를 호출해야 한다.

Posted by 열혈개발자
 

 

 

 

문서의 분할(Partitioning)

2007-05-29

수정: 김상태

 Eclipse 에디터(JFace 텍스트 문자 편집기)에서는 에디터로 편집하는 문서의 내용을 org.eclipse.jface.textIDocument 추상 오브젝트로써 취급한다. IDocument 오브젝트는 문서 프로바이더에 의해 제공된다. XML Sample Editor에서는 XML DocumentProvider 해당된다.

리스트3  

public class XMLDocumentProvider extends FileDocumentProvider {

   protected IDocument createDocument(Object element)
                     throws CoreException {
     IDocument document = super.createDocument(element);
     if (document != null) {
       IDocumentPartitioner partitioner =
         new FastPartitioner(
            new XMLPartitionScanner(),
            new String[] {
              XMLPartitionScanner.XML_TAG,
              XMLPartitionScanner.XML_COMMENT });
       partitioner.connect(document);
       document.setDocumentPartitioner(partitioner);
     }
     return document;
   }
}

 

  XMLPartitionScanner 문서의 의미적인 구역을 분할(Partitioning) 한다. 분할된 구역은 각각의 구문 하이라이팅이나 코드어시스트 기능을 설정하는 것이 가능하다. Java 에디터를 예로 하면, Javadoc부분에서는 Javadoc 태그의 어시스트, Java 코드 부분에서는 Java코드의 어시스트와 같이 해당 콘텍스트에 응한 기능을 제공할 있다.

 XMLPartitionScanner에서는 코멘트(XML_COMMENT), 태그(XML_TAG) 이외의 영역의 3개의 파티션으로 분할 한다.

 

리스트4  

public final static String XML_DEFAULT = "__xml_default";
   public final static String XML_COMMENT = "__xml_comment";
   public final static String XML_TAG = "__xml_tag";

   public XMLPartitionScanner() {

     IToken xmlComment = new Token(XML_COMMENT);
     IToken tag = new Token(XML_TAG);

     IPredicateRule[] rules = new IPredicateRule[2];

     rules[0] = }
        new MultiLineRule("<!--", "-->", xmlComment); ……(1)
     rules[1] = new TagRule(tag); ……(2)

     setPredicateRules(rules);
   }
}

 

XMLpartitionScanner RuleBasedPartitionScanner 상속 받아 구현 되고 있다. XML이나 프로그램의 소스코드 , 룰에 근거한 문서를 분할 하는 경우는 org.eclipse.jface.text.rules.RuleBasedPartitonScanner 사용하면 된다.

 

(1) 코멘트 구역의 룰은 org.eclipse.jface.text.rules.MultiLineRule 정의 하고 있다. MultiLineRule 시작 문자열과 종료 문자열을 지정해 매치되는 부분을 파티션으로 설정 하는 이다. , (2) 태그구역의 룰을 TagRule 정의하고 있다. 태그구역에 관해서도 코멘트 구역과 같이 new MultiLineRule(“<”, ”>”, token)으로 지정해도 좋을 같긴 하지만 이렇게 하면 코멘트나 XML태그 선언 모두 XML태그로 인식되기 때문에 TagRule 리스트5 같이 MultiLineRule 상속 받아 독자적으로 매치의 판정을 실시하게 정의 하였다.

 

리스트5

public class TagRule extends MultiLineRule {

   public TagRule(IToken token) {
     super("<", ">", token);
   }
   protected boolean sequenceDetected(
     ICharacterScanner scanner,
     char[] sequence,
     boolean eofAllowed) {
     int c = scanner.read();
     if (sequence[0] == '<') {
       if (c == '?') { // < 의 다음의 문자가 ‘?’이면 설정 하지 않는다
         // processing instruction - abort
         scanner.unread();
         return false;
       }
       if (c == '!') { // < 의 다음의 문자가 ‘!’이면 설정 하지 않는다
         scanner.unread();
         // comment - abort
         return false;
       }
     } else if (sequence[0] == '>') {
       scanner.unread();
     }
     return super.sequenceDetected(scanner, sequence, eofAllowed);
   }
}

 이것에 의해서XML 문서는 그림5 같은 파티션으로 분할된다.

 

그림5. 분할 후의 파티션

 

에디터의 configuration

 SourceViewerConfiguration 에디터의 동작을 커스터마이즈하기 위한 시작 포인트가 된다. 자동 생성된 샘플에서는 XMLConfiguration 이에 해당한다.

Org.eclipse.jface.text.source.SourceViewerConfiguration 상속받은 클래스가 사용되고 있다. 이와 같이 SourceViewerConfiguration 메소드를 오버라이드하는 것으로, 다음과 같은 이디터의 동작을 커스터마이즈 있다.

l  코드 어시스트

l  문장 하이라이트

l  더블 클릭 시의 동작

l  자동 들여쓰기 기능

l  코드 포메터

템플릿으로 작성한 XML에디터는 코드 어시스트나 코드 포멧터의 기능은 가지고 있지 않다. 이번에는 코드 하이라이트와 더블클릭시의 동작, 특히 코드하이라이트의 구현 방법에 대해 자세히 알아보자. 

 

리스트6

public class XMLConfiguration extends SourceViewerConfiguration {
   private XMLDoubleClickStrategy doubleClickStrategy;
   private XMLTagScanner tagScanner;
   private XMLScanner scanner;
   private ColorManager colorManager;

   public XMLConfiguration(ColorManager colorManager) {
     this.colorManager = colorManager;
   }
   public String[] getConfiguredContentTypes(
       ISourceViewer sourceViewer) { ……(1 )
     return new String[] {
       IDocument.DEFAULT_CONTENT_TYPE,
       XMLPartitionScanner.XML_COMMENT,
       XMLPartitionScanner.XML_TAG };
   }
   public ITextDoubleClickStrategy getDoubleClickStrategy(
     ISourceViewer sourceViewer,
     String contentType) { ……(2 )
     if (doubleClickStrategy == null)
       doubleClickStrategy = new XMLDoubleClickStrategy();
     return doubleClickStrategy;
   }

   protected XMLScanner getXMLScanner() {
     if (scanner == null) {
       scanner = new XMLScanner(colorManager);
       scanner.setDefaultReturnToken(
         new Token(
            new TextAttribute(
              colorManager.getColor(IXMLColorConstants.DEFAULT))));
     }
     return scanner;
   }
   protected XMLTagScanner getXMLTagScanner() {
     if (tagScanner == null) {
       tagScanner = new XMLTagScanner(colorManager);
       tagScanner.setDefaultReturnToken(
         new Token(
            new TextAttribute(
              colorManager.getColor(IXMLColorConstants.TAG))));
     }
     return tagScanner;
   }

   public IPresentationReconciler getPresentationReconciler(
               ISourceViewer sourceViewer) { ……(3 )
     PresentationReconciler reconciler =
                  new PresentationReconciler();

     DefaultDamagerRepairer dr =
       new DefaultDamagerRepairer(getXMLTagScanner());
     reconciler.setDamager(dr, XMLPartitionScanner.XML_TAG);
     reconciler.setRepairer(dr, XMLPartitionScanner.XML_TAG);

     dr = new DefaultDamagerRepairer(getXMLScanner());
     reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
     reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);

     NonRuleBasedDamagerRepairer ndr =
       new NonRuleBasedDamagerRepairer(
         new TextAttribute(
            colorManager.getColor(IXMLColorConstants.XML_COMMENT)));
     reconciler.setDamager(ndr, XMLPartitionScanner.XML_COMMENT);
     reconciler.setRepairer(ndr, XMLPartitionScanner.XML_COMMENT);

     return reconciler;
   }

}

 

 (1) getConfiguredContentType()메소드에서는 에디터가 지원하는 파티션의 타입을 리턴 하도록 정의 한다.  , (2) getDoubleClickStrategy()메소드에서는 더블클릭시의 동작을 결정한다. Org.eclipse.jfacejface.text.ITextDoubleClickStrategy 구현 클래스를 리턴 한다. XMLDoubleClickStrategy 구현에 따라서 깊게 설명하지는 않겠지만, 더블 클릭 위치에 따라 더블 쿼츠로 둘러싸인 구역, 혹은 단어를 검출해서 해당 범위가 선택 되도록 구현 되어 있다. 그리고  (3) getPresentationReconciler()메소드로 에디터의 프레젠테이션(구문 하이라이팅) 관한 설정을 구현한다.

구문 하이라이트는 org.eclipse.jface.text.prresentation.PresentationReconciler 파티션마다 Damager Repairer 설정하는 것으로 구현 된다. PregetntationReconciler 텍스트의 변경을 검출하면 Damager 호출하여 Damage(텍스트의 프레젠테이션을 갱신해야 하는 범위) 산출한다. 다음 Repairer Damage 통지하여 새로운 프레젠테이션을 취득한다.

이번 예에서는 XML_TAG구역, DEFAULT-CONTENT_TYPE구역에 각각 XMLTagScanner, XMLScanner org.eclipse.jface.text.rules.DefaultDamagerRepairer 통하여 설정되어있다. XMLTagScanner 구현은 리스트7 같이 되어있다.

 

리스트7

public class XMLTagScanner extends RuleBasedScanner {

 public XMLTagScanner(ColorManager manager) {
   IToken string =
    new Token(
    new TextAttribute(
    manager.getColor(IXMLColorConstants.STRING)));

   IRule[] rules = new IRule[3];

   // Add rule for double quotes
   rules[0] = new SingleLineRule("\"", "\"", string, '\\');
   // Add a rule for single quotes
   rules[1] = new SingleLineRule("'", "'", string, '\\');
   // Add generic whitespace rule.
   rules[2] = new WhitespaceRule(new XMLWhitespaceDetector());

   setRules(rules);
   }
}

이것은XML_TAG 구역을 더블쿼츠 혹은 싱글 쿼츠로 둘러싸인 영역으로 정의하고 IXMLColorConstants.STRING으로 정의된 색으로 하이라이트 한다.

 

XMLScanner 구현도 유사하다. 이것은 DEFAULT-CONTENT_TYPE구역을 <? ?>으로 둘러싸인 영역으로 정의하고 IXMLColorConstants.PROC_INSTR 정의된 색으로 하이라이트 한다.

 

리스트8  

public class XMLScanner extends RuleBasedScanner {

   public XMLScanner(ColorManager manager) {
   IToken procInstr =
    new Token(
    new TextAttribute(
     manager.getColor(IXMLColorConstants.PROC_INSTR)));

   IRule[] rules = new IRule[2];
   //Add rule for processing instructions
   rules[0] = new SingleLineRule("<?", "?>", procInstr);
   // Add generic whitespace rule.
   rules[1] = new WhitespaceRule(new XMLWhitespaceDetector());

   setRules(rules);
   }
}

 

파티션 내에서 룰에 정의 되지 않는 부분에 대해서는 setDefaultReturnToken() 지정된 토큰이 적용 된다. , XML_COMMENT구역은 이상 분할할 필요는 없기 때문에 NonRuleBasedDamagerRepairer 의해서 구역 전체를 IXMLColorConstant.XML_COMMENT 정의된 색으로 하이라이트 한다.

 

끝으로……

텍스트 문자 편집기의 구현에는 많은 주제가 있다. 특히 중요한 것은 이번에 중심적으로 해설한 Partitioning이다. 고로 해설했던 대로 구문 하이라이트는 Partitioning 구역에 대해서 설정하고, 코드 어시스트 기능 역시 파티션 마다 어시스트 프로세서를 설정하는 것으로 구현 된다.

 

 

Ps. 포스트는 http://www.atmarkit.co.jp/fjava/rensai3/eclipsepde03/eclipsepde03_2.html 문서를 Naver 인조이 제팬을 이용하여 번역한 문서 입니다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 열혈개발자
TAG Eclipse, RCP

이클립스에서 제공하는 Sample XML Editor는 내부에서 Document Provider로 FileDocumentProvider를 상속 받은 XMLDocumentProvider를 사용한다.
 그런데 이 FileDocumentProvider는 org.eclipse.ui.ide에 의존하기 때문에 RCP에서는 상용할 수 없고 Plug-in에서만 사용할 수 있다.
그래서 Sample XML Editor를 RCP에서 사용하려면 DocumentProvider를 직접 구현해서 적용해야 한다.
 
DocumentProvider의 역할은 EditorInput으로 부터 Editor에 표시될 내용을 입력받아 IDocument를 생성해 주는 역할을 한다. 그래서 직접 구현할 부분중 핵심이 되는것이 DocumentProvider의 createDocument()메소드 이다.

AbstractDocumentProvider를 상속받아 자신만의 DocumentProvider를 만들고 상속받은 추상 메소드 들을 구현한다. 그중 createDocument()에서 IDocument의 인스턴스를 생성하여 리턴한다.

 IDocument document = new Document() 로 빈 Document를 생성하여 Document의 내용을 채운후 리턴한다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 열혈개발자
TAG Eclipse, RCP
Wizard를 상속 한 MyWizard의 Finish 버튼의 활성화를 제어 하는 법이다.

우선 MyWizard에 Wizard의 canFinish()를 오버라이딩 하여 활성화 유무 상태를 정의 한다.

MyWizard에 올라가는 WizardPage의 컨트롤 들에 Listener를 추가 한다. 각 Listener들이 수신하는 이벤트에서 getWizard().getContainer().updateButtons();를 호출하여 부모 WIzard의 버튼들의 상태를 업데이트 한다.

일렇게 Finish 버튼의 활성화 유무를 제어할 수 있고, next버튼 역시 이와 비슷한 방법으로 제어할 수 있다.
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 열혈개발자
TAG RCP, Wizard
텍스트 편집기 구현중 다른이름 저장 기능을 마법사를 이용해서 구현 중이다.
WizardPage에 TreeViewer를 올릴려고 하다가 TreeViewerLayout을 지정하는 법을 몰라 한참 뒤적였다.
다른 컨트롤 처럼 setLayout()메소드가 TreeViewer에는 제공 되지 않았다. TreeVirewer는 Controll이 아니기 때문이다. 이것을 쓰기 위해서는 TreeViewer에서 getControl()메소드를 이용해서 control을 가져온 다음 거기에 setLayoutData()를 호출하여 레이아웃을 지정하면 된다.
처음 이것을 몰라서 TreeViwer가 WizardPage에 꽉 차지 않고 작게 나와서 황당했다.

사용자 삽입 이미지

소스 :
treeviewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 열혈개발자
/ : 루트 디렉토리
. : 커런트 디렉토리
.. : 상위 디렉토리
~ : 홈 디렉토리
~_ : 직전 디렉토리
~[사용자명] : 지정 사용자의 디렉토리
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 열혈개발자