/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.editor; import java.io.*; import java.text.MessageFormat; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.jboss.tools.common.core.resources.XModelObjectEditorInput; import org.jboss.tools.common.model.util.XModelTreeListenerSWTSync; import org.jboss.tools.common.model.ui.outline.XModelObjectContentOutlineProvider; import org.jboss.tools.common.model.ui.select.XModelObjectSelectionProvider; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.*; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.*; import org.eclipse.ui.*; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.dialogs.SaveAsDialog; import org.eclipse.ui.editors.text.TextEditor; import org.eclipse.ui.ide.IGotoMarker; import org.eclipse.ui.part.MultiPageEditorActionBarContributor; import org.eclipse.ui.part.MultiPageEditorPart; import org.eclipse.ui.part.MultiPageEditorSite; import org.eclipse.ui.texteditor.AbstractTextEditor; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.IDocumentProviderExtension; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import org.eclipse.wst.sse.ui.StructuredTextEditor; import org.jboss.tools.common.meta.action.XAction; import org.jboss.tools.common.meta.action.XActionInvoker; import org.jboss.tools.common.model.XModel; import org.jboss.tools.common.model.XModelException; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.event.XModelTreeEvent; import org.jboss.tools.common.model.event.XModelTreeListener; import org.jboss.tools.common.model.filesystems.FileSystemsHelper; import org.jboss.tools.common.model.filesystems.impl.FileAnyImpl; import org.jboss.tools.common.model.filesystems.impl.FileSystemImpl; import org.jboss.tools.common.model.filesystems.impl.FolderImpl; import org.jboss.tools.common.model.options.Preference; import org.jboss.tools.common.model.options.PreferenceModelUtilities; import org.jboss.tools.common.model.plugin.ModelPlugin; import org.jboss.tools.common.model.project.IModelNature; import org.jboss.tools.common.model.util.EclipseResourceUtil; import org.jboss.tools.common.model.util.XModelObjectCache; import org.jboss.tools.common.model.ui.ModelUIPlugin; import org.jboss.tools.common.model.ui.editor.IModelObjectEditorInput; import org.jboss.tools.common.text.ext.IMultiPageEditor; public class ObjectMultiPageEditor extends MultiPageEditorPart implements XModelTreeListener, IGotoMarker, IMultiPageEditor { protected AbstractSectionEditor treeEditor; protected TreeFormPage treeFormPage; protected ObjectTextEditor textEditor; protected IModelObjectEditorInput input; protected XModel model = null; protected XModelObjectCache cache = null; protected XModelObject object = null; protected long timeStamp = -1; protected long lastModifiedTimeStamp = -1; protected boolean isErrorMode = false; protected XModelTreeListenerSWTSync syncListener = new XModelTreeListenerSWTSync(this); public XModelObjectContentOutlineProvider outline = new XModelObjectContentOutlineProvider(); private ActivationListener fActivationListener= new ActivationListener(); protected XModelObjectSelectionProvider selectionProvider = new XModelObjectSelectionProvider(); protected NatureChecker natureChecker = new NatureChecker(); protected ObjectEditorErrorTickUpdater errorTickUpdater; private QualifiedName persistentTabQualifiedName = new QualifiedName("", "Selected_tab"); //$NON-NLS-1$ //$NON-NLS-2$ int selectedPageIndex = 0; public ObjectMultiPageEditor() { errorTickUpdater = new ObjectEditorErrorTickUpdater(this); } public void init(IEditorSite site, IEditorInput input) throws PartInitException { natureChecker.check(input, getSupportedNatures(), getNatureWarningMessageKey()); super.init(site, natureChecker.input); IWorkbenchWindow window= getSite().getWorkbenchWindow(); window.getPartService().addPartListener(fActivationListener); window.getShell().addShellListener(fActivationListener); } protected void setInput(IEditorInput input) { super.setInput(XModelObjectEditorInput.checkInput(input)); updateFile(); if(Display.getCurrent() == null) { Display.getDefault().asyncExec(new Runnable(){ public void run() { firePropertyChange(IEditorPart.PROP_INPUT); } }); } else { firePropertyChange(IEditorPart.PROP_INPUT); } if (errorTickUpdater != null && getFile() != null) { errorTickUpdater.updateEditorImage(getFile()); } } protected IEditorSite createSite(IEditorPart editor) { if(editor instanceof ITextEditor) { return new PostMultiPageEditorSite(this, editor); } else { return new MultiPageEditorSite(this, editor); } } public boolean isAppropriateNature() { return natureChecker.isAppropriateNature; } /** * Returns list of natures, of which at least one is necessary to * open gui tabs of the editor. Null value is equivalent to list of * all natures implementing IModelNature. Empty array is equivalent * to turning the check off. */ protected String[] getSupportedNatures() { return null; } /** * Returns key for a warning message displayed if project does not * have a supported nature. */ protected String getNatureWarningMessageKey() { return "SharableEditors.natureWarning.message"; //$NON-NLS-1$ } private void updateFile() { IFile file = getFile(); if(file != null) try { file.refreshLocal(0, null); } catch (CoreException e) { //ignore } } private IFile getFile() { IEditorInput input = getEditorInput(); return (input instanceof IFileEditorInput) ? ((IFileEditorInput)input).getFile() : null; } private void loadSelectedTab() { IFile file = getFile(); try { if("yes".equals(PreferenceModelUtilities.getPreferenceModel().getByPath(Preference.EDITOR_PATH).getAttributeValue("selectSourceTab"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ selectedPageIndex = getSourcePageIndex(); } else if(file == null) { loadSelectedTabForStorage(); } else { String q = file.getPersistentProperty(persistentTabQualifiedName); selectedPageIndex = (q == null) ? 0 : Integer.parseInt(q); } } catch (NumberFormatException e) { selectedPageIndex = 0; } catch (CoreException e) { selectedPageIndex = 0; } } private void loadSelectedTabForStorage() { if(object == null) return; String path = object.getPath(); QualifiedName qn = new QualifiedName("", "Selected_tab_" + path); //$NON-NLS-1$ //$NON-NLS-2$ IProject p = EclipseResourceUtil.getProject(object); if(p == null || !p.isOpen()) return; try { String q = p.getPersistentProperty(qn); selectedPageIndex = (q == null) ? 0 : Integer.parseInt(q); } catch (NumberFormatException e) { //ignore selectedPageIndex = 0; } catch (CoreException e) { //ignore selectedPageIndex = 0; } } private void saveSelectedTab() { IFile file = getFile(); if(file == null) { saveSelectedTabForStorage(); } else { try { if(file.isAccessible()) file.setPersistentProperty(persistentTabQualifiedName, "" + selectedPageIndex); //$NON-NLS-1$ } catch (CoreException e) { ModelUIPlugin.getPluginLog().logError(e); } } } private void saveSelectedTabForStorage() { if(object == null) return; IProject p = EclipseResourceUtil.getProject(object); if(p == null || !p.isOpen()) return; String path = object.getPath(); QualifiedName qn = new QualifiedName("", "Selected_tab_" + path); //$NON-NLS-1$ //$NON-NLS-2$ try { p.setPersistentProperty(qn, "" + selectedPageIndex); //$NON-NLS-1$ } catch (CoreException e) { //ignore } } public final boolean isWrongEntity() { return getModelObject() != null && isWrongEntity(getModelObject().getModelEntity().getName()); } protected boolean isWrongEntity(String entity) { return false; } protected XModelObject getModelObject() { return (cache == null) ? null : cache.getObject(); } protected void createPages() { IEditorInput _input = getEditorInput(); setPartName(_input.getName()); if(!(_input instanceof IModelObjectEditorInput)) { createUnloadedPage(); return; } input = (IModelObjectEditorInput)getEditorInput(); object = input.getXModelObject(); timeStamp = (object == null) ? -1 : object.getTimeStamp(); lastModifiedTimeStamp = (object == null || object.isModified()) ? -1 : object.getLastModificationTimeStamp(); cache = new XModelObjectCache(object); outline.setCache(cache); model = object.getModel(); getSite().setSelectionProvider(selectionProvider); doCreatePages(); model.addModelTreeListener(syncListener); loadSelectedTab(); if(selectedPageIndex < getPageCount()) { setActivePage(selectedPageIndex); } updateSelectionProvider(); new ResourceChangeListener(this, getContainer()); } public void selectPageByName(String name) { if(name == null) return; for (int i = 0; i < getPageCount(); i++) { String h = getPageText(i); if(name.equals(h)) { if(selectedPageIndex == i) return; selectedPageIndex = i; switchToPage(i); } } } protected void createUnloadedPage() { createTextPage(); } protected void doCreatePages() { } protected void createTreePage() { installTreePage(new TreeGuiEditor()); } protected void createTextPage() { textEditor = createTextEditor(); try { int index = addPage((IEditorPart)textEditor, getEditorInput()); setPageText(index, ObjectMultiPageEditorMessages.PAGES_EDITOR_SOURCE_TAB); textEditor.setObject(object); textEditor.addFocusListener(new TextFocusListener()); outline.addSelectionChangedListener(new OutlineSelectionListener()); } catch (PartInitException ex) { ModelUIPlugin.getPluginLog().logError(ex); textEditor = null; } } class OutlineSelectionListener implements ISelectionChangedListener { boolean isFiringToSource = false; public void selectionChanged(SelectionChangedEvent event) { if(isFiringToSource) return; ISelection s = event.getSelection(); if(s.isEmpty() || !(s instanceof IStructuredSelection)) return; /// if(getActivePage() != getSourcePageIndex()) return; if(selectionProvider.isFiringSelection() && getActivePage() == getSourcePageIndex()) return; if(outline.getControl() == null || outline.getControl().isDisposed()) return; boolean isFocused = outline.getControl().isFocusControl(); if(isFocused) { isFiringToSource = true; selectionProvider.setSelection(event.getSelection()); isFiringToSource = false; return; } if(!isFocused && getActivePage() == getSourcePageIndex()) { return; } Object o = ((IStructuredSelection)s).getFirstElement(); if(!(o instanceof XModelObject)) return; XModelObject so = (XModelObject)o; isFiringToSource = true; postponedTextSelection.select(so, null); isFiringToSource = false; } } protected final void installTreePage(AbstractSectionEditor treeEditor) { this.treeEditor = treeEditor; Control control = treeEditor.createControl(getContainer()); treeEditor.addErrorSelectionListener(createErrorSelectionListener()); int index = addPage(control); setPageText(index, "Tree"); selectionProvider.addHost("treeEditor", treeEditor.getSelectionProvider()); //$NON-NLS-1$ } protected ObjectTextEditor createTextEditor() { return null; } public boolean isDirty() { if(super.isDirty()) return true; if(input == null) return false; XModelObject o = getModelObject(); if( (o != null && lastModifiedTimeStamp != o.getLastModificationTimeStamp()) || (textEditor != null && textEditor.isModified())) return true; return false; } public void doSave(IProgressMonitor monitor) { if(input == null) { if(textEditor != null) textEditor.save(); return; } if(!checkReadOnlyOnSave()) { if(monitor != null) monitor.setCanceled(true); return; } lock2 = false; try { if(textEditor != null && textEditor.isModified()) { textEditor.save(); } XModelObject o = getModelObject(); if(o == null || !o.isActive()) return; XModelObject p = o.getParent(); if(!(p instanceof FolderImpl)) return; FolderImpl f = (FolderImpl)p; if (treeFormPage!=null) { treeFormPage.doSave(monitor); } this.enableSanityChecking(false); try { f.saveChild(o); } catch (XModelException e) { ModelPlugin.getPluginLog().logError(e); } this.updateModificationStamp(this.getEditorInput()); this.enableSanityChecking(true); if(textEditor != null) textEditor.setModified(false); lastModifiedTimeStamp = o.getLastModificationTimeStamp(); firePropertyChange(IEditorPart.PROP_DIRTY); saveX(monitor); f.updateRegistration(o); } finally { lock2 = false; } } /** * FIXME remove Java reflection calls * @param monitor */ void saveX(IProgressMonitor monitor) { if(!(textEditor instanceof AbstractTextEditor)) return; try { Method m = AbstractTextEditor.class.getDeclaredMethod("performSave", new Class[]{boolean.class, IProgressMonitor.class}); //$NON-NLS-1$ m.setAccessible(true); m.invoke(textEditor, new Object[]{Boolean.TRUE, monitor}); } catch (SecurityException e) { ModelUIPlugin.getPluginLog().logError(e); } catch (NoSuchMethodException e) { ModelUIPlugin.getPluginLog().logError(e); } catch (IllegalArgumentException e) { ModelUIPlugin.getPluginLog().logError(e); } catch (InvocationTargetException e) { ModelUIPlugin.getPluginLog().logError(e); } catch (IllegalAccessException e) { ModelUIPlugin.getPluginLog().logError(e); } } public void doSaveAs() { performSaveAs(null); } public void gotoMarker(IMarker marker) { if(marker == null || getModelObject() == null || !marker.exists()) return; String path = marker.getAttribute("path", null); //$NON-NLS-1$ if(path != null) { XModelObject o = getModelObject().getModel().getByPath(path); if(o == null) return; XModelObject f = FileSystemsHelper.getFile(o); if(f != null && f != object && object.getFileType() == XModelObject.FILE && getFile() != null && getFile().equals(f.getAdapter(IFile.class))) { if(f == o) { o = object; } else { o = object.getChildByPath(o.getPath().substring(f.getPath().length() + 1)); if(o == null) { return; } } } selectionProvider.setSelection(new StructuredSelection(o)); //tab=Tree is set to prevent switching to Source tab. if(!"Tree".equals(marker.getAttribute("tab", null))) { //$NON-NLS-1$ //$NON-NLS-2$ switchToPage(getSourcePageIndex()); } postponedTextSelection.clean(); if(marker.getAttribute(IMarker.LINE_NUMBER, -1) != -1) { if(textEditor != null) textEditor.gotoMarker(marker); } else { String attr = marker.getAttribute("attribute", ""); //$NON-NLS-1$ //$NON-NLS-2$ if(attr == null || attr.length() == 0) { postponedTextSelection.select(o, null); } else { postponedTextSelection.select(o, attr); } } } else { postponedTextSelection.clean(); if(textEditor != null) { switchToPage(getSourcePageIndex()); textEditor.gotoMarker(marker); } } } protected void switchToPage(int page) { if (getActivePage() != page && page >= 0) { setActivePage(page); pageChange(page); } } protected boolean isErrorMode() { return isErrorMode; } public boolean isSaveAsAllowed() { return true; } public void dispose() { saveSelectedTab(); super.dispose(); if(model == null) return; model.removeModelTreeListener(syncListener); model = null; if (syncListener!=null) syncListener.dispose(); syncListener = null; if(treeFormPage != null) treeFormPage.dispose(); if(treeEditor != null) treeEditor.disposeGui(); if (fActivationListener != null) { IWorkbenchWindow window= getSite().getWorkbenchWindow(); window.getPartService().removePartListener(fActivationListener); Shell shell= window.getShell(); if (shell != null && !shell.isDisposed()) shell.removeShellListener(fActivationListener); fActivationListener= null; } XModelObject o = getModelObject(); if(o != null && o.isModified() && o.isActive()) { try { XAction action = XActionInvoker.getAction("DiscardActions.Discard", object); //$NON-NLS-1$ if(action != null) { // to avoid confirmation action.executeHandler(object, null); } else if(object.getParent() instanceof FolderImpl) { ((FolderImpl)object.getParent()).discardChildFile(object); } } catch (XModelException e) { ModelPlugin.getPluginLog().logError(e); } } if (outline!=null) outline.dispose(); outline = null; if(errorTickUpdater != null) { errorTickUpdater.dispose(); errorTickUpdater = null; } } protected void initEditors() { checkErrorMode(); if(isErrorMode) { setErrorMode(); } else { setNormalMode(); } if(textEditor != null) textEditor.setObject(object); } boolean lock2 = false; boolean waitForMerge = false; public void nodeChanged(XModelTreeEvent event) { if(lock2) return; if(event.getDetails() == XModelTreeEvent.BEFORE_MERGE && event.getModelObject() == getModelObject()) { waitForMerge = true; return; } if(event.getDetails() == XModelTreeEvent.AFTER_MERGE && event.getModelObject() == getModelObject()) { waitForMerge = false; } if(waitForMerge) return; if(needsUpdate()) { Display.getDefault().syncExec(new U()); } } public void structureChanged(XModelTreeEvent event) { if(lock2) return; if(waitForMerge) return; if((event.getModelObject() instanceof FileSystemImpl || event.getDetails() instanceof FileSystemImpl) && getFile() != null && getFile().exists() && getEditorInput() instanceof XModelObjectEditorInput) { XModelObjectEditorInput ei = (XModelObjectEditorInput)getEditorInput(); if(ei.updateXModelObject()) { lock2 = true; try { XModelObject o = ei.getXModelObject(); if(textEditor != null) textEditor.setObject(o); object = o; setInput(ei); lastModifiedTimeStamp = (object == null || object.isModified()) ? -1 : object.getLastModificationTimeStamp(); cache = new XModelObjectCache(object); outline.setCache(cache); model = object.getModel(); updateTitle(); timeStamp = -1; update0(); } finally { lock2 = false; } } } if(needsUpdate()) { Display.getDefault().syncExec(new U()); } } class U implements Runnable { public void run() { lock2 = true; try { update0(); while(needsUpdate()) { update0(); } } finally { lock2 = false; } } } protected boolean needsUpdate() { XModelObject o = getModelObject(); if(o == object && (o == null || o.getTimeStamp() == timeStamp)) { if(o != null && o.getLastModificationTimeStamp() != lastModifiedTimeStamp) { if(!o.isModified()) lastModifiedTimeStamp = o.getLastModificationTimeStamp(); firePropertyChange(IEditorPart.PROP_DIRTY); if(textEditor != null) textEditor.updateModification(); } return false; } object = o; timeStamp = (o == null) ? -1 : o.getTimeStamp(); return true; } public void update0() { // setContentDescription(getEditorInput().getName()); setPartName(getEditorInput().getName()); checkErrorMode(); if(isErrorMode) { setErrorMode(); } else { setNormalMode(); } if(textEditor != null) textEditor.updateDocument(); } protected void setErrorMode() { } protected void setNormalMode() { } protected void checkErrorMode() { if(object == null) return; boolean i = isWrongEntity() || "yes".equals(object.get("isIncorrect")); //$NON-NLS-1$ //$NON-NLS-2$ if(isErrorMode == i) return; isErrorMode = i; } public Object getAdapter(Class adapter) { if(adapter != null && adapter.isAssignableFrom(IContentOutlinePage.class)) { if(input == null) { return null; } return outline; } else if(ITextEditor.class == adapter) { if(textEditor instanceof ITextEditor) return textEditor; } return super.getAdapter(adapter); } class TextFocusListener extends FocusAdapter { public void focusLost(FocusEvent e) { if(!textEditor.isModified()) return; Display.getDefault().syncExec( new Runnable() { public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { //ignore } textEditor.save(); } } ); } } protected ErrorSelectionListener createErrorSelectionListener() { return new ErrorSelectionListenerImpl(); } class ErrorSelectionListenerImpl implements ErrorSelectionListener { public void errorSelected(int line, int position) { doErrorSelected(line, position); } } protected int getSourcePageIndex() { return getPageCount() - 1; } void doErrorSelected(int line, int position) { setActivePage(getSourcePageIndex()); pageChange(getSourcePageIndex()); if(textEditor != null) textEditor.setCursor(line, position); } public void activateErrorTab() { setActivePage(0); } protected void updateEditableMode() { } public IEditorPart getActiveEditor() { return super.getActiveEditor(); } public StructuredTextEditor getSourceEditor() { if(textEditor instanceof StructuredTextEditor) { return (StructuredTextEditor)textEditor; } return null; } TextSelectionProvider textSelectionProvider = new TextSelectionProvider(); protected AbstractSelectionProvider getTextSelectionProvider() { textSelectionProvider.init(); return textSelectionProvider; } private class TextSelectionProvider extends AbstractSelectionProvider implements ISelectionChangedListener { boolean inites = false; public void init() { if(inites) return; inites = true; if(textEditor instanceof TextEditor) { ((TextEditor)textEditor).getSelectionProvider().addSelectionChangedListener(this); } } protected XModelObject getSelectedModelObject() { XModelObject o = textEditor == null ? null : textEditor.findModelObjectAtCursor(); if(o != null) return o; return getModelObject(); } protected void setSelectedModelObject(XModelObject object) { postponedTextSelection.select(object, null); } public void selectionChanged(SelectionChangedEvent event) { fireSelectionChanged(); } public void dispose() { if(textEditor instanceof TextEditor) { ((TextEditor)textEditor).getSelectionProvider().removeSelectionChangedListener(this); } } } /** * Internal part and shell activation listener for triggering state validation. * @since 2.0 */ class ActivationListener extends ShellAdapter implements IPartListener { private IWorkbenchPart fActivePart; private boolean fIsHandlingActivation= false; public void partActivated(IWorkbenchPart part) { fActivePart= part; handleActivation(); if(getActivePage() != getSourcePageIndex() && textEditor != null && textEditor.isModified()) { textEditor.save(); } } public void partBroughtToTop(IWorkbenchPart part) {} public void partClosed(IWorkbenchPart part) {} public void partDeactivated(IWorkbenchPart part) { fActivePart= null; } public void partOpened(IWorkbenchPart part) {} public void shellActivated(ShellEvent e) { updateEditableMode(); /* * Workaround for problem described in * http://dev.eclipse.org/bugs/show_bug.cgi?id=11731 * Will be removed when SWT has solved the problem. */ e.widget.getDisplay().asyncExec(new Runnable() { public void run() { handleActivation(); if(textEditor != null && textEditor.isModified()) { textEditor.save(); } } }); } private void handleActivation() { if (fIsHandlingActivation) return; if (fActivePart != null && fActivePart.getSite() == getSite()) { fIsHandlingActivation= true; try { doSanityCheckState(getEditorInput()); } finally { fIsHandlingActivation= false; } } } }; private long fModificationStamp= -1; private boolean fIsSanityCheckEnabled= true; protected void enableSanityChecking(boolean enable) { synchronized (this) { fIsSanityCheckEnabled= enable; } } protected void safelySanityCheckState(IEditorInput input) { boolean enabled= false; synchronized (this) { enabled= fIsSanityCheckEnabled; } if (enabled) doSanityCheckState(input); } protected boolean doSanityCheckState(IEditorInput input) { if (input == null) return false; if (input instanceof IFileEditorInput) { IFile iFile = ((IFileEditorInput)input).getFile(); if (iFile == null) return false; File f = (iFile.getLocation() == null ? null : iFile.getLocation().toFile()); if (f == null) return false; if (fModificationStamp == -1) fModificationStamp= f.lastModified(); long stamp= f.lastModified(); try { handleEditorInputChanged(); } catch (XModelException e) { ModelPlugin.getPluginLog().logError(e); } if (stamp != fModificationStamp) { fModificationStamp= stamp; // handleEditorInputChanged(); return true; } } return false; } private void updateModificationStamp(IEditorInput input) { try { if(input instanceof IFileEditorInput) { this.fModificationStamp = ((IFileEditorInput)input).getFile() .getLocation().toFile().lastModified(); } } finally { this.fModificationStamp = -1; } } private void handleEditorInputChanged() throws XModelException { XModelObject o = getModelObject(); if(o == null) return; if(input instanceof IFileEditorInput && o.getParent() instanceof FolderImpl) { FolderImpl f = (FolderImpl)o.getParent(); IFile file = ((IFileEditorInput)input).getFile(); if(file.isSynchronized(IResource.DEPTH_ZERO)) return; f.updateChildFile(o, file.getLocation().toFile()); if(textEditor instanceof ITextEditor) { IDocumentProvider provider = ((ITextEditor)textEditor).getDocumentProvider(); if(provider instanceof IDocumentProviderExtension) { IDocumentProviderExtension extension= (IDocumentProviderExtension) provider; try { extension.synchronize(input); } catch (CoreException e) { ModelUIPlugin.getDefault().logError(e); } } } else { try { file.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); } catch (CoreException e) { ModelUIPlugin.getDefault().logError(e); } } f.setModified(false); firePropertyChange(ITextEditor.PROP_DIRTY); } } PostponedTextSelection postponedTextSelection = new PostponedTextSelection(); class PostponedTextSelection implements Runnable { XModelObject selected = null; String attribute = null; boolean _lock = false; public void clean() { selected = null; attribute = null; } public void select(XModelObject object, String attr) { if(textEditor == null || _lock) return; if(getActivePage() == getSourcePageIndex()) { _lock = true; try { textEditor.selectModelObject(object, attr); } finally { _lock = false; } } else { selected = object; attribute = (attr == null || attr.length() == 0) ? null : attr; } } public void run() { if(selected == null || textEditor == null) return; if(_lock) return; _lock = true; try { textEditor.selectModelObject(selected, attribute); } finally { _lock = false; } clean(); } } protected void pageChange(int newPageIndex) { deactivateSite(false, false); boolean isText = selectedPageIndex == getSourcePageIndex(); selectedPageIndex = newPageIndex; Control control = getControl(newPageIndex); if (control != null) { control.setVisible(true); } setFocus(); IEditorPart activeEditor = getEditor(newPageIndex); IEditorActionBarContributor contributor = getEditorSite().getActionBarContributor(); if(contributor instanceof EditorActionBarContributorWrapper) contributor = ((EditorActionBarContributorWrapper)contributor).getActiveContributer(); if (contributor instanceof MultiPageEditorActionBarContributor) { ((MultiPageEditorActionBarContributor) contributor).setActivePage(activeEditor); } updateSelectionProvider(); if(postponedTextSelection.selected != null) { Display.getDefault().asyncExec(postponedTextSelection); } if(isText && newPageIndex != getSourcePageIndex()) { synchronizeSelectionWithText(); } activateSite(); } protected void synchronizeSelectionWithText() { } protected void updateSelectionProvider() { } protected boolean checkReadOnlyOnSave() { IFile f = getFile(); if(f == null || !f.exists() || !f.isReadOnly()) return true; String title= "Save problems"; String msg= " Cannot could not be completed."; IStatus status = new Status(Status.ERROR, ModelUIPlugin.PLUGIN_ID, Status.OK, MessageFormat.format("File {0} is read-only.", f.getLocation().toString()), new Exception()); ErrorDialog.openError(getSite().getShell(), title, msg, status); return false; } //@S_CLASS@ protected TreeFormPage createTreeFormPage() { treeFormPage = new TreeFormPage(); treeFormPage.setLabel("Tree"); treeFormPage.setTitle("%TreeFormPage%"); //$NON-NLS-1$ treeFormPage.addErrorSelectionListener(createErrorSelectionListener()); return treeFormPage; } protected void addFormPage(TreeFormPage formPage) { try { int index = addPage(formPage, getEditorInput()); setPageText(index, formPage.getLabel()); selectionProvider.addHost("treeEditor", formPage.getSelectionProvider()); //$NON-NLS-1$ //Activate key binding service here formPage.getEditorSite().getKeyBindingService(); } catch (PartInitException ex) { ModelUIPlugin.getPluginLog().logError(ex); } //getSite().setSelectionProvider(formPage.getSelectionProvider()); } /* protected void addFormPage(IFormPage formPage) { Control control = formPage.createControl(getContainer()); int index = addPage(control); setPageText(index, formPage.getLabel()); selectionProvider.addHost("treeEditor", formPage.getSelectionProvider()); //getSite().setSelectionProvider(formPage.getSelectionProvider()); } */ protected void performSaveAs(IProgressMonitor progressMonitor) { Shell shell = getSite().getShell(); SaveAsDialog dialog = new SaveAsDialog(shell); initSaveAsDialog(dialog); dialog.create(); final IFile file = runSaveAsDialog(dialog, progressMonitor); if (file == null) return; WorkspaceModifyOperation op = new WorkspaceModifyOperation() { public void execute(final IProgressMonitor monitor) throws CoreException { String body = ((FileAnyImpl)object).getAsText(); ByteArrayInputStream b = new ByteArrayInputStream(body.getBytes()); if(!file.exists()) { file.create(b, true, monitor); } else { file.setContents(b, true, false, monitor); } object.getModel().update(); file.getParent().refreshLocal(IResource.DEPTH_INFINITE, monitor); } }; boolean success = false; try { new ProgressMonitorDialog(shell).run(false, true, op); success = true; } catch (InterruptedException x) { //ignore } catch (InvocationTargetException x) { Throwable targetException= x.getTargetException(); String title = "Save As"; String msg = "Error: " + targetException.getMessage(); if (targetException instanceof CoreException) { CoreException coreException= (CoreException) targetException; IStatus status= coreException.getStatus(); if (status != null) { switch (status.getSeverity()) { case IStatus.INFO: MessageDialog.openInformation(shell, title, msg); break; case IStatus.WARNING: MessageDialog.openWarning(shell, title, msg); break; default: MessageDialog.openError(shell, title, msg); } } else { MessageDialog.openError(shell, title, msg); } } } finally { if (success) { XModelObject o = null; for (int i = 0; i < 5 && o == null; i++) { o = EclipseResourceUtil.getObjectByResource(file); if(o == null) try { Thread.sleep(200); } catch (InterruptedException e) { //ignore } } if(o == null) o = EclipseResourceUtil.createObjectForResource(file); if(o != null) { XActionInvoker.invoke("Open", o, null); //$NON-NLS-1$ } } } if (progressMonitor != null) progressMonitor.setCanceled(!success); } private void initSaveAsDialog(SaveAsDialog dialog) { IFile original = (input instanceof IFileEditorInput) ? ((IFileEditorInput) input).getFile() : null; if (original != null) dialog.setOriginalFile(original); } private IFile runSaveAsDialog(SaveAsDialog dialog, IProgressMonitor progressMonitor) { if (dialog.open() == Dialog.CANCEL) { if (progressMonitor != null) progressMonitor.setCanceled(true); return null; } IPath filePath = dialog.getResult(); if (filePath == null) { if (progressMonitor != null) progressMonitor.setCanceled(true); return null; } IWorkspace workspace = ResourcesPlugin.getWorkspace(); return workspace.getRoot().getFile(filePath); } void updateTitle() { Display.getDefault().asyncExec(new Runnable() { public void run() { setPartName(getEditorInput().getName()); } }); } public void updatedTitleImage(Image image) { setTitleImage(image); } class PostMultiPageEditorSite extends MultiPageEditorSite { private ISelectionChangedListener postSelectionChangedListener = null; public PostMultiPageEditorSite(ObjectMultiPageEditor multiPageEditor, IEditorPart editor) { super(multiPageEditor, editor); } private ISelectionChangedListener getPostSelectionChangedListener() { if (postSelectionChangedListener == null) { postSelectionChangedListener = new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { PostMultiPageEditorSite.this.handlePostSelectionChanged(event); } }; } return postSelectionChangedListener; } protected void handlePostSelectionChanged(SelectionChangedEvent event) { if(selectedPageIndex != getSourcePageIndex()) { //link outline only to text editor return; } ISelectionProvider parentProvider = getMultiPageEditor().getSite().getSelectionProvider(); ISelection s = event.getSelection(); if(s == null || s.isEmpty()) return; if(s instanceof ITextSelection) { XModelObject o = textEditor.findModelObjectAtCursor(); if(o != null) { SelectionChangedEvent newEvent = new SelectionChangedEvent(parentProvider, new StructuredSelection(o)); if(parentProvider instanceof XModelObjectSelectionProvider) { ((XModelObjectSelectionProvider)parentProvider).postSelectionChanged(newEvent); } } } } public void setSelectionProvider(ISelectionProvider provider) { ISelectionProvider oldSelectionProvider = getSelectionProvider(); if (oldSelectionProvider != null) { if (oldSelectionProvider instanceof IPostSelectionProvider) { ((IPostSelectionProvider) oldSelectionProvider).removePostSelectionChangedListener(getPostSelectionChangedListener()); } } super.setSelectionProvider(provider); if (provider != null) { if (provider instanceof IPostSelectionProvider) { ((IPostSelectionProvider) provider).addPostSelectionChangedListener(getPostSelectionChangedListener()); } } } } @Override public void switchToSourceTab() { setActiveEditor((IEditorPart)textEditor); } } class ResourceChangeListener implements IResourceChangeListener { IEditorPart editorPart; Composite container; ResourceChangeListener(IEditorPart editorPart, Composite container) { this.editorPart = editorPart; this.container = container; IWorkspace workspace = ModelUIPlugin.getWorkspace(); if (workspace == null) return; workspace.addResourceChangeListener(this); container.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { IWorkspace workspace = ModelUIPlugin.getWorkspace(); if (workspace == null) return; workspace.removeResourceChangeListener(ResourceChangeListener.this); } }); } public void resourceChanged(IResourceChangeEvent event) { final IEditorInput ei = editorPart.getEditorInput(); if(ei instanceof IModelObjectEditorInput) { XModelObject o = ((IModelObjectEditorInput)ei).getXModelObject(); IProject project = EclipseResourceUtil.getProject(o); if(project != null && (!project.exists() || !project.isOpen())) { closeEditor(); return; } } if(!(ei instanceof IFileEditorInput)) return; IFileEditorInput fi = (IFileEditorInput)ei; IFile f = fi.getFile(); if(f == null) return; IPath path = getPathChange(event, f); if(path == null) { if(f != null && !f.exists()) closeEditor(); return; } f = ModelPlugin.getWorkspace().getRoot().getFile(path); XModelObject p = f == null ? null : EclipseResourceUtil.getObjectByResource(f.getParent()); if(p instanceof FolderImpl) { ((FolderImpl)p).update(); } final XModelObject o = EclipseResourceUtil.getObjectByResource(f); if(f != null && f.exists() && o != null) { if(editorPart instanceof ObjectMultiPageEditor) { final ObjectMultiPageEditor e = (ObjectMultiPageEditor)editorPart; if(ei instanceof XModelObjectEditorInput) { final IEditorInput e2 = XModelObjectEditorInput.createInstance(o); if(Display.getCurrent() == null) { Display.getDefault().asyncExec(new Runnable() { public void run() { apply(e, o, ei, e2); } }); } else { apply(e, o, ei, e2); } } } } if(f == null || f.exists()) return; closeEditor(); } void apply(ObjectMultiPageEditor e, XModelObject o, IEditorInput ei, IEditorInput e2) { e.setInput(e2); e.updateTitle(); if(e.textEditor instanceof AbstractTextEditor) { ((AbstractTextEditor)e.textEditor).setInput(e2); ((XModelObjectEditorInput)ei).synchronize(); if(((XModelObjectEditorInput)ei).getXModelObject() != o) { closeEditor(); return; } } } private void closeEditor() { Display.getDefault().asyncExec(new Runnable() { public void run() { editorPart.getSite().getPage().closeEditor(editorPart, false); } }); } private IPath getPathChange(IResourceChangeEvent event, IFile f) { return getPathChange(event.getDelta(), f.getFullPath()); } private IPath getPathChange(IResourceDelta delta, IPath p) { if(delta == null || delta.getFullPath() == null) return null; if(!delta.getFullPath().isPrefixOf(p)) return null; if(delta != null && delta.getKind() == IResourceDelta.CHANGED) { IResourceDelta[] ds = delta.getAffectedChildren(); if(ds == null) return null; if(ds.length > 1) { return getPathChange(ds, p); } for (int i = 0; i < ds.length; i++) { IPath ps = getPathChange(ds[i], p); if(ps != null) return ps; } } return null; } private IPath getPathChange(IResourceDelta[] ds, IPath p) { int index = -1; boolean equals = false; IPath dp = null; for (int i = 0; i < ds.length; i++) { if(ds[i].getKind() == IResourceDelta.REMOVED) { IPath d = ds[i].getFullPath(); if(d.equals(p)) { equals = true; index = i; dp = d; break; } else if(d.isPrefixOf(p)) { index = i; dp = d; } } } if(index < 0) return null; for (int i = 0; i < ds.length; i++) { if(ds[i].getKind() == IResourceDelta.ADDED) { IPath d = ds[i].getFullPath(); IPath df = ds[i].getMovedFromPath(); if(!dp.equals(df)) continue; if(equals) return d; return d.append(p.removeFirstSegments(dp.segmentCount())); } } return null; } } class NatureChecker { boolean isAppropriateNature = false; IResource resource = null; String[] natures; String warningKey; IEditorInput input; public boolean isAppropriateNature() { return isAppropriateNature; } public void check(IEditorInput input, String[] natures, String warningKey) { //Suppress check: EXIN-292 natures = new String[0]; this.input = input; if(input instanceof IFileEditorInput) { resource = ((IFileEditorInput)input).getFile(); } else { isAppropriateNature = true; return; } this.warningKey = warningKey; this.natures = natures; isAppropriateNature = isAppropriateNature(input); if(!isAppropriateNature) { //Suppress check: EXIN-292 // showWarning(); // if(this.input instanceof IFileEditorInput) { // resource = ((IFileEditorInput)this.input).getFile(); // } // isAppropriateNature = isAppropriateNature(this.input); } } private boolean isAppropriateNature(IEditorInput input) { input = XModelObjectEditorInput.checkInput(input); if(!(input instanceof IModelObjectEditorInput)) return false; XModelObject o = ((IModelObjectEditorInput)input).getXModelObject(); IProject project = (IProject)o.getModel().getProperties().get("project"); //$NON-NLS-1$ if(project == null) return false; if(natures != null && natures.length == 0) return true; IModelNature n = EclipseResourceUtil.getModelNature(project); if(n == null) return false; if(natures == null) return true; for (int i = 0; i < natures.length; i++) { if(EclipseResourceUtil.getModelNature(project, natures[i]) != null) return true; } return false; } }