/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.sling.ide.eclipse.ui.views; import java.util.Map; import java.util.Map.Entry; import org.apache.sling.ide.eclipse.core.internal.Activator; import org.apache.sling.ide.eclipse.ui.nav.model.JcrNode; import org.apache.sling.ide.eclipse.ui.nav.model.SyncDir; import org.apache.sling.ide.eclipse.ui.nav.model.SyncDirManager; import org.apache.sling.ide.eclipse.ui.nav.model.UpdateHandler; import org.apache.sling.ide.eclipse.ui.views.JcrEditingSupport.ColumnId; import org.eclipse.core.resources.IFile; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.CellNavigationStrategy; import org.eclipse.jface.viewers.ColumnViewerEditor; import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.TableViewerEditor; import org.eclipse.jface.viewers.TableViewerFocusCellManager; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.IActionBars; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.internal.IWorkbenchGraphicConstants; import org.eclipse.ui.internal.WorkbenchImages; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.views.properties.IPropertyDescriptor; public class JcrPropertiesView extends ViewPart { private static final String TITLE_FONT = "org.eclipse.ui.internal.views.properties.tabbed.view.TabbedPropertyTitle"; //$NON-NLS-1$ private TableViewer viewer; private Action insertAction; private Action deleteAction; private Action doubleClickAction; private Label titleLabel; private ISelectionListener listener; private Action showInEditorAction; private Action pinAction; private JcrNode lastInput; private Action synchedAction; private String lastEditedOldPropertyName; private String lastEditedNewPropertyName; private ColumnId lastEditedColumnId; private Composite mainControl; private IWorkbenchPage page; class ViewContentProvider implements IStructuredContentProvider { public void inputChanged(Viewer v, Object oldInput, Object newInput) { } public void dispose() { } public Object[] getElements(Object parent) { if (parent instanceof JcrNode) { JcrNode node = (JcrNode)parent; final IPropertyDescriptor[] pds = node.getProperties().getPropertyDescriptors(); return pds; } else { return new String[] {}; } } } /** * The constructor. */ public JcrPropertiesView() { } public Control getMainControl() { return mainControl; } /** * This is a callback that will allow us * to create the viewer and initialize it. */ public void createPartControl(Composite parent) { SyncDirManager.registerUpdateListener(new UpdateHandler() { @Override public void syncDirUpdated(SyncDir syncDir) { refreshContent(); } }); mainControl = new Composite(parent, SWT.NONE); final GridLayout gridLayout = new GridLayout(1, true); mainControl.setLayout(gridLayout); if (getViewSite()!=null) { titleLabel = new Label(mainControl, SWT.WRAP); titleLabel.setText(""); GridData data = new GridData(GridData.FILL_HORIZONTAL); titleLabel.setLayoutData(data); Label horizontalLine = new Label(mainControl, SWT.SEPARATOR | SWT.HORIZONTAL); data = new GridData(GridData.FILL_HORIZONTAL); horizontalLine.setLayoutData(data); } Font font; if (! JFaceResources.getFontRegistry().hasValueFor(TITLE_FONT)) { FontData[] fontData = JFaceResources.getFontRegistry().getBold( JFaceResources.DEFAULT_FONT).getFontData(); /* title font is 2pt larger than that used in the tabs. */ fontData[0].setHeight(fontData[0].getHeight() + 2); JFaceResources.getFontRegistry().put(TITLE_FONT, fontData); } font = JFaceResources.getFont(TITLE_FONT); if (titleLabel!=null) { titleLabel.setFont(font); } Composite tableParent = new Composite(mainControl, SWT.NONE); // tableParent.setBackground(new Color(Display.getDefault(), 100,20,180)); GridData tableLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); tableLayoutData.widthHint = 1; // shrink to min - table settings will resize to correct ratios tableLayoutData.heightHint = SWT.DEFAULT; tableParent.setLayoutData(tableLayoutData); TableColumnLayout tableLayout = new TableColumnLayout() { @Override protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) { Point p = super.computeSize(composite, wHint, hHint, flushCache); return new Point(p.x, p.y); } }; tableParent.setLayout(tableLayout); viewer = new TableViewer(tableParent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.HIDE_SELECTION | SWT.FULL_SELECTION); TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager( viewer, new FocusCellOwnerDrawHighlighter(viewer), new CellNavigationStrategy()); ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy( viewer){ @Override protected boolean isEditorActivationEvent( ColumnViewerEditorActivationEvent event) { resetLastValueEdited(); return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR) || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC; } }; int features = ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION | ColumnViewerEditor.KEEP_EDITOR_ON_DOUBLE_CLICK; TableViewerEditor.create(viewer, focusCellManager, actSupport, features); viewer.getTable().setLinesVisible(true); viewer.getTable().setHeaderVisible(true); viewer.setContentProvider(new ViewContentProvider()); viewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { final ISelection selection = event.getSelection(); if (selection instanceof IStructuredSelection) { IStructuredSelection iss = (IStructuredSelection)selection; if (iss.isEmpty()) { deleteAction.setEnabled(false); } else { deleteAction.setEnabled(true); } } else { deleteAction.setEnabled(false); } } }); CellLabelProvider clp = new JcrCellLabelProvider(viewer); TableViewerColumn column0 = new TableViewerColumn(viewer, SWT.NONE); column0.getColumn().setText("Name"); column0.getColumn().setResizable(true); column0.getColumn().setWidth(200); tableLayout.setColumnData(column0.getColumn(), new ColumnWeightData(30, 140)); final TableViewerColumn column1 = new TableViewerColumn(viewer, SWT.NONE); column1.getColumn().setText("Type"); column1.getColumn().setResizable(true); column1.getColumn().setWidth(300); column1.setLabelProvider(clp); tableLayout.setColumnData(column1.getColumn(), new ColumnWeightData(10, 80)); final TableViewerColumn column2 = new TableViewerColumn(viewer, SWT.NONE); column2.getColumn().setText("Value"); column2.getColumn().setResizable(true); column2.getColumn().setWidth(300); tableLayout.setColumnData(column2.getColumn(), new ColumnWeightData(70, 220)); final TableViewerColumn column3 = new TableViewerColumn(viewer, SWT.NONE); column3.getColumn().setText("Protected"); column3.getColumn().setResizable(true); column3.getColumn().setWidth(300); column3.setLabelProvider(clp); tableLayout.setColumnData(column3.getColumn(), new ColumnWeightData(5, 57)); final TableViewerColumn column4 = new TableViewerColumn(viewer, SWT.NONE); column4.getColumn().setText("Mandatory"); column4.getColumn().setResizable(true); column4.getColumn().setWidth(300); column4.setLabelProvider(clp); tableLayout.setColumnData(column4.getColumn(), new ColumnWeightData(5, 62)); final TableViewerColumn column5 = new TableViewerColumn(viewer, SWT.NONE); column5.getColumn().setText("Multiple"); column5.getColumn().setResizable(true); column5.getColumn().setWidth(300); column5.setLabelProvider(clp); tableLayout.setColumnData(column5.getColumn(), new ColumnWeightData(5, 82)); final TableViewerColumn column6 = new TableViewerColumn(viewer, SWT.NONE); column6.getColumn().setText("Auto Created"); column6.getColumn().setResizable(true); column6.getColumn().setWidth(300); column6.setLabelProvider(clp); tableLayout.setColumnData(column6.getColumn(), new ColumnWeightData(5, 77)); column0.setLabelProvider(clp); column0.setEditingSupport(new JcrEditingSupport(this, viewer, ColumnId.NAME)); column1.setLabelProvider(clp); column1.setEditingSupport(new JcrEditingSupport(this, viewer, ColumnId.TYPE)); column2.setLabelProvider(clp); column2.setEditingSupport(new JcrEditingSupport(this, viewer, ColumnId.VALUE)); column5.setEditingSupport(new JcrEditingSupport(this, viewer, ColumnId.MULTIPLE)); // Create the help context id for the viewer's control PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(), "org.apache.sling.ide.eclipse-ui.viewer"); makeActions(); hookContextMenu(); hookDoubleClickAction(); contributeToActionBars(); listener = new ISelectionListener() { @Override public void selectionChanged(IWorkbenchPart part, ISelection selection) { if (selection instanceof IStructuredSelection) { IStructuredSelection iss = (IStructuredSelection)selection; Object firstElem = iss.getFirstElement(); if (firstElem instanceof JcrNode) { JcrNode jcrNode = (JcrNode)firstElem; setInput(jcrNode); return; } } } }; if (getViewSite()!=null) { getViewSite().getPage().addSelectionListener(listener); final ISelection selection = getViewSite().getPage().getSelection(); Display.getCurrent().asyncExec(new Runnable() { @Override public void run() { listener.selectionChanged(null, selection); } }); } } void resetLastValueEdited() { this.lastEditedOldPropertyName = null; this.lastEditedNewPropertyName = null; this.lastEditedColumnId = null; } void setLastValueEdited(String oldPropertyName, String newPropertyName, ColumnId columnId) { this.lastEditedOldPropertyName = oldPropertyName; this.lastEditedNewPropertyName = newPropertyName; this.lastEditedColumnId = columnId; } @Override public void dispose() { super.dispose(); if (listener!=null) { getViewSite().getPage().removeSelectionListener(listener); listener = null; } } private void hookContextMenu() { MenuManager menuMgr = new MenuManager("#PopupMenu"); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { JcrPropertiesView.this.fillContextMenu(manager); } }); Menu menu = menuMgr.createContextMenu(viewer.getControl()); viewer.getControl().setMenu(menu); IWorkbenchPartSite site = getSite(); if (site!=null) { site.registerContextMenu(menuMgr, viewer); } } private void contributeToActionBars() { if (getViewSite()!=null) { IActionBars bars = getViewSite().getActionBars(); fillLocalPullDown(bars.getMenuManager()); fillLocalToolBar(bars.getToolBarManager()); } } private void fillLocalPullDown(IMenuManager manager) { manager.add(insertAction); // manager.add(new Separator()); manager.add(deleteAction); manager.add(showInEditorAction); if (pinAction!=null) { manager.add(pinAction); } if (synchedAction!=null) { manager.add(synchedAction); } } private void fillContextMenu(IMenuManager manager) { manager.add(insertAction); manager.add(deleteAction); manager.add(showInEditorAction); if (pinAction!=null) { manager.add(pinAction); } if (synchedAction!=null) { manager.add(synchedAction); } // Other plug-ins can contribute there actions here manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } private void fillLocalToolBar(IToolBarManager manager) { manager.add(insertAction); manager.add(deleteAction); manager.add(showInEditorAction); if (pinAction!=null) { manager.add(pinAction); } if (synchedAction!=null) { manager.add(synchedAction); } } private void makeActions() { insertAction = new Action() { public void run() { NewRow newRow = new NewRow(); viewer.add(newRow); viewer.getTable().setTopIndex(viewer.getTable().getItemCount()); viewer.getTable().select(viewer.getTable().getItemCount()-1); viewer.editElement(newRow, 0); } }; insertAction.setText("Insert"); insertAction.setToolTipText("Insert a property"); insertAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages(). getImageDescriptor(ISharedImages.IMG_OBJ_ADD)); deleteAction = new Action() { public void run() { if (viewer.getSelection().isEmpty()) { return; } ISelection sel = viewer.getSelection(); if (sel instanceof IStructuredSelection) { IStructuredSelection iss = (IStructuredSelection)sel; Object elem = iss.getFirstElement(); if (elem instanceof IPropertyDescriptor) { IPropertyDescriptor pd = (IPropertyDescriptor)elem; JcrNode jcrnode = (JcrNode)viewer.getInput(); jcrnode.deleteProperty(pd.getDisplayName()); refreshContent(); } } } }; deleteAction.setText("Delete"); deleteAction.setToolTipText("Delete a proeprty"); deleteAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages(). getImageDescriptor(ISharedImages.IMG_TOOL_DELETE)); doubleClickAction = new Action() { public void run() { //TODO doesn't do anything currently.. ISelection selection = viewer.getSelection(); // Object obj = ((IStructuredSelection)selection).getFirstElement(); // showMessage("Double-click detected on "+obj.toString()); } }; showInEditorAction = new Action() { public void run() { JcrNode node = (JcrNode)viewer.getInput(); final IFile file = node.getFileForEditor(); if (file!=null) { try { IDE.openEditor(getPage(), file, true); } catch (PartInitException e) { e.printStackTrace(System.out); } } } }; showInEditorAction.setText("Show in editor"); showInEditorAction.setToolTipText("Show underlying vault file in editor"); showInEditorAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages(). getImageDescriptor(ISharedImages.IMG_OBJ_FILE)); if (getViewSite()!=null) { pinAction = new Action("pin to selection", IAction.AS_CHECK_BOX) { public void run() { if (!pinAction.isChecked()) { // unpin setContentDescription(""); setInput(lastInput); } else { setContentDescription("[pinned]"); } // toggle state of syncedAction accordingly if (synchedAction!=null) { synchedAction.setEnabled(!pinAction.isChecked()); } } }; pinAction.setText("Pin to selection"); pinAction.setToolTipText("Pin this property view to the current selection"); pinAction.setImageDescriptor(WorkbenchImages .getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_PIN_EDITOR)); pinAction.setDisabledImageDescriptor(WorkbenchImages .getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_PIN_EDITOR_DISABLED)); pinAction.setChecked(false); synchedAction = new Action("Link with Editor and selection", IAction.AS_CHECK_BOX) { public void run() { // toggle state of pinAction accordingly pinAction.setEnabled(!synchedAction.isChecked()); } }; synchedAction.setText("Link with Editor and selection"); synchedAction.setToolTipText("Link with Editor and selection"); synchedAction.setImageDescriptor(WorkbenchImages .getImageDescriptor(ISharedImages.IMG_ELCL_SYNCED)); synchedAction.setDisabledImageDescriptor(WorkbenchImages .getImageDescriptor(ISharedImages.IMG_ELCL_SYNCED_DISABLED)); synchedAction.setChecked(true); } } private void hookDoubleClickAction() { viewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { doubleClickAction.run(); } }); } /** * Passing the focus request to the viewer's control. */ public void setFocus() { viewer.getControl().setFocus(); } void refreshContent() { final Object input = viewer.getInput(); if (input!=null && input instanceof JcrNode) { JcrNode jcrnode = (JcrNode)input; SyncDir syncDir = jcrnode.getSyncDir(); JcrNode newnode = syncDir.getNode(jcrnode.getJcrPath()); if (newnode!=null) { viewer.setInput(newnode); if (lastEditedNewPropertyName!=null) { // set the selection/focus accordingly for(int i=0;;i++) { Object element = viewer.getElementAt(i); if (element==null) { break; } final IPropertyDescriptor pd = (IPropertyDescriptor) element; Map.Entry<String,Object> me = (Entry<String, Object>) pd.getId(); String key = me.getKey(); if (lastEditedNewPropertyName.equals(key)) { // set the selection to this one final int column; if (lastEditedColumnId==ColumnId.NAME) { column = 0; } else if (lastEditedColumnId==ColumnId.TYPE) { column = 1; } else if (lastEditedColumnId==ColumnId.VALUE) { column = 2; } else if (lastEditedColumnId==ColumnId.MULTIPLE) { column = 5; } else { throw new IllegalStateException("Unknown columnId="+lastEditedColumnId); } Display.getDefault().asyncExec(new Runnable() { @Override public void run() { try{ // edit viewer.editElement(pd, column); // and cancel immediately - to get the selection right viewer.cancelEditing(); } catch(Exception e) { Activator.getDefault().getPluginLogger().error("Exception occured on edit/cancel: "+e, e); } } }); break; } } } } } } public void setInput(JcrNode jcrNode) { // reset the last edited values..: resetLastValueEdited(); if (pinAction!=null && pinAction.isChecked()) { lastInput = jcrNode; } else { if (getViewSite()!=null && synchedAction!=null && synchedAction.isChecked()) { getViewSite().getPage().bringToTop(this); } viewer.setInput(jcrNode); if (titleLabel!=null) { titleLabel.setText(jcrNode.getJcrPath()); } insertAction.setEnabled(!jcrNode.getPrimaryType().equals("nt:folder")); deleteAction.setEnabled(false); showInEditorAction.setEnabled(jcrNode.getFileForEditor()!=null); } } private IWorkbenchPage getPage() { if (page!=null) { return page; } else if (getViewSite()!=null) { return getViewSite().getPage(); } else { return null; } } public void setPage(IWorkbenchPage page) { this.page = page; } }