Java tutorial
/******************************************************************************* * Copyright (c) 2007-2010 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.jst.css.dialog.selector; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.jboss.tools.jst.css.CSSPlugin; import org.jboss.tools.jst.css.dialog.common.StyleAttributes; import org.jboss.tools.jst.css.dialog.common.Util; import org.jboss.tools.jst.css.dialog.selector.dnd.CSSTableDragAdapter; import org.jboss.tools.jst.css.dialog.selector.dnd.CSSTableDropAdapter; import org.jboss.tools.jst.css.dialog.selector.dnd.CSSTreeDragAdapter; import org.jboss.tools.jst.css.dialog.selector.model.CSSContainer; import org.jboss.tools.jst.css.dialog.selector.model.CSSJSPRecognizer; import org.jboss.tools.jst.css.dialog.selector.model.CSSRuleContainer; import org.jboss.tools.jst.css.dialog.selector.model.CSSSelectorTableModel; import org.jboss.tools.jst.css.dialog.selector.model.CSSSelectorTreeModel; import org.jboss.tools.jst.css.dialog.selector.model.CSSStyleSheetContainer; import org.jboss.tools.jst.css.dialog.selector.model.CSSTreeNode; import org.jboss.tools.jst.css.dialog.selector.selection.CSSClassSelectionChangedEvent; import org.jboss.tools.jst.css.dialog.selector.selection.CSSSelectionEventManager; import org.jboss.tools.jst.css.dialog.selector.selection.ICSSClassSelectionChangedListener; import org.jboss.tools.jst.css.dialog.selector.viewers.CSSSelectorFilter; import org.jboss.tools.jst.css.dialog.selector.viewers.CSSSelectorTableViewer; import org.jboss.tools.jst.css.dialog.selector.viewers.CSSSelectorTreeViewer; import org.jboss.tools.jst.jsp.jspeditor.JSPMultiPageEditor; import org.jboss.tools.jst.jsp.messages.JstUIMessages; import org.jboss.tools.jst.jsp.util.Constants; /** * * @author yzhishko * */ public class CSSSelectorPartComposite extends Composite implements SelectionListener { private static final int VIEWER_HEIGHT = 500; private static final int BUTTOND_WIDTH = 50; private static final int VIEWER_WIDTH = 175; /** Existing font family */ private Composite moveButtonsContainer; private Composite tableButtonsContainer; private Button rightButton; private Button leftButton; private Button upButton; private Button downButton; private String setClasses; private CSSSelectorTreeViewer allCSSStyleClassViewer; private CSSSelectorTableViewer selectedClassesTableViewer; private Map<String, Map<String, String>> allCSSClassStyles; private StyleAttributes styleAttributes; private CSSSelectorTreeModel styleClassTreeModel; private CSSSelectorFilter filter; private List<ICSSClassSelectionChangedListener> changedListeners = new ArrayList<ICSSClassSelectionChangedListener>( 0); public CSSSelectorPartComposite(StyleAttributes styleAttributes, Composite parentComposite, String setClasses) { super(parentComposite, SWT.BORDER); this.setClasses = setClasses; this.styleAttributes = styleAttributes; creatSelectorPart(); } private void creatSelectorPart() { initControls(); createLayout(); initListeners(); initDND(); initDefaultContent(); } private void initDefaultContent() { IEditorPart editorPart = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() .getActiveEditor(); if (!(editorPart instanceof JSPMultiPageEditor)) { return; } String[] selectedClasses = parseSetClasses(); selectedClassesTableViewer.setModel(new CSSSelectorTableModel(selectedClasses)); CSSJSPRecognizer recognizer = new CSSJSPRecognizer((JSPMultiPageEditor) editorPart); if (recognizer.parseCSS() == CSSJSPRecognizer.VOID_RESULT) { return; } styleClassTreeModel = recognizer.getCssStyleClassTreeModel(); allCSSClassStyles = recognizer.getCSSStyleMap(); allCSSStyleClassViewer.setModel(styleClassTreeModel); updateStyles(); } private void initDND() { Transfer[] types = new Transfer[] { TextTransfer.getInstance() }; allCSSStyleClassViewer.addDragSupport(DND.DROP_MOVE, types, new CSSTreeDragAdapter(this, allCSSStyleClassViewer, selectedClassesTableViewer)); selectedClassesTableViewer.addDragSupport(DND.DROP_MOVE, types, new CSSTableDragAdapter(this, allCSSStyleClassViewer, selectedClassesTableViewer)); allCSSStyleClassViewer.addDropSupport(DND.DROP_MOVE, types, new DropTargetAdapter() { @Override public void drop(DropTargetEvent event) { if (event.data == null || event.data.equals(CSSSelectorTreeViewer.CSS_SELECTOR_TREE_VIWER_ID)) { event.detail = DND.DROP_NONE; return; } } }); selectedClassesTableViewer.addDropSupport(DND.DROP_MOVE, types, new CSSTableDropAdapter(this, allCSSStyleClassViewer, selectedClassesTableViewer)); } private void initListeners() { allCSSStyleClassViewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { handleAddClass(); } }); selectedClassesTableViewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { handleRemoveClass(); } }); allCSSStyleClassViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(final SelectionChangedEvent event) { if (!CSSSelectionEventManager.getInstance().isHandleSelection()) { CSSSelectionEventManager.getInstance().setHandleSelection(true); return; } if (!event.getSelection().isEmpty()) { rightButton.setEnabled(true); leftButton.setEnabled(false); } else { rightButton.setEnabled(false); leftButton.setEnabled(false); } selectedClassesTableViewer.getTable().deselectAll(); checkForTableMove(event); if (event.getSelection().isEmpty()) { return; } Display.getCurrent().asyncExec(new Runnable() { public void run() { fireClassSelectionChanged(CSSSelectionEventManager.getInstance() .createTreeSelectionChangedEvent(event, allCSSStyleClassViewer.getModel())); } }); } }); selectedClassesTableViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(final SelectionChangedEvent event) { if (!CSSSelectionEventManager.getInstance().isHandleSelection()) { CSSSelectionEventManager.getInstance().setHandleSelection(true); return; } if (!event.getSelection().isEmpty()) { rightButton.setEnabled(false); leftButton.setEnabled(true); } else { rightButton.setEnabled(false); leftButton.setEnabled(false); } checkForTableMove(event); allCSSStyleClassViewer.getTree().deselectAll(); if (event.getSelection().isEmpty()) { return; } Display.getCurrent().asyncExec(new Runnable() { public void run() { fireClassSelectionChanged(CSSSelectionEventManager.getInstance() .createTableSelectionChangedEvent(event, allCSSStyleClassViewer.getModel())); } }); } }); allCSSStyleClassViewer.getTree().addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { if (SWT.ARROW_RIGHT == e.keyCode && SWT.ALT == e.stateMask) { handleAddClass(); } } public void keyPressed(KeyEvent e) { } }); selectedClassesTableViewer.getTable().addKeyListener(new KeyListener() { public void keyReleased(KeyEvent e) { if (SWT.ARROW_LEFT == e.keyCode && SWT.ALT == e.stateMask) { handleRemoveClass(); } } public void keyPressed(KeyEvent e) { } }); rightButton.addSelectionListener(this); leftButton.addSelectionListener(this); upButton.addSelectionListener(this); downButton.addSelectionListener(this); } private void checkForTableMove(SelectionChangedEvent event) { if (event.getSelection().isEmpty()) { upButton.setEnabled(false); downButton.setEnabled(false); return; } int[] selectionIndices = selectedClassesTableViewer.getTable().getSelectionIndices(); if (selectionIndices.length == 0) { upButton.setEnabled(false); downButton.setEnabled(false); return; } if (!isSequencedIndices(selectionIndices)) { upButton.setEnabled(true); downButton.setEnabled(true); } else { if (selectionIndices[0] != 0 && (selectionIndices[selectionIndices.length - 1] != selectedClassesTableViewer.getTable().getItemCount() - 1)) { upButton.setEnabled(true); downButton.setEnabled(true); } else if (selectionIndices[0] != 0) { downButton.setEnabled(false); upButton.setEnabled(true); } else if (selectionIndices[selectionIndices.length - 1] != selectedClassesTableViewer.getTable() .getItemCount() - 1) { downButton.setEnabled(true); upButton.setEnabled(false); } else if (selectionIndices[0] == 0 && (selectionIndices[selectionIndices.length - 1] == selectedClassesTableViewer.getTable().getItemCount() - 1)) { upButton.setEnabled(false); downButton.setEnabled(false); } } } private boolean isSequencedIndices(int[] indices) { for (int i = 0; i < indices.length - 1; i++) { if (indices[i + 1] - indices[i] != 1) return false; } return true; } private void initControls() { allCSSStyleClassViewer = new CSSSelectorTreeViewer(this, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); filter = new CSSSelectorFilter(); allCSSStyleClassViewer.addFilter(filter); moveButtonsContainer = new Composite(this, SWT.NONE); rightButton = new Button(moveButtonsContainer, SWT.PUSH); leftButton = new Button(moveButtonsContainer, SWT.PUSH); selectedClassesTableViewer = new CSSSelectorTableViewer(this, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); tableButtonsContainer = new Composite(this, SWT.NONE); upButton = new Button(tableButtonsContainer, SWT.PUSH); downButton = new Button(tableButtonsContainer, SWT.PUSH); rightButton.setToolTipText(JstUIMessages.CSS_ADD_CSS_CLASS_TIP); ImageDescriptor rightDesc = CSSPlugin.getImageDescriptor(Util.IMAGE_RIGHT_FILE_LOCATION); Image rightImage = rightDesc.createImage(); rightButton.setImage(rightImage); rightButton.setEnabled(false); rightButton.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { Button button = (Button) e.getSource(); button.getImage().dispose(); } }); leftButton.setToolTipText(JstUIMessages.CSS_REMOVE_CSS_CLASS_TIP); ImageDescriptor leftDesc = CSSPlugin.getImageDescriptor(Util.IMAGE_LEFT_FILE_LOCATION); Image leftImage = leftDesc.createImage(); leftButton.setImage(leftImage); leftButton.setEnabled(false); leftButton.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { Button button = (Button) e.getSource(); button.getImage().dispose(); } }); upButton.setToolTipText(JstUIMessages.CSS_MOVE_UP_CSS_CLASS_TIP); ImageDescriptor upDesc = CSSPlugin.getImageDescriptor(Util.IMAGE_UP_FILE_LOCATION); Image upImage = upDesc.createImage(); upButton.setImage(upImage); upButton.setEnabled(false); upButton.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { Button button = (Button) e.getSource(); button.getImage().dispose(); } }); downButton.setToolTipText(JstUIMessages.CSS_MOVE_DOWN_CSS_CLASS_TIP); ImageDescriptor downDesc = CSSPlugin.getImageDescriptor(Util.IMAGE_DOWN_FILE_LOCATION); Image downImage = downDesc.createImage(); downButton.setImage(downImage); downButton.setEnabled(false); downButton.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { Button button = (Button) e.getSource(); button.getImage().dispose(); } }); } private String[] parseSetClasses() { if (setClasses == null || setClasses.length() == 0) { return new String[0]; } StringTokenizer stringTokenizer = new StringTokenizer(setClasses.trim(), " ", false); //$NON-NLS-1$ java.util.List<String> list = new ArrayList<String>(0); while (stringTokenizer.hasMoreTokens()) { String token = stringTokenizer.nextToken(); list.add(token.trim()); } return list.toArray(new String[0]); } public void widgetDefaultSelected(SelectionEvent e) { Object ob = e.getSource(); if (ob.equals(leftButton)) { handleRemoveClass(); } else if (ob.equals(rightButton)) { handleAddClass(); } else if (ob.equals(upButton)) { handleMoveUp(); } else if (ob.equals(downButton)) { handleMoveDown(); } else if (ob.equals(allCSSStyleClassViewer.getTree())) { selectedClassesTableViewer.setSelection(new StructuredSelection()); } else if (ob.equals(selectedClassesTableViewer.getTable())) { allCSSStyleClassViewer.setSelection(new StructuredSelection()); } } private void handleMoveDown() { StructuredSelection selection = (StructuredSelection) selectedClassesTableViewer.getSelection(); Object[] selectedItems = selection.toArray(); int[] selectedIndices = selectedClassesTableViewer.getTable().getSelectionIndices(); int itemsCount = selectedClassesTableViewer.getTable().getItemCount(); int selectionLength = selectedIndices.length; for (int i = 0; i < selectionLength; i++) { CSSSelectionEventManager.getInstance().setHandleSelection(false); selectedClassesTableViewer.remove(selectedItems[selectionLength - 1 - i]); if (selectedIndices[selectionLength - 1 - i] == itemsCount - 1) { TableItem item = new TableItem(selectedClassesTableViewer.getTable(), selectedClassesTableViewer.getTable().getStyle(), itemsCount - 1); item.setData(selectedItems[selectionLength - 1 - i]); itemsCount--; } else { TableItem item = new TableItem(selectedClassesTableViewer.getTable(), selectedClassesTableViewer.getTable().getStyle(), selectedIndices[selectionLength - 1 - i] + 1); item.setData(selectedItems[selectionLength - 1 - i]); } } selectedClassesTableViewer.refresh(); selectedClassesTableViewer.setSelection(new StructuredSelection(selectedItems)); updateStyles(); } private void handleMoveUp() { StructuredSelection selection = (StructuredSelection) selectedClassesTableViewer.getSelection(); Object[] selectedItems = selection.toArray(); int[] selectedIndices = selectedClassesTableViewer.getTable().getSelectionIndices(); CSSSelectionEventManager.getInstance().setHandleSelection(false); selectedClassesTableViewer.remove(selection.toArray()); for (int i = 0; i < selectedIndices.length; i++) { if (selectedIndices[i] == i) { TableItem item = new TableItem(selectedClassesTableViewer.getTable(), selectedClassesTableViewer.getTable().getStyle(), i); item.setData(selectedItems[i]); } else { TableItem item = new TableItem(selectedClassesTableViewer.getTable(), selectedClassesTableViewer.getTable().getStyle(), selectedIndices[i] - 1); item.setData(selectedItems[i]); } } selectedClassesTableViewer.refresh(); selectedClassesTableViewer.setSelection(new StructuredSelection(selectedItems)); updateStyles(); } public void widgetSelected(SelectionEvent e) { Object ob = e.getSource(); if (ob.equals(leftButton)) { handleRemoveClass(); } else if (ob.equals(rightButton)) { handleAddClass(); } else if (ob.equals(upButton)) { handleMoveUp(); } else if (ob.equals(downButton)) { handleMoveDown(); } } private void handleRemoveClass() { TableItem[] selectedItems = selectedClassesTableViewer.getTable().getSelection(); if (selectedItems != null && selectedItems.length > 0) { List<String> itemsToRemove = new ArrayList<String>(0); for (int i = 0; i < selectedItems.length; i++) { itemsToRemove.add(selectedItems[i].getData().toString()); } selectedClassesTableViewer.remove(itemsToRemove.toArray()); updateStyles(); } } private void handleAddClass() { Set<String> itemsToMove = new LinkedHashSet<String>(0); TreeItem[] selectedItems = allCSSStyleClassViewer.getTree().getSelection(); if (selectedItems != null && selectedItems.length > 0) { for (int i = 0; i < selectedItems.length; i++) { TreeItem item = selectedItems[i]; CSSContainer container = ((CSSTreeNode) item.getData()).getCSSContainer(); CSSTreeNode treeNode = (CSSTreeNode) item.getData(); if ((container instanceof CSSStyleSheetContainer)) { List<CSSTreeNode> children = treeNode.getChildren(); for (int j = 0; j < children.size(); j++) { itemsToMove.add(children.get(j).toString()); } } else if (container instanceof CSSRuleContainer) { itemsToMove.add(treeNode.toString()); } } selectedClassesTableViewer.add(itemsToMove.toArray()); updateStyles(); allCSSStyleClassViewer.setSelection(new StructuredSelection()); } } private void createLayout() { final GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 4; setLayout(gridLayout); GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); setLayoutData(gridData); gridData = new GridData(SWT.FILL, SWT.FILL, true, true); gridData.heightHint = VIEWER_HEIGHT; gridData.widthHint = VIEWER_WIDTH; allCSSStyleClassViewer.getTree().setLayoutData(gridData); gridData = new GridData(SWT.FILL, SWT.FILL, true, true); gridData.heightHint = VIEWER_HEIGHT; gridData.widthHint = VIEWER_WIDTH; selectedClassesTableViewer.getTable().setLayoutData(gridData); final GridLayout moveBtnContGridLayout = new GridLayout(); moveBtnContGridLayout.numColumns = 1; moveButtonsContainer.setLayout(moveBtnContGridLayout); gridData = new GridData(SWT.FILL, SWT.FILL, true, true); gridData.widthHint = BUTTOND_WIDTH; rightButton.setLayoutData(gridData); gridData = new GridData(SWT.FILL, SWT.FILL, true, true); gridData.widthHint = BUTTOND_WIDTH; leftButton.setLayoutData(gridData); final GridLayout tableBtnContGridLayout = new GridLayout(); tableBtnContGridLayout.numColumns = 1; tableButtonsContainer.setLayout(tableBtnContGridLayout); } public void updateStyles() { String[] selectedItems = getItemsFromSelectedTable(); styleAttributes.clear(); if (filter == null) { filter = new CSSSelectorFilter(); allCSSStyleClassViewer.addFilter(filter); } filter.removeAllFilters(); if (selectedItems != null && selectedItems.length != 0) { selectedItems = getSortedStyleClasses(selectedItems); for (int i = 0; i < selectedItems.length; i++) { if (selectedItems[i] != null) { styleAttributes.putAll(allCSSClassStyles.get(selectedItems[i])); filter.addFilterName(selectedItems[i]); } } } allCSSStyleClassViewer.refresh(); } public String getCSSStyleClasses() { StringBuilder stringBuilder = new StringBuilder(""); //$NON-NLS-1$ String[] selectedItems = getItemsFromSelectedTable(); if (selectedItems != null && selectedItems.length != 0) { for (int i = 0; i < selectedItems.length - 1; i++) { stringBuilder.append(selectedItems[i] + " "); //$NON-NLS-1$ } stringBuilder.append(selectedItems[selectedItems.length - 1]); } return stringBuilder.toString(); } private String[] getSortedStyleClasses(String[] unsortedClasses) { String[] sortedStyleClasses = new String[unsortedClasses.length]; if (allCSSClassStyles != null) { Set<String> keySet = allCSSClassStyles.keySet(); int iter = 0; for (Iterator<String> iterator = keySet.iterator(); iterator.hasNext();) { String styleClassName = iterator.next(); for (int i = 0; i < unsortedClasses.length; i++) { if (unsortedClasses[i].equals(styleClassName)) { sortedStyleClasses[iter] = styleClassName; iter++; continue; } } } } return sortedStyleClasses; } private String[] getItemsFromSelectedTable() { TableItem[] selectedTableItems = selectedClassesTableViewer.getTable().getItems(); java.util.List<String> selectedItemsList = new ArrayList<String>(0); if (selectedTableItems != null) { for (int i = 0; i < selectedTableItems.length; i++) { selectedItemsList.add((String) selectedTableItems[i].getData()); } } return selectedItemsList.toArray(new String[0]); } private void fireClassSelectionChanged(final CSSClassSelectionChangedEvent event) { for (int i = 0; i < changedListeners.size(); i++) { final ICSSClassSelectionChangedListener listener = changedListeners.get(i); SafeRunner.run(new SafeRunnable() { public void run() throws Exception { for (int i = 0; i < changedListeners.size(); i++) { listener.classSelectionChanged(event); } } }); } } public synchronized void addCSSClassSelectionChangedListener(ICSSClassSelectionChangedListener listener) { changedListeners.add(listener); } public synchronized void removeCSSClassSelectionChangedListener(ICSSClassSelectionChangedListener listener) { changedListeners.remove(listener); } @Override public void dispose() { for (int i = 0; i < changedListeners.size(); i++) { removeCSSClassSelectionChangedListener(changedListeners.get(i)); } changedListeners = null; super.dispose(); } }