- 전체
- JAVA 일반
- JAVA 수학
- JAVA 그래픽
- JAVA 자료구조
- JAVA 인공지능
- JAVA 인터넷
- Java Framework
- Java GUI (AWT,SWING,SWT,JFACE)
- SWT and RCP (web RAP/RWT)[eclipse], EMF
SWT and RCP (web RAP/RWT)[eclipse], EMF RCP 에디터 정리
2019.11.20 13:24
RCP 에디터 정리
출처: http://blog.naver.com/PostView.nhn?blogId=unbraid&logNo=124922134
Editor Overview#
-
Editor는 사용자가 Resource(예 : 파일)를 생성하고 편집하는데 이용하는 기본적인 메커니즘이다.
- 이클립스는 Text Editor, Java Source Editor 같은 기본적인 편집기 뿐만 아니라
- 플러그인 내역서 편집기처럼 복잡한 MutilPage Editor도 제공한다.
- 또한, Eclipse Editor와 Extention을 사용해 자신만의 Editor를 만들 수 있다.
-
Editor는 org.eclipse.ui.IEditorPart 인터페이스를 구현해야 한다.
- 일반적으로 Editor는 EditorPart의 하위 클래스이므로 간접적으로 WrokbenchPart의 하위 클래스이다.
- public abstract class EditorPart extends WorkbenchPart implements IEditorPart{
-
Editor는 IEditorSite를 포함되며, IEditorSite는 IWorkbenchPage에 포함된다.
-
IEditorPart
- public abstract class EditorPart extends WorkbenchPart implementsIEditorPart {
-
public abstract class WorkbenchPart extends EventManager implements
IWorkbenchPart2, IExecutableExtension, IWorkbenchPartOrientation { - public interface IEditorPart extends IWorkbenchPart, ISaveablePart {
- public interface IWorkbenchPart extends IAdaptable {
-
- IWorkbenchPage는 Editor 자체보다는 IEditorReference의 인스턴스를 참조하고, 이를 통해 Editor를 정의하는 플러그인을 로딩하지 않고도 Editor의 목록을 관리할 수 있다.
Editor와 View 차이#
- Editor와 View 모두 WorkbenchPart 클래스와 IWorkbenchPart 인터페이스는 몇 가지 공통 부분을 가지고 있다.
-
하지만 여기에 중요한 차이점이 있는데 아래와 같다.
- Editor는 'Open-Modify-Save' 패러다임을 따르는 반면, View는 수행된 Action은 즉시 작업공간과 하위 리소스의 상태에 영향을 미친다.
- Editor는 이클립스 내에서 공통 영역에 사용되는 반면에, View는 각 Perspective에 다른 영역을 사용한다.
- Editor는 일반적으로 리소스 기반으로 동작하지만, View는 단일 리소스나 복수의 리소스 또는 Memory, Network 상태, Error 등의 정보를 다루는데 사용된다.
Editor 선언#
-
Editor 생성은 Plugin Project Wizard에서 Editor 지정을 통해서 만들어 질 수 있다.
-
만약 이미 플러그인이 존재한 상태라면, 아래와 같은 방법을 사용해야 한다.
- Plugin 내역서 파일에서 Editor 정의
- EditorPart 코드 작성
- plugin.xml
- <?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
<!-- 앞에서 했던 부분 -->
<extension
point="org.eclipse.ui.views">
<category
name="QualityEclipse"
id="com.qualityeclipse.favorites">
</category>
<view
name="Favorites"
icon="icons/sample.gif"
category="com.qualityeclipse.favorites"
class="com.qualityeclipse.favorites.views.FavoritesView"
id="com.qualityeclipse.favorites.views.FavoritesView">
</view>
</extension>
<extension point="org.eclipse.ui.commands">
<category
description="Commands related to the Favorites View"
id="com.qualityeclipse.favorites.commands.category"
name="Favorites">
</category>
<command
categoryId="com.qualityeclipse.favorites.commands.category"
description="Open the Favorites view if it is not already visible"
id="com.qualityeclipse.favorites.commands.openView"
name="Open Favorites View">
</command>
<command
categoryId="com.qualityeclipse.favorites.commands.category"
description="Add selected items to the Favorites view"
id="com.qualityeclipse.favorites.commands.add"
name="Add">
</command>
...
</extension>
<extension
point="org.eclipse.ui.menus">
<menuContribution
locationURI="menu:org.eclipse.ui.main.menu?after=additions">
<menu
id="com.qualityeclipse.favorites.menus.favoritesMenu"
label="Favorites"
mnemonic="v">
<command
commandId="com.qualityeclipse.favorites.commands.openView"
icon="icons/sample.gif"
id="com.qualityeclipse.favorites.menus.openFavoritesView"
mnemonic="O">
<visibleWhen
checkEnabled="false">
<with
variable="activeContexts">
<iterate
ifEmpty="false"
operator="or">
<equals
value="com.qualityeclipse.favorites.workbenchActionSet">
</equals>
</iterate>
</with>
</visibleWhen>
</command>
</menu>
</menuContribution>
...
</extension>
<extension point="org.eclipse.ui.handlers">
<handler class="com.qualityeclipse.favorites.handlers.OpenFavoritesViewHandler"
commandId="com.qualityeclipse.favorites.commands.openView">
</handler>
...
</extension>
<extension
point="org.eclipse.ui.actionSets">
<actionSet
id="com.qualityeclipse.favorites.workbenchActionSet"
label="Favorites ActionSet"
visible="true">
</actionSet>
</extension>
<extension
point="org.eclipse.core.expressions.propertyTesters">
<propertyTester
class="com.qualityeclipse.favorites.propertyTester.FavoritesTester"
id="com.qualityeclipse.favorites.propertyTester"
namespace="com.qualityeclipse.favorites"
properties="isFavorite, notFavorite"
type="java.lang.Object">
</propertyTester>
</extension>
<extension
point="org.eclipse.ui.contexts">
<context
id="com.qualityeclipse.properties.editor.context"
name="Properties Editor Context"
parentId="org.eclipse.ui.textEditorScope">
</context>
</extension> - <!-- 단축키 지정 -->
<extension
point="org.eclipse.ui.bindings">
<key
commandId="com.qualityeclipse.favorites.commands.add"
contextId="org.eclipse.ui.textEditorScope"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="Ctrl+Shift+A">
</key>
...
</extension>
<extension
point="org.eclipse.ui.editors">
<editor
class="com.qualityeclipse.favorites.editors.PropertiesEditor"
default="false"
extensions="properties"
icon="icons/sample.gif"
id="com.qualityeclipse.properties.editor"
name="Properties Editor">
</editor>
</extension>
</plugin>
-
class
- Editor에 해당 하는 클래스로 IEditorPart를 구현하고 있음.
-
contributorClass
- Workbench 메뉴와 Toolbar에 Action을 추가하는 클래스를 지정.
-
extensions
- Editor가 지원할 파일 type을 지정한다.
- 여러개는 ','로 구분하여 입력한다.
-
icon
- Editor의 title bar에 나타나는 이미지
- id
- name
-
command
- 외부 Editor를 실행하기 위해 사용되는 명령어.
- 실행될 프로그램은 시스템 path에 잡혀있거나 plugin 디렉토리에 있어야한다.
- 이 속성과 class, luncher 속성은 상호 배타적이다 (?)
-
default (true, false)
- 생성된 editor가 extension으로 지정된 파일 유형에 대한 Default Editor로 사용할지 여부.
- 당연히 여러개의 Editor가 등록되어있을 때 의미가 있음.
- filenames
- luncher
- matchingStrategy
-
이들 지정된 값들은 아래 UI를 통해서도 수정가능하다.
EditorPart#
-
Editor를 정의하는 코드는 IEditorPart 인터페이스를 구현하는 클래스가 되어야한다.
- 이 장의 샘플로 제공되는 PropertiesEditor는 MultiPageEditorPart를 상속받고 있다.
- /**
* Editor for modifying *.property files containing content in the
* typical key=value format
*/
public class PropertiesEditor extends MultiPageEditorPart {
Editor Method #
EditorPart #
EditorPart는 MVC 모델의 Control 이라 생각하면 좋을 듯하다.
-
createPartControl(Composite)
- Editor의 Control들을 생성한다.
- /**
* The <code>MultiPageEditor</code> implementation of this
* <code>IWorkbenchPart</code> method creates the control for the
* multi-page editor by calling <code>createContainer</code>, then
* <code>createPages</code>. Subclasses should implement
* <code>createPages</code> rather than overriding this method.
*
* @param parent
* The parent in which the editor should be created; must not be
* <code>null</code>.
*/
public final void createPartControl(Composite parent) {
- createContainer()
- /**
* Creates an empty container. Creates a CTabFolder with no style bits set,
* and hooks a selection listener which calls <code>pageChange()</code>
* whenever the selected tab changes.
*
* @param parent
* The composite in which the container tab folder should be
* created; must not be <code>null</code>.
* @return a new container
*/
private CTabFolder createContainer(Composite parent) {
-
dispose()
- Editor가 닫힐 때 callback된다.
- 보통 Editor가 사용하고 있는 Resource를 반환하는 작업을 수행한다.
-
doSave(IProgressMonitor)
-
기능
- /* (non-Javadoc)
* Saves the contents of this editor.
* <p>
* Subclasses must override this method to implement the open-save-close lifecycle
* for an editor. For greater details, see <code>IEditorPart</code>
* </p>
*
* @see IEditorPart
*/
public abstract void doSave(IProgressMonitor monitor);
- /* (non-Javadoc)
- 내 용이 수정되면 Editor는 firePropertyChange(int) 메소드를 호출해서 수정되었음을 다른 구성요소에게 알려야 한다. 저장되면 다시 firePropertyChange(int)를 호출하여 Editor의 내용과 저장내용이 일치함을 등록된 Listener들에게 알린다.
-
-
doSaveAs()
- optional.
-
gotoMarker(IMarker)
- Marker가 지정한 곳으로 Editor의 cursor와 선택사항들을 반영시킨다.
- /**
* Sets the cursor and selection state for an editor to
* reveal the position of the given marker.
*/
public void gotoMarker(IMarker marker) {
-
IMarker
- /**
* Markers are a general mechanism for associating notes and meta-data with
* resources. - * ...
- */
- public interface IMarker extends IAdaptable {
/**
* Base marker type.
*
* @see #getType()
*/
public static final String MARKER = ResourcesPlugin.PI_RESOURCES + ".marker"; //$NON-NLS-1$
public static final String TASK = ResourcesPlugin.PI_RESOURCES + ".taskmarker"; //$NON-NLS-1$
public static final String PROBLEM = ResourcesPlugin.PI_RESOURCES + ".problemmarker"; //$NON-NLS-1$
public static final String TEXT = ResourcesPlugin.PI_RESOURCES + ".textmarker"; //$NON-NLS-1$
public static final String BOOKMARK = ResourcesPlugin.PI_RESOURCES + ".bookmark"; //$NON-NLS-1$
- /**
-
init(IEditorSite, IEditorInput)
- 설명
- /**
* Initializes this editor with the given editor site and input.
* This method is automatically called shortly after the part is
* instantiated, marking the start of the part's lifecycle.
* In our case, we assert that we are editing a file.
*/
public void init(IEditorSite site, IEditorInput input)
-
IEditorSite
- 으음... (?)
- /**
* The primary interface between an editor part and the workbench.
* <p>
* The workbench exposes its implemention of editor part sites via this
* interface, which is not intended to be implemented or extended by clients.
* </p>
*/
public interface IEditorSite extends IWorkbenchPartSite {
- IEditorInput
- isDirty()
- isSaveAsAllowed()
- setFocus()
MultiPageEditorPart Method#
-
addPage(Control)
- 주어진 Control을 포함하는 새 페이지를 생성하고 추가한다.
- 이 Control 인자값으로 null을 줄고, 나중에 setControl로 지정할 수 있다.
-
addPage(IEditorPart, IEditorInput)
- 설명
- /**
* Creates and adds a new page containing the given editor to this
* multi-page editor. This also hooks a property change listener on the
* nested editor.
*
* @param editor
* the nested editor
* @param input
* the input for the nested editor
* @return the index of the new page
* @exception PartInitException
* if a new page could not be created
*
* @see MultiPageEditorPart#handlePropertyChange(int) the handler for
* property change events from the nested editor
*/
public int addPage(IEditorPart editor, IEditorInput input)
- createPages()
-
getContainer()
- 추가 설명 : 이 클래스를 override 하지마라.
- /**
* Returns "the composite control" containing this multi-page editor's pages.
* This should be used as the parent when creating controls for the
* individual pages. That is, when calling <code>addPage(Control)</code>,
* the passed control should be a child of this container.
* <p>
* Warning: Clients should not assume that the container is any particular
* subclass of Composite. The actual class used may change in order to
* improve the look and feel of multi-page editors. Any code making
* assumptions on the particular subclass would thus be broken.
* </p>
* <p>
* Subclasses should not override this method
* </p>
*
* @return the composite, or <code>null</code> if
* <code>createPartControl</code> has not been called yet
*/
protected Composite getContainer() {
- setPageImage(int, Image)
- setPageText(int, String)
Editor Control(페이지 생성) #
-
이 장의 예제에서 작성하는 PropertiesEditor 코드에서 'Properties'와 'Source' 페이지를 생성한다.
-
Properties 페이지
- key, value로 구성된 데이터를 가진 Tree 구조.
-
Source 페이지
- 파일 내용을 그냥 텍스트로 보여준다.
- 위의 두 페이지는 서로 동기화 된다.
-
-
먼저 MultiPageEditorPart 클래스를 상속 받는 PropertiesEditor 클래스 생성.
- init() 메소드에서 Content Type이 생각했던 (IFileEditorInput) 타입과 같은지 체크해준다.
-
다음으로 createPages()를 overriding 하여, Source와 Properties 페이지를 넣다.
- /**
* Creates the Source and Properties pages
* of this multi-page editor.
*/
protected void createPages() {
createPropertiesPage();
createSourcePage();
updateTitle();
initTreeContent();
initTreeEditors();
createContextMenu();
initKeyBindingContext();
initUndoRedo();
}
- /**
-
createPropertiesPage()
- Properties 페이지를 생성하고,
- Column에 대해 설정하자.
- void createPropertiesPage() {
Composite treeContainer = new Composite(getContainer(), SWT.NONE);
TreeColumnLayout layout = new TreeColumnLayout();
treeContainer.setLayout(layout);
treeViewer = new TreeViewer(treeContainer, SWT.MULTI | SWT.FULL_SELECTION);
Tree tree = treeViewer.getTree();
tree.setHeaderVisible(true);
keyColumn = new TreeColumn(tree, SWT.NONE);
keyColumn.setText("Key");
layout.setColumnData(keyColumn, new ColumnWeightData(2));
valueColumn = new TreeColumn(tree, SWT.NONE);
valueColumn.setText("Value");
layout.setColumnData(valueColumn, new ColumnWeightData(3));
int index = addPage(treeContainer);
setPageText(index, "Properties");
getSite().setSelectionProvider(treeViewer);
}
-
createSourcePage()
- void createSourcePage() {
try {
textEditor = new TextEditor();
int index = addPage(textEditor, getEditorInput());
setPageText(index, "Source");
}
catch (PartInitException e) {
FavoritesLog.logError("Error creating nested text editor",e);
}
}
- void createSourcePage() {
-
updateTitle()
-
IEditorInput을 확실히 모르니 이해가 안된다...
- 그림 8-3을 보고 이해하면, 'test.properties' 라는 텍스트가 나타니는 것으로 보아서 Data 입력 파일, 즉 IEditorInput에서 사용할 부분 가리키는 것 같다.
- /**
* Update the editor's title based upon the content being edited.
*/
void updateTitle() {
IEditorInput input = getEditorInput();
setPartName(input.getName());
setTitleToolTip(input.getToolTipText());
}
-
setPartName()
- /**
* Sets the name of this part. The name will be shown in the tab area for
* the part. Clients should call this method instead of overriding getPartName.
* Setting this to the empty string will cause a default part name to be used.
*
* <p>
* setPartName and setContentDescription are intended to replace setTitle.
* This may change a value that was previously set using setTitle.
* </p>
*
* @param partName the part name, as it should be displayed in tabs.
*
* @since 3.0
*/
protected void setPartName(String partName) {
- /**
-
- setFocus()
- gotoMarker()
- isSaveAsAllowed()
Editor Model(Data) #
-
이제 데이터의 내용을 Properties Page의 Tree에 넣어보자.
- 먼저 Model을 만들고,
- 이것을 절적히 출력하기 위해서 ContentProvider와 LabelProvier를 구현해야한다.
ContentProvider는 Data를 표현하고, LabelProvider는 이것을 어떻게 보여질지에 대해서 구현하는 클래스로 이해하면 되지 않을까?
A : 비슷하네..
Page.341
- content provider extracts property elements to be displayed
- LabelProvider로 부터 얻은 행 요소 객체를 각 셀에 출력할 이미지와 텍스트로 변환한다.
-
추가 구현 사항
-
텍스트 파서를 좀 더 잘 만들어보자.
- 독립된 클래스로 만들고,
- 여러 줄로 구성된 값도 해석하는 기능을 추가해보자.
-
-
PropertyElement
- PropertyElement의 abstract 클래스.
-
PropertyEntry
- public class PropertyEntry extends PropertyElement
- Property 파일의 데이터를 key, value 쌍으로 표현하기 위한 클래스.
-
PropertyCategory
- public class PropertyCategory extends PropertyElement
- Property 항목의 그룹을 나타내기 위한 클래스.
- 그룹명은 '#xxx' 형식으로 얻는다.
-
PropertyFile
- /**
* The editor model for a property file.
*/
public class PropertyFile extends PropertyElement
- PropertyEntry와 PropertyCategory를 가지고 클래스.
-
PropertyFileListener 인터페이스를 사용
- 등록된 Listener(PropertiesEditor 등)에 모델(Data)이 변경되었음을 알리는 이벤트를 전달한다.
- private List<PropertyFileListener> listeners;
- ...
- void addPropertyFileListener(PropertyFileListener listener) {
if (!listeners.contains(listener))
listeners.add(listener);
}
- /**
ContentProvider #
-
ContentProvider는 Tree에 나타날 행들을 Parent/Child 관계에 따라 제공하지만, 셀 단위의 내용을 제공하지는 않는다.
- 셀 단위의 내용은 LabelProvider에서 제공한다.
- /**
* A content provider mediates between the viewer's model and the
* viewer itself. In our case, this content provider extracts property
* elements to be displayed one per row in the editor.
*/
public class PropertiesEditorContentProvider
implements ITreeContentProvider
LabelProvider #
-
ContentProvider로 부터 얻은 행 요소 객체를 각 셀에 출력할 이미지와 텍스트로 변환한다.
- /**
* A label provider maps an element of the viewer's model to an
* optional image and optional text string used to display the element * in the viewer's control. In our case, this label provider extracts
* text from the {@link PropertyElement} to display in the editor.
*/
public class PropertiesEditorLabelProvider extends LabelProvider
implements ITableLabelProvider
{
- /**
ContentProvider와 LabelProvider를 연결 #
-
위에서 만든 PropertyFile, ContentProvider, LabelProvider를 사용해서
- TextEditor로부터 데이터를 읽어서 TreeView에 뿌려보자.
-
아래 createPages()에서 호출하고 있다.
- protected void createPages() {
createPropertiesPage();
createSourcePage();
updateTitle();
initTreeContent();
...
}
- protected void createPages() {
-
initTreeContent()
- /**
* Initialize the model behind the editor.
*/
void initTreeContent() {
treeContentProvider = new PropertiesEditorContentProvider();
treeViewer.setContentProvider(treeContentProvider);
treeLabelProvider = new PropertiesEditorLabelProvider();
treeViewer.setLabelProvider(treeLabelProvider);
// Reset the input from the text editor content
// after the editor initialization has completed.
treeViewer.setInput(new PropertyFile(""));
treeViewer.getTree().getDisplay().asyncExec(new Runnable() {
public void run() {
updateTreeFromTextEditor();
}
});
treeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);
}
- /**
-
updateTreeFromTextEditor()
- TextEditor가 input 데이터가 된다.
- /**
* Called when the properties page should be updated
* based upon new input from the source page
*/
void updateTreeFromTextEditor() {
PropertyFile propertyFile = (PropertyFile) treeViewer.getInput();
propertyFile.removePropertyFileListener(propertyFileListener);
propertyFile = new PropertyFile(
textEditor
.getDocumentProvider()
.getDocument(textEditor.getEditorInput())
.get());
treeViewer.setInput(propertyFile);
propertyFile.addPropertyFileListener(propertyFileListener);
}
-
위의 코드에서 왜 propertyFile.removePropertyFileListener(), propertyFile.addPropertyFileListener()를 호출하는지 궁금하지 않는가?
- 뒤에서 설명.
Edit #
-
Properties 페이지에서 내용을 수정할 수 있도록 해보자.
- 참고 : Text Editor에서 Content를 다루는 예제는 14.2.4절 '마커 해결-빠른 수정' (p520을 참고)
- protected void createPages() {
...
initTreeContent();
initTreeEditors();
...
}
Cell Editor #
-
Cell Editor는 특정 객체에서 어떤 부분을 편집.
-
수정
- getCellEditor() 셀 Editor 정의
- canEdit()
- getValue()
- setValue()
-
Cell Change 리스너.
- ICellEditorListener.
-
Cell Validator
- ICellEditorValidator.
-
Cell Editor 활성화
- addEditorActivationListener()
-
- /**
* Initialize the cell editors in the tree
*/
private void initTreeEditors() {
TreeViewerColumn column1 = new TreeViewerColumn(treeViewer, keyColumn);
TreeViewerColumn column2 = new TreeViewerColumn(treeViewer, valueColumn);
column1.setLabelProvider(new ColumnLabelProvider() {
public String getText(Object element) {
return treeLabelProvider.getColumnText(element, 0);
}
});
...
column1.setEditingSupport(new EditingSupport(treeViewer) {
TextCellEditor editor = null;
protected boolean canEdit(Object element) {
return true;
}
protected CellEditor getCellEditor(Object element) {
if (editor == null) {
Composite tree = (Composite) treeViewer.getControl();
editor = new TextCellEditor(tree); - /* Cell Validator */
editor.setValidator(new ICellEditorValidator() {
public String isValid(Object value) {
if (((String) value).trim().length() == 0)
return "Key must not be empty string";
return null;
}
}); - /* 사용자가 잘못된 값을 입력했을 때 어떻게 알려줄지를 구현한다. */
editor.addListener(new ICellEditorListener() {
public void applyEditorValue() {
setErrorMessage(null);
}
public void cancelEditor() {
setErrorMessage(null);
}
public void editorValueChanged(
boolean oldValidState,
boolean newValidState) {
setErrorMessage(editor.getErrorMessage());
}
private void setErrorMessage(String errorMessage) {
getEditorSite().getActionBars()
.getStatusLineManager()
.setErrorMessage(errorMessage);
}
});
}
return editor;
}
protected Object getValue(Object element) {
return treeLabelProvider.getColumnText(element, 0);
}
protected void setValue(Object element, Object value) {
if (value == null)
return;
String text = ((String) value).trim();
if (element instanceof PropertyCategory)
((PropertyCategory) element).setName(text);
if (element instanceof PropertyEntry)
((PropertyEntry) element).setKey(text);
}
}); - /* Alt 눌렀을 때, Cell을 Editor할 수 있다. */
- treeViewer.getColumnViewerEditor().addEditorActivationListener(
new AltClickCellEditListener()); - }
Editor life cycle #
- 일반적으로 Editor는 'Open-Modify-Save-Close'와 같은 life cycle을 가진다.
- Editor Open시에 init(IeditorSite, IEditorInput) 메소드를 호출해서 편집기의 기본 Content를 설정한다.
-
Content가 수정되면, Editor는 firePropertyChange(int) 메소드를 호출해서 수정되었음을 다른 구성요소에 알려야 한다.
-
dirty 값이 설정되어있을 때, 상황에 따라 여러 동작을 한다.
- Editor title bar 수정
- title bar 앞에 '*' 붙이기
- 'Save' 메뉴 활성화
-
- Editor Close시에 dirty 값이 true이면 Content를 저장한다.
수정사항이 있는 Editor #
-
수정이 있을 때,
- 마지막 저장후에 Content가 수정되었는지 확인할 수 있어야한다.
- /**
* Called when a cell editor has modified the editor model.
*/
public void treeModified() {
boolean wasDirty = isDirty();
isPageModified = true;
if (!wasDirty)
firePropertyChange(IEditorPart.PROP_DIRTY);
}
-
Source 페이지(Text Editor)가 수정되었을 때 Property 페이지에서 인지하기 위해서.
- /**
* Handles a property change notification from a nested editor. In
* our case, the <code>isPageModified</code> field is adjusted as
* appropriate and superclass is called to notify listeners of the
* change.
*/
protected void handlePropertyChange(int propertyId) {
if (propertyId == IEditorPart.PROP_DIRTY)
isPageModified = isDirty();
super.handlePropertyChange(propertyId);
}
- /**
-
MultiPageEditorPart의 경우.
- addPage() 메소드에서 Editor가 수정될 때마다 다른 Part 들에게 알린다.
- /**
* Creates and adds a new page containing the given editor to this
* multi-page editor. The page is added at the given index. This also hooks
* a property change listener on the nested editor.
*
* ...
* @see MultiPageEditorPart#handlePropertyChange(int) the handler for
* property change events from the nested editor
*/
public void addPage(int index, IEditorPart editor, IEditorInput input)
throws PartInitException {
IEditorSite site = createSite(editor);
// call init first so that if an exception is thrown, we have created no
// new widgets
editor.init(site, input);
Composite parent2 = new Composite(getContainer(),
getOrientation(editor));
parent2.setLayout(new FillLayout());
editor.createPartControl(parent2);
editor.addPropertyListener(new IPropertyListener() {
public void propertyChanged(Object source, int propertyId) {
MultiPageEditorPart.this.handlePropertyChange(propertyId);
}
});
// create item for page only after createPartControl has succeeded
Item item = createItem(index, parent2);
// remember the editor, as both data on the item, and in the list of
// editors (see field comment)
item.setData(editor);
nestedEditors.add(editor);
}
페이지 전환 #
-
Property와 Source 페이지 사이에서 전환할 때는 Properties 페이지에서 수정된 내용을 자동으로 Source 페이지로 반영시켜야 하며 반대로도 동작해야 한다.
- 이 구현을 위해서 pageChange(int) 메소드를 override 해야한다.
- /**
* Notifies this multi-page editor that the page with the given id has been
* activated. This method is called when the user selects a different tab.
*/
protected void pageChange(int newPageIndex) {
switch (newPageIndex) {
case 0 :
if (isDirty())
updateTreeFromTextEditor();
setTreeUndoRedo();
break;
case 1 :
if (isPageModified)
updateTextEditorFromTree();
setTextEditorUndoRedo();
break;
}
isPageModified = false;
super.pageChange(newPageIndex);
}
Save Content #
-
현재 구현은 Text Editor에서 Content를 파일에 저장하고 있기 때문에, Properties 페이지의 변경 사항이 사용자가 Source 페이지로 전환할 때까지 저장되지 않는다.
- 그래서 저장하기 전에 Text Editor의 내용을 갱신하도록 수정하자.
- 이 때, 이 작업을 IProgressMonitor를 사용하여 구현하자.
- /**
* Saves the contents of this part. If the save is successful, the
* part should fire a property changed event reflecting the new
* dirty state (<code>PROP_DIRTY</code> property).
*/
public void doSave(IProgressMonitor monitor) {
if (getActivePage() == 0 && isPageModified)
updateTextEditorFromTree();
isPageModified = false;
textEditor.doSave(monitor);
}
Editor Action #
-
Context Menu
- 액션 생성, Context Menu 작성, Context Menu 동적 구성
-
Editor Contributor
- Global Action
- top-level Menu
- toolbar button
- keyboard action
- Undo, Redo
Editor 연결 #
RFRS guideline. #
- /**
* Returns the input for this editor. If this value changes the part must
* fire a property listener event with <code>PROP_INPUT</code>.
*
* @return the editor input
*/
public IEditorInput getEditorInput();
/**
* Returns the site for this editor.
* This method is equivalent to <code>(IEditorSite) getSite()</code>.
* <p>
* The site can be <code>null</code> while the editor is being initialized.
* After the initialization is complete, this value must be non-<code>null</code>
* for the remainder of the editor's life cycle.
* </p>
*
* @return the editor site; this value may be <code>null</code> if the editor
* has not yet been initialized
*/
public IEditorSite getEditorSite();
/**
* Initializes this editor with the given editor site and input.
* <p>
* This method is automatically called shortly after the part is instantiated.
* It marks the start of the part's lifecycle. The
* {@link IWorkbenchPart#dispose IWorkbenchPart.dispose} method will be called
* automically at the end of the lifecycle. Clients must not call this method.
* </p><p>
* Implementors of this method must examine the editor input object type to
* determine if it is understood. If not, the implementor must throw
* a <code>PartInitException</code>
* </p>
* @param site the editor site
* @param input the editor input
* @exception PartInitException if this editor was not initialized successfully
*/
public void init(IEditorSite site, IEditorInput input)
throws PartInitException;
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.