/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php * * 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 com.android.ide.eclipse.adt.internal.editors.layout.properties; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.IconFactory; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart; import com.android.ide.eclipse.adt.internal.editors.layout.properties.PropertyFactory.SortingMode; import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; import com.android.ide.eclipse.adt.internal.editors.uimodel.IUiUpdateListener; import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; 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.IStatusLineManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.Page; import org.eclipse.ui.views.properties.IPropertySheetPage; import org.eclipse.wb.internal.core.editor.structure.IPage; import org.eclipse.wb.internal.core.model.property.Property; import org.eclipse.wb.internal.core.model.property.table.IPropertyExceptionHandler; import org.eclipse.wb.internal.core.model.property.table.PropertyTable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * Property sheet page used when the graphical layout editor is chosen */ public class PropertySheetPage extends Page implements IPropertySheetPage, IUiUpdateListener, IPage { private PropertyTable mPropertyTable; private final GraphicalEditorPart mEditor; private Property mActiveProperty; private Action mDefaultValueAction; private Action mShowAdvancedPropertiesAction; private Action mSortAlphaAction; private Action mCollapseAll; private Action mExpandAll; private List<CanvasViewInfo> mSelection; private static final String EXPAND_DISABLED_ICON = "expandall-disabled"; //$NON-NLS-1$ private static final String EXPAND_ICON = "expandall"; //$NON-NLS-1$ private static final String DEFAULT_ICON = "properties_default"; //$NON-NLS-1$ private static final String ADVANCED_ICON = "filter_advanced_properties"; //$NON-NLS-1$ private static final String ALPHA_ICON = "sort_alpha"; //$NON-NLS-1$ // TODO: goto-definition.png /** * Constructs a new {@link PropertySheetPage} associated with the given * editor * * @param editor the editor associated with this property sheet page */ public PropertySheetPage(GraphicalEditorPart editor) { mEditor = editor; } private PropertyFactory getPropertyFactory() { return mEditor.getPropertyFactory(); } @Override public void createControl(Composite parent) { assert parent != null; mPropertyTable = new PropertyTable(parent, SWT.NONE); mPropertyTable.setExceptionHandler(new IPropertyExceptionHandler() { @Override public void handle(Throwable e) { AdtPlugin.log(e, null); } }); mPropertyTable.setDefaultCollapsedNames(Arrays.asList( "Deprecated", "Layout Parameters", "Layout Parameters|Margins")); createActions(); setPropertyTableContextMenu(); } @Override public void selectionChanged(IWorkbenchPart part, ISelection selection) { if (selection instanceof TreeSelection && mPropertyTable != null && !mPropertyTable.isDisposed()) { TreeSelection treeSelection = (TreeSelection) selection; // We get a lot of repeated selection requests for the same selection // as before, so try to eliminate these if (mSelection != null) { if (mSelection.isEmpty()) { if (treeSelection.isEmpty()) { return; } } else { int selectionCount = treeSelection.size(); if (selectionCount == mSelection.size()) { boolean same = true; Iterator<?> iterator = treeSelection.iterator(); for (int i = 0, n = selectionCount; i < n && iterator.hasNext(); i++) { Object next = iterator.next(); if (next instanceof CanvasViewInfo) { CanvasViewInfo info = (CanvasViewInfo) next; if (info != mSelection.get(i)) { same = false; break; } } else { same = false; break; } } if (same) { return; } } } } stopTrackingSelection(); if (treeSelection.isEmpty()) { mSelection = Collections.emptyList(); } else { int selectionCount = treeSelection.size(); List<CanvasViewInfo> newSelection = new ArrayList<CanvasViewInfo>(selectionCount); Iterator<?> iterator = treeSelection.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); if (next instanceof CanvasViewInfo) { CanvasViewInfo info = (CanvasViewInfo) next; newSelection.add(info); } } mSelection = newSelection; } startTrackingSelection(); refreshProperties(); } } @Override public void dispose() { stopTrackingSelection(); super.dispose(); } private void startTrackingSelection() { if (mSelection != null && !mSelection.isEmpty()) { for (CanvasViewInfo item : mSelection) { UiViewElementNode node = item.getUiViewNode(); if (node != null) { node.addUpdateListener(this); } } } } private void stopTrackingSelection() { if (mSelection != null && !mSelection.isEmpty()) { for (CanvasViewInfo item : mSelection) { UiViewElementNode node = item.getUiViewNode(); if (node != null) { node.removeUpdateListener(this); } } } mSelection = null; } // Implements IUiUpdateListener @Override public void uiElementNodeUpdated(UiElementNode node, UiUpdateState state) { refreshProperties(); } @Override public Control getControl() { return mPropertyTable; } @Override public void setFocus() { mPropertyTable.setFocus(); } @Override public void makeContributions(IMenuManager menuManager, IToolBarManager toolBarManager, IStatusLineManager statusLineManager) { toolBarManager.add(mShowAdvancedPropertiesAction); toolBarManager.add(new Separator()); toolBarManager.add(mSortAlphaAction); toolBarManager.add(new Separator()); toolBarManager.add(mDefaultValueAction); toolBarManager.add(new Separator()); toolBarManager.add(mExpandAll); toolBarManager.add(mCollapseAll); toolBarManager.add(new Separator()); } private void createActions() { ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages(); IconFactory iconFactory = IconFactory.getInstance(); mExpandAll = new PropertySheetAction( IAction.AS_PUSH_BUTTON, "Expand All", ACTION_EXPAND, iconFactory.getImageDescriptor(EXPAND_ICON), iconFactory.getImageDescriptor(EXPAND_DISABLED_ICON)); mCollapseAll = new PropertySheetAction( IAction.AS_PUSH_BUTTON, "Collapse All", ACTION_COLLAPSE, sharedImages.getImageDescriptor(ISharedImages.IMG_ELCL_COLLAPSEALL), sharedImages.getImageDescriptor(ISharedImages.IMG_ELCL_COLLAPSEALL_DISABLED)); mShowAdvancedPropertiesAction = new PropertySheetAction( IAction.AS_CHECK_BOX, "Show Advanced Properties", ACTION_SHOW_ADVANCED, iconFactory.getImageDescriptor(ADVANCED_ICON), null); mSortAlphaAction = new PropertySheetAction( IAction.AS_CHECK_BOX, "Sort Alphabetically", ACTION_SORT_ALPHA, iconFactory.getImageDescriptor(ALPHA_ICON), null); mDefaultValueAction = new PropertySheetAction( IAction.AS_PUSH_BUTTON, "Restore Default Value", ACTION_DEFAULT_VALUE, iconFactory.getImageDescriptor(DEFAULT_ICON), null); // Listen on the selection in the property sheet so we can update the // Restore Default Value action ISelectionChangedListener listener = new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { StructuredSelection selection = (StructuredSelection) event.getSelection(); mActiveProperty = (Property) selection.getFirstElement(); updateDefaultValueAction(); } }; mPropertyTable.addSelectionChangedListener(listener); } /** * Updates the state of {@link #mDefaultValueAction}. */ private void updateDefaultValueAction() { if (mActiveProperty != null) { try { mDefaultValueAction.setEnabled(mActiveProperty.isModified()); } catch (Exception e) { AdtPlugin.log(e, null); } } else { mDefaultValueAction.setEnabled(false); } } /** * Sets the context menu for {@link #mPropertyTable}. */ private void setPropertyTableContextMenu() { final MenuManager manager = new MenuManager(); manager.setRemoveAllWhenShown(true); manager.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager m) { // dispose items to avoid caching for (MenuItem item : manager.getMenu().getItems()) { item.dispose(); } // apply new items fillContextMenu(); } private void fillContextMenu() { manager.add(mDefaultValueAction); manager.add(mSortAlphaAction); manager.add(mShowAdvancedPropertiesAction); } }); mPropertyTable.setMenu(manager.createContextMenu(mPropertyTable)); } /** * Shows {@link Property}'s of current objects. */ private void refreshProperties() { PropertyFactory factory = getPropertyFactory(); mPropertyTable.setInput(factory.getProperties(mSelection)); updateDefaultValueAction(); } // ---- Actions ---- private static final int ACTION_DEFAULT_VALUE = 1; private static final int ACTION_SHOW_ADVANCED = 2; private static final int ACTION_COLLAPSE = 3; private static final int ACTION_EXPAND = 4; private static final int ACTION_SORT_ALPHA = 5; private class PropertySheetAction extends Action { private final int mAction; private PropertySheetAction(int style, String label, int action, ImageDescriptor imageDesc, ImageDescriptor disabledImageDesc) { super(label, style); mAction = action; setImageDescriptor(imageDesc); if (disabledImageDesc != null) { setDisabledImageDescriptor(disabledImageDesc); } setToolTipText(label); } @Override public void run() { switch (mAction) { case ACTION_COLLAPSE: { mPropertyTable.collapseAll(); break; } case ACTION_EXPAND: { mPropertyTable.expandAll(); break; } case ACTION_SHOW_ADVANCED: { boolean show = mShowAdvancedPropertiesAction.isChecked(); mPropertyTable.setShowAdvancedProperties(show); break; } case ACTION_SORT_ALPHA: { boolean isAlphabetical = mSortAlphaAction.isChecked(); getPropertyFactory().setSortingMode( isAlphabetical ? SortingMode.ALPHABETICAL : PropertyFactory.DEFAULT_MODE); refreshProperties(); break; } case ACTION_DEFAULT_VALUE: try { mActiveProperty.setValue(Property.UNKNOWN_VALUE); } catch (Exception e) { // Ignore warnings from setters } break; default: assert false : mAction; } } } @Override public void setToolBar(IToolBarManager toolBarManager) { makeContributions(null, toolBarManager, null); toolBarManager.update(false); } }