/* * ----------------------------------------------------------------------- * File: $HeadURL$ * Revision $LastChangedRevision$ * Last Modified: $LastChangedDate$ * Last Change by: $LastChangedBy$ * ----------------------------------------------------------------------- * Copyright (C) 2007 Keith Stribley <devel@thanlwinsoft.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * ----------------------------------------------------------------------- */ /** * */ package org.thanlwinsoft.languagetest.eclipse.views; import java.util.HashSet; import java.util.List; import java.util.Vector; import java.util.regex.Pattern; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.jface.action.Action; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxCellEditor; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.TreePath; import org.eclipse.search.core.text.TextSearchScope; import org.eclipse.search.ui.NewSearchUI; import org.eclipse.search.ui.text.FileTextSearchScope; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.RowData; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.thanlwinsoft.languagetest.MessageUtil; import org.thanlwinsoft.languagetest.eclipse.LanguageTestPlugin; import org.thanlwinsoft.languagetest.eclipse.editors.TestModuleEditor; import org.thanlwinsoft.languagetest.eclipse.search.TestItemQuery; import org.thanlwinsoft.languagetest.eclipse.search.TestItemSearchEngine; import org.thanlwinsoft.languagetest.eclipse.workspace.MetaDataManager; import org.thanlwinsoft.languagetest.eclipse.workspace.WorkspaceLanguageManager; import org.thanlwinsoft.languagetest.language.test.TestItemFilter; import org.thanlwinsoft.languagetest.language.test.meta.MetaFilter; import org.thanlwinsoft.languagetest.language.test.meta.MetaNode; import org.thanlwinsoft.schemas.languagetest.module.ConfigType; import org.thanlwinsoft.schemas.languagetest.module.LangType; import org.thanlwinsoft.schemas.languagetest.module.MetaDataType; import org.thanlwinsoft.schemas.languagetest.module.TestItemType; import org.thanlwinsoft.schemas.languagetest.module.TagType; /** * @author keith * */ public class TagFilterComposite extends ScrolledComposite implements ICheckStateListener { private Tree tree; private CheckboxTreeViewer viewer; private MetaDataContentProvider contentProvider; private MetaDataLabelProvider labelProvider; private Object [] rootElements = null; private IPath [] checkedPaths = null; private TestItemType testItem = null; private Menu popup; private MenuAction addTagAction; private MenuAction deleteTagAction; private MenuAction editTagAction; private MenuAction searchTagAction; /** * @param parent * @param style */ public TagFilterComposite(Composite parent, int style) { super(parent, style); init(); createMenu(); } protected void init() { tree = new Tree(this, SWT.MULTI | SWT.CHECK); tree.setHeaderVisible(false); tree.setEnabled(true); tree.setLinesVisible(true); TreeColumn nameColumn = new TreeColumn(tree, SWT.NONE); nameColumn.setWidth(400); nameColumn.setResizable(true); nameColumn.setText(MessageUtil.getString("FilterColumn")); tree.showColumn(nameColumn); viewer = new CheckboxTreeViewer(tree); viewer.setCellEditors(new CellEditor[] { new CheckboxCellEditor()}); contentProvider = new MetaDataContentProvider(); labelProvider = new MetaDataLabelProvider(this.getDisplay()); viewer.setContentProvider(contentProvider); viewer.setLabelProvider(labelProvider); viewer.addCheckStateListener(this); refresh(); setContent(tree); setExpandHorizontal(true); setExpandVertical(true); if (getParent().getLayout() instanceof RowLayout) { RowData treeRowData = new RowData(SWT.DEFAULT,200); setLayoutData(treeRowData); } else if (getParent().getLayout() instanceof GridLayout) { GridData treeGridData = new GridData(GridData.FILL); treeGridData.minimumHeight = 200; treeGridData.heightHint = 200; setLayoutData(treeGridData); } tree.setToolTipText(getTagPathDescription()); } protected void refresh() { ConfigType [] config = MetaDataManager.loadConfig(); // convert the config array into the top level MetaNodes // otherwise we can't compare MetaNodes from TreePaths rootElements = contentProvider.getElements(config); viewer.setInput(rootElements); viewer.refresh(); viewer.expandAll(); } protected void createMenu() { popup = new Menu(tree); addTagAction = new MenuAction(MessageUtil.getString("AddTagAction")) { public void run() { addItem(tree.getSelection()); } }; MenuItem addTag = new MenuItem(popup, SWT.PUSH); addTag.setText(addTagAction.getText()); addTag.addSelectionListener(addTagAction); editTagAction = new MenuAction(MessageUtil.getString("EditTagAction")) { public void run() { editItem(tree.getSelection()); } }; MenuItem editTag = new MenuItem(popup, SWT.PUSH); editTag.setText(editTagAction.getText()); editTag.addSelectionListener(editTagAction); deleteTagAction = new MenuAction(MessageUtil.getString("DeleteTagAction")) { public void run() { deleteItem(tree.getSelection()); } }; MenuItem deleteTag = new MenuItem(popup, SWT.PUSH); deleteTag.setText(deleteTagAction.getText()); deleteTag.addSelectionListener(deleteTagAction); searchTagAction = new MenuAction(MessageUtil.getString("SearchTagAction")) { public void run() { searchForTagItems(tree.getSelection()); } }; MenuItem searchTag = new MenuItem(popup, SWT.PUSH); searchTag.setText(searchTagAction.getText()); searchTag.addSelectionListener(searchTagAction); // enable it for right click popup.setEnabled(true); tree.setMenu(popup); // tree.addMouseListener(new MouseListener() // { // public void mouseDoubleClick(MouseEvent e) { } // public void mouseDown(MouseEvent e) // { // if (e.button == 3) // popup.setVisible(true); // } // public void mouseUp(MouseEvent e) {} // }); } /** * @param selection */ protected void searchForTagItems(TreeItem[] selection) { Vector <IPath> tags = new Vector<IPath>(selection.length); for (TreeItem item : selection) { if (item.getData() instanceof MetaNode) { tags.add(((MetaNode)item.getData()).toPath()); } } if (tags.size() == 0) return; // nothing to do TestItemFilter [] filters = { new MetaFilter(tags.toArray(new IPath[tags.size()]), MetaFilter.Mode.ALL) }; LangType [] langCodes = WorkspaceLanguageManager.findUserLanguages(); HashSet<String> langSet = new HashSet<String>(langCodes.length); for (int i = 0; i < langCodes.length; i++) { langSet.add(langCodes[i].getLang()); } String [] langs = langSet.toArray(new String[langSet.size()]); TestItemSearchEngine engine = new TestItemSearchEngine(langSet, filters); TextSearchScope scope = FileTextSearchScope.newWorkspaceScope(new String[] {"*.xml"}, false); Pattern searchPattern = Pattern.compile(""); final TestItemQuery query = new TestItemQuery(engine, scope, searchPattern, langs); NewSearchUI.runQueryInBackground(query); } /** * @param selection */ protected void deleteItem(TreeItem[] selection) { boolean deleted = false; for (TreeItem item : selection) { if (item.getData() instanceof MetaNode) { MetaNode mn = (MetaNode)item.getData(); if (MessageDialog.openQuestion(getShell(), MessageUtil.getString("DeleteTagTitle"), MessageUtil.getString("DeleteTagQuestion", mn.getPath()))) { if (!MetaDataManager.deleteNode(mn)) { MessageDialog.openWarning(getShell(), MessageUtil.getString("DeleteTagTitle"), MessageUtil.getString("TagDeleteFailed", mn.getPath())); } else deleted = true; } } } if (deleted) { refresh(); } } /** * @param selection */ protected void editItem(TreeItem[] selection) { EditTagDialog dialog = new EditTagDialog(this.getShell(), MessageUtil.getString("EditTagTitle"), MessageUtil.getString("EditTagDesc"), false); dialog.setSelection(selection); if (dialog.open() == 0) { MetaNode node = dialog.getMetaNode(); if (MetaDataManager.saveNode(node)) { refresh(); } else { MessageDialog.openWarning(getShell(), MessageUtil.getString("EditTagTitle"), MessageUtil.getString("TagEditFailed", node.getPath())); } } } /** * @param selection */ protected void addItem(TreeItem[] selection) { EditTagDialog dialog = new EditTagDialog(this.getShell(), MessageUtil.getString("AddTagTitle"), MessageUtil.getString("AddTagDesc"), true); dialog.setSelection(selection); if (dialog.open() == 0) { MetaNode node = dialog.getMetaNode(); if (MetaDataManager.saveNode(node)) { refresh(); } else { MessageDialog.openWarning(getShell(), MessageUtil.getString("AddTagTitle"), MessageUtil.getString("TagCreateFailed", node.getPath())); } } } public MetaNode [] getCheckedNodes() { Object [] elements = viewer.getCheckedElements(); MetaNode [] nodes = new MetaNode[elements.length]; for (int i = 0; i < elements.length; i++) { if (elements[i] instanceof MetaNode) { nodes[i] = (MetaNode)elements[i]; } } return nodes; } public IPath [] getCheckedTagPaths() { if (tree.isDisposed()) return checkedPaths; Object [] elements = viewer.getCheckedElements(); List <IPath>paths = new Vector<IPath>(elements.length); for (int i = 0; i < elements.length; i++) { if (elements[i] instanceof MetaNode) { MetaNode mn = (MetaNode)elements[i]; if (!mn.hasChildren()) paths.add(mn.toPath()); } } return paths.toArray(new IPath[paths.size()]); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent) */ public void checkStateChanged(CheckStateChangedEvent event) { if (event.getElement() instanceof MetaNode) { MetaNode mn = (MetaNode)event.getElement(); if (mn.hasChildren()) { // set all the children to this state //setChildrenState(mn, event.getChecked()); IPath path = mn.toPath(); Object [] segments = new Object[path.segmentCount()]; segments[0] = rootElements; MetaNode n = mn; for (int i = path.segmentCount() - 1; i >= 0 ; i--) { segments[i] = n; n = mn.getParent(); } TreePath tp = new TreePath(segments); viewer.expandToLevel(tp, CheckboxTreeViewer.ALL_LEVELS); viewer.setSubtreeChecked(tp, event.getChecked()); // normally branches will not have been checked, but it may // have once been a leaf, so force unchecking if (event.getChecked() == false) mn.setOnItem(testItem, event.getChecked()); if (testItem != null) setChildrenState(mn, event.getChecked()); } else { // only set the test item on leaves if (testItem != null) mn.setOnItem(testItem, event.getChecked()); } if (testItem != null) { IEditorPart editor = PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getActivePage().getActiveEditor(); if (editor instanceof TestModuleEditor) { TestModuleEditor tme = (TestModuleEditor)editor; tme.setDirty(true); } } } checkedPaths = getCheckedTagPaths(); tree.setToolTipText(getTagPathDescription()); } public String getTagPathDescription() { StringBuilder sb = new StringBuilder(); if (checkedPaths == null || checkedPaths.length == 0) { sb.append(MessageUtil.getString("NoTagsSelectedTooltip")); } else { if (checkedPaths.length == 1) sb.append(MessageUtil.getString("OneTagSelected")); else sb.append(MessageUtil.getString("TagsSelected", Integer.toString(checkedPaths.length))); final String eol = System.getProperty("line.separator"); for (IPath p : checkedPaths) { if (sb.length() > 0) sb.append(eol); sb.append(p); } } return sb.toString(); } /** set children of a branch node to the same state */ protected void setChildrenState(MetaNode mn, boolean state) { for (MetaNode child : mn.getChildren()) { if (child.hasChildren()) { setChildrenState(child, state); } else { // only set the test item on leaves child.setOnItem(testItem, state); } } } /* (non-Javadoc) * @see org.eclipse.swt.widgets.Control#setEnabled(boolean) */ @Override public void setEnabled(boolean enabled) { tree.setEnabled(enabled); super.setEnabled(enabled); } /** * Create a TreePath made up of MetaNode segments. * Only the ID is important, the descriptions can be left out. */ static TreePath pathToTreePath(IPath p) { Object [] segments = new Object[p.segmentCount()]; MetaDataType metaData = null; MetaNode mn = null; for (int i = 0; i < p.segmentCount(); i++) { metaData = MetaDataType.Factory.newInstance(); metaData.setMetaId(p.segment(i)); mn = new MetaNode(mn, metaData); segments[i] = mn; } return new TreePath(segments); } public void setTestItem(TestItemType ti) { this.testItem = null; labelProvider.setTestItem(ti); viewer.setSubtreeChecked(viewer.getTree().getTopItem(), false); if (ti != null && ti.sizeOfTagArray() > 0) { for (TagType t : ti.getTagArray()) { TreePath element = pathToTreePath(new Path(t.getRef())); viewer.setChecked(element, true); } } this.testItem = ti; checkedPaths = getCheckedTagPaths(); tree.setToolTipText(getTagPathDescription()); } public void setSelectedTags(IPath [] tags) { for (IPath t : tags) { TreePath element = pathToTreePath(t); if (!viewer.setChecked(element, true)) LanguageTestPlugin.log(IStatus.WARNING, "Tag " + t + " may not exist anymore."); } checkedPaths = tags; } class MenuAction extends Action implements SelectionListener { public MenuAction(String text) { super(text); } /* (non-Javadoc) * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetDefaultSelected(SelectionEvent e) { } /* (non-Javadoc) * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetSelected(SelectionEvent e) { run(); } } }