Java tutorial
/* * This file is part of the ZoRa project: http://www.photozora.org. * * ZoRa is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * ZoRa 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ZoRa; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * (c) 2016 Berthold Daum */ package com.bdaum.zoom.ui.internal.dialogs; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.TableDragSourceEffect; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.TextLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import com.bdaum.zoom.cat.model.asset.Asset; import com.bdaum.zoom.cat.model.meta.Category; import com.bdaum.zoom.cat.model.meta.CategoryImpl; import com.bdaum.zoom.cat.model.meta.Meta; import com.bdaum.zoom.core.Constants; import com.bdaum.zoom.core.Core; import com.bdaum.zoom.core.QueryField; import com.bdaum.zoom.core.internal.CoreActivator; import com.bdaum.zoom.core.internal.Utilities; import com.bdaum.zoom.core.internal.ai.IAiService; import com.bdaum.zoom.core.internal.ai.Prediction; import com.bdaum.zoom.core.internal.ai.Prediction.Token; import com.bdaum.zoom.css.ZColumnLabelProvider; import com.bdaum.zoom.image.ImageStore; import com.bdaum.zoom.image.ImageUtilities; import com.bdaum.zoom.operations.internal.CatResult; import com.bdaum.zoom.ui.dialogs.ZTitleAreaDialog; import com.bdaum.zoom.ui.internal.HelpContextIds; import com.bdaum.zoom.ui.internal.Icons; import com.bdaum.zoom.ui.internal.UiActivator; import com.bdaum.zoom.ui.internal.UiUtilities; import com.bdaum.zoom.ui.internal.VocabManager; import com.bdaum.zoom.ui.internal.hover.HoverInfo; import com.bdaum.zoom.ui.internal.hover.HoveringController; import com.bdaum.zoom.ui.internal.hover.IGalleryHover; import com.bdaum.zoom.ui.internal.hover.IHoverInfo; import com.bdaum.zoom.ui.internal.views.EffectDropTargetListener; import com.bdaum.zoom.ui.internal.views.IHoverSubject; import com.bdaum.zoom.ui.internal.views.ImageRegion; import com.bdaum.zoom.ui.internal.views.ZColumnViewerToolTipSupport; import com.bdaum.zoom.ui.internal.widgets.CheckboxButton; import com.bdaum.zoom.ui.internal.widgets.CheckedText; import com.bdaum.zoom.ui.internal.widgets.RadioButtonGroup; import com.bdaum.zoom.ui.internal.widgets.WidgetFactory; import com.bdaum.zoom.ui.preferences.PreferenceConstants; import com.bdaum.zoom.ui.widgets.CGroup; import com.bdaum.zoom.ui.widgets.CLink; @SuppressWarnings("restriction") public class CategorizeDialog extends ZTitleAreaDialog implements IHoverSubject, KeyListener { private final class PairLabelProvider extends ZColumnLabelProvider { @Override public String getText(Object element) { if (element instanceof Token) return ((Token) element).getMatch() != 0 ? Messages.CategorizeDialog_match : null; return element.toString(); } @Override protected Color getForeground(Object element) { if (element instanceof Token) { switch (((Token) element).getMatch()) { case CHECKED: case PROPOSED: return catCanvas.getDisplay().getSystemColor(SWT.COLOR_RED); case SUPPLEMENTAL: case SUPPROPOSED: return catCanvas.getDisplay().getSystemColor(SWT.COLOR_YELLOW); } } return super.getForeground(element); } } private final class CategoryLabelProvider extends ZColumnLabelProvider { private VocabManager vManager; public CategoryLabelProvider(VocabManager vManager) { this.vManager = vManager; } @Override public String getToolTipText(Object element) { if (element instanceof Token && UiActivator.getDefault().getShowHover()) { Token token = (Token) element; String title; switch (token.getMatch()) { case SUPPROPOSED: title = NLS.bind(Messages.CategorizeDialog_as_supplemental, token.getCategory()); break; case PROPOSED: title = NLS.bind(Messages.CategorizeDialog_as_primary, token.getCategory()); break; default: title = Messages.CategorizeDialog_no_match; } String label = token.getLabel(); String mapped = vManager.getVocab(label); String warning = mapped == null ? Messages.CategorizeDialog_not_contained_in_vocab : mapped.equals(label) ? "" : NLS.bind(Messages.CategorizeDialog_will_be_replaced, mapped); //$NON-NLS-1$ return NLS.bind(Messages.CategorizeDialog_proposal_hover, new Object[] { label, title, predictions.get(currentAsset.getStringId()).getServiceName(), warning }); } return super.getToolTipText(element); } @Override public Image getToolTipImage(Object element) { return getImage(element); } @Override public String getText(Object element) { return element.toString(); } @Override public Image getImage(Object element) { if (element instanceof Token) { String label = ((Token) element).getLabel(); String mapped = vManager.getVocab(label); if (mapped == null) return Icons.warning.getImage(); else if (!mapped.equals(label)) return Icons.info.getImage(); } return null; } } public class PredictionJob extends Job { private List<Asset> assets; private Map<String, Prediction> predictions; @Override public boolean belongsTo(Object family) { return CategorizeDialog.this == family; } public PredictionJob(List<Asset> assets, Map<String, Prediction> predictions) { super(Messages.CategorizeDialog_collecting); this.assets = assets; this.predictions = predictions; setSystem(true); setPriority(DECORATE); } @Override protected IStatus run(IProgressMonitor monitor) { if (aiService == null) return Status.CANCEL_STATUS; monitor.beginTask(Messages.CategorizeDialog_collecting, assets.size() * 2); int latency = aiService.getLatency(null); for (Asset asset : assets) { Prediction prediction = aiService.predict(ImageUtilities.asJpeg(asset.getJpegThumbnail()), null); String assetId = asset.getStringId(); predictions.put(assetId, prediction); if (monitor.isCanceled()) return Status.CANCEL_STATUS; predictionReady(assetId); monitor.worked(1); if (latency > 0) try { Thread.sleep(latency); } catch (InterruptedException e) { // do nothing } if (monitor.isCanceled()) return Status.CANCEL_STATUS; monitor.worked(1); } return Status.OK_STATUS; } } public class ProposalDropTargetListener extends EffectDropTargetListener { private int ops; public ProposalDropTargetListener(Control control, int ops) { super(control); this.ops = ops; final DropTarget target = new DropTarget(control, ops); target.setTransfer(new Transfer[] { selectionTransfer }); target.addDropListener(this); } @Override public void dragEnter(DropTargetEvent event) { int detail = event.detail; event.detail = DND.DROP_NONE; for (int i = 0; i < event.dataTypes.length; i++) { if (selectionTransfer.isSupportedType(event.dataTypes[i])) { event.currentDataType = event.dataTypes[i]; if ((detail & ops) != 0) { event.detail = detail; break; } } } super.dragEnter(event); } @Override public void dragOver(DropTargetEvent event) { event.detail = checkOperations(event); super.dragOver(event); } private int checkOperations(DropTargetEvent event) { if (selectionTransfer.isSupportedType(event.currentDataType)) { Point p = control.toControl(event.x, event.y); Node found = root.findNode(p.x, p.y); if (found != null) { if (event.detail != DND.DROP_COPY) return DND.DROP_MOVE; return DND.DROP_COPY; } if (event.detail == DND.DROP_COPY) return DND.DROP_COPY; } return DND.DROP_NONE; } @Override public void dragOperationChanged(DropTargetEvent event) { event.detail = (event.detail & ops) != 0 ? checkOperations(event) : DND.DROP_NONE; } @Override public void drop(DropTargetEvent event) { if (selectionTransfer.isSupportedType(event.currentDataType)) { StructuredSelection sel = (StructuredSelection) event.data; Token token = (Token) sel.getFirstElement(); if (token != null) { Point p = control.toControl(event.x, event.y); Node found = root.findNode(p.x, p.y); if ((event.detail & DND.DROP_COPY) != 0) { if (catBackup == null) catBackup = Utilities.cloneCategories(categories); Category cat = new CategoryImpl(token.getLabel()); Category parent = null; if (found != null) parent = found.getCat(); EditCategoryDialog dialog = new EditCategoryDialog(getShell(), cat, categories, null, parent, true); if (dialog.open() == EditCategoryDialog.OK) { String label = dialog.getLabel(); cat.setLabel(label); cat.setSynonyms(dialog.getSynonyms()); Node newNode; if (found != null) { parent.putSubCategory(cat); cat.setCategory_subCategory_parent(parent); newNode = new Node(found, cat); found.addChild(newNode); } else { categories.put(label, cat); newNode = new Node(root, cat); root.addChild(newNode); } configureTree(); if (root.has(CHECKED)) newNode.setChecked(SUPPLEMENTAL, false); else { root.degrade(PROPOSED, SUPPROPOSED); newNode.setChecked(CHECKED, false); } token.setCategory(label); token.setMatch(newNode.getChecked() == CHECKED ? PROPOSED : SUPPROPOSED); proposalViewer1.update(token, null); proposalViewer.update(token, null); drawCat(); } } else if (found != null) { found.addSynonym(token.getLabel()); token.setCategory(found.getCat().getLabel()); if (found.getChecked() != CHECKED && found.getChecked() != SUPPLEMENTAL) { found.setChecked(root.has(CHECKED) ? SUPPLEMENTAL : CHECKED, false); drawCat(); } token.setMatch(found.getChecked() == CHECKED ? PROPOSED : SUPPROPOSED); proposalViewer1.update(token, null); proposalViewer.update(token, null); } updateButtons(); } } } } public final class ProposalDragSourceListener extends TableDragSourceEffect { private CheckboxTableViewer viewer; public ProposalDragSourceListener(CheckboxTableViewer viewer) { super(viewer.getTable()); this.viewer = viewer; } public void dragStart(DragSourceEvent event) { IStructuredSelection selection = viewer.getStructuredSelection(); Object firstElement = selection.getFirstElement(); if (firstElement != null) { event.doit = true; selectionTransfer.setSelection(selection); event.detail = DND.DROP_MOVE; super.dragStart(event); return; } event.doit = false; } public void dragFinished(DragSourceEvent event) { selectionTransfer.setSelection(null); super.dragFinished(event); } } public class CatHoverInfo implements IHoverInfo { private Node node; public CatHoverInfo(Node node) { this.node = node; } @Override public String getText() { StringBuilder sb = new StringBuilder(); String[] synonyms = node.getCat().getSynonyms(); if (synonyms != null && synonyms.length > 0) sb.append(Messages.CategorizeDialog_synonyms).append(Core.toStringList(synonyms, ", ")) //$NON-NLS-1$ .append('\n'); sb.append(Messages.CategorizeDialog_set_as); switch (node.getChecked()) { case CHECKED: sb.append(Messages.CategorizeDialog_primaryClick); break; case SUPPLEMENTAL: sb.append(Messages.CategorizeDialog_supplementalClick); break; case PROPOSED: sb.append(Messages.CategorizeDialog_proposedClick); break; case SUPPROPOSED: sb.append(Messages.CategorizeDialog_click_proposed_sup); break; default: sb.append(Messages.CategorizeDialog_nilClick); break; } return sb.toString(); } @Override public String getTitle() { return NLS.bind(Messages.CategorizeDialog_category, node.cat.getLabel()); } @Override public ImageRegion[] getRegions() { return null; } @Override public Object getObject() { return node; } } public class CatDialogHover implements IGalleryHover { @Override public IHoverInfo getHoverInfo(IHoverSubject viewer, MouseEvent event) { if (event.widget == imageCanvas) return new HoverInfo(currentAsset, (ImageRegion[]) null); Node found = root.findNode(event.x, event.y); if (found != null) return new CatHoverInfo(found); return null; } } private static final class NodeComparator implements Comparator<Node> { @Override public int compare(Node n1, Node n2) { return n1.getCat().getLabel().compareTo(n2.getCat().getLabel()); } } private class Node { private Category cat; private int level; private int pos; private int checked; private Node parent; private List<Node> children; private Rectangle rect; private Rectangle covered; public Node(Node parent, Category cat) { this.parent = parent; this.cat = cat; } public void addSynonym(String label) { if (cat != null) { if (label.equalsIgnoreCase(cat.getLabel())) return; String[] synonyms = cat.getSynonyms(); if (synonyms != null) for (String syn : synonyms) if (label.equalsIgnoreCase(syn)) return; if (catBackup == null) catBackup = Utilities.cloneCategories(categories); if (synonyms == null) cat.setSynonyms(new String[] { label }); else { String[] newSyns = new String[synonyms.length + 1]; System.arraycopy(synonyms, 0, newSyns, 0, synonyms.length); newSyns[synonyms.length] = label; cat.setSynonyms(newSyns); } } } public int getChecked() { return checked; } public void setChecked(int checked, boolean deep) { this.checked = checked; if (deep && children != null) for (Node child : children) child.setChecked(checked, deep); } public Category getCat() { return cat; } public void addChild(Node child) { if (children == null) children = new ArrayList<>(); children.add(child); } public void configureTree(Point dim, int level) { pos = dim.y; this.level = level; dim.x = Math.max(level, dim.x); if (children != null && !children.isEmpty()) { Collections.sort(children, comparator); for (Node child : children) child.configureTree(dim, level + 1); } else ++dim.y; } public void draw(GC gc, int x, int y, int distX, int distY) { if (level >= 0) { int nx = x + distX * level; int ny = y + distY * pos; rect = new Rectangle(nx, ny, 10, 10); switch (checked) { case CHECKED: Color background = gc.getBackground(); gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_RED)); gc.fillRectangle(rect); gc.setBackground(background); break; case SUPPLEMENTAL: background = gc.getBackground(); gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_YELLOW)); gc.fillRectangle(rect); gc.setBackground(background); break; case PROPOSED: Color foreground = gc.getForeground(); gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_RED)); gc.drawRectangle(rect); gc.setForeground(foreground); break; case SUPPROPOSED: foreground = gc.getForeground(); gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_YELLOW)); gc.drawRectangle(rect); gc.setForeground(foreground); break; default: gc.drawRectangle(rect); break; } Color foreground = gc.getForeground(); gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_CYAN)); Point textExtent = gc.textExtent(cat.getLabel()); gc.drawText(cat.getLabel(), nx + 13, ny + 6); if (covered == null) covered = new Rectangle(nx, ny, 10, 10); covered.x = nx; covered.y = ny; covered.width = 13 + textExtent.x; covered.height = 6 + textExtent.y; gc.setForeground(foreground); if (parent != null && parent.level >= 0) { int px = x + distX * parent.level + 10; int nx0 = nx; int ny0 = ny + 5; if (parent.pos == pos) gc.drawLine(px, ny0, nx0, ny0); else { int mx = (px + nx0) / 2; gc.drawLine(mx, ny0, nx0, ny0); gc.drawLine(mx, y + distY * parent.pos + 5, mx, ny0); } } } if (children != null) for (Node child : children) child.draw(gc, x, y, distX, distY); } public Node findNode(int mx, int my) { if (covered != null && covered.contains(mx, my)) return this; if (children != null) for (Node child : children) { Node found = child.findNode(mx, my); if (found != null) return found; } return null; } public Node find(String lab) { if (lab != null) { if (cat != null) { if (lab.equalsIgnoreCase(cat.getLabel())) return this; String[] synonyms = cat.getSynonyms(); if (synonyms != null) for (String syn : synonyms) { if (lab.equalsIgnoreCase(syn)) return this; } } if (children != null) for (Node child : children) { Node found = child.find(lab); if (found != null) return found; } } return null; } public void degrade(int was, int tobe) { if (checked == was) checked = tobe; if (children != null) for (Node child : children) child.degrade(was, tobe); } public String getSelection(List<String> supplemental, int primFlag, int supFlag) { String primary = null; if (cat != null) { if (checked == primFlag) primary = cat.getLabel(); else if (checked == supFlag) supplemental.add(cat.getLabel()); } if (children != null) for (Node child : children) { String prim = child.getSelection(supplemental, primFlag, supFlag); if (primary == null) primary = prim; } return primary; } @Override public String toString() { return cat.getLabel(); } public void sort() { if (children != null) { Collections.sort(children, comparator); for (Node child : children) child.sort(); } } public boolean has(int flags) { if ((checked & flags) != 0) return true; if (children != null) for (Node child : children) if (child.has(flags)) return true; return false; } public void acceptProposals(boolean hasPrimary) { if (checked == SUPPROPOSED || checked == PROPOSED && hasPrimary) checked = SUPPLEMENTAL; else if (checked == PROPOSED) { checked = CHECKED; hasPrimary = true; } if (children != null) for (Node child : children) child.acceptProposals(hasPrimary); } public void transferTo(Node root) { if (cat != null) { Node found = root.find(cat.getLabel()); if (found != null) found.setChecked(checked, false); } if (children != null) for (Node child : children) child.transferTo(root); } } private static final int BACK_ID = 101; private static final int NEXT_ID = 102; private static final int CLONE_ID = 103; private static final int DONE_ID = 104; private static final int MARGINS = 15; private static final int UNCHECKED = 0; private static final int PROPOSED = 1; private static final int SUPPROPOSED = 2; private static final int SUPPLEMENTAL = 4; private static final int CHECKED = 8; private static final LocalSelectionTransfer selectionTransfer = LocalSelectionTransfer.getTransfer(); private List<Asset> assets; private int current = 0; private int size; private TextLayout textLayout; private Canvas imageCanvas; private Canvas catCanvas; private Asset currentAsset; private ImageStore imageCache; private Node root = new Node(null, null); private int depth; private int width; private HoveringController hoveringController; private static final NodeComparator comparator = new NodeComparator(); private Composite comp; private CatResult[] result; private boolean forcePrimary; private CheckboxTableViewer proposalViewer; private Composite stack; private StackLayout stackLayout; private Composite propComp; private Composite msgComp; private Label msgLabel; private boolean cloned; private CLink acceptLink; private Map<String, Category> categories; private Map<String, Category> catBackup; private Meta meta; private Map<String, Prediction> predictions; private IAiService aiService; private Set<String> newKeywords = new HashSet<>(); private RadioButtonGroup newPrivacyGroup; private CheckboxButton faceButton; private CheckedText descriptionField; private Label proposalTitle; private int showRegions; private ArrayList<ImageRegion> currentRegions; private Composite splitComp; private CheckboxTableViewer proposalViewer1; private CheckboxTableViewer proposalViewer2; private List<Rectangle> newFaces; private Rectangle imageBounds; private VocabManager vocabManager; public CategorizeDialog(Shell parentShell, List<Asset> localAssets) { super(parentShell, HelpContextIds.CATEGORIZE_DIALOG); setShellStyle(getShellStyle() | SWT.RESIZE); this.assets = localAssets; this.size = assets.size(); result = new CatResult[size]; imageCache = CoreActivator.getDefault().getImageCache(); meta = dbManager.getMeta(true); categories = meta.getCategory(); constructTree(categories); predictions = new HashMap<>(size * 3 / 2); aiService = CoreActivator.getDefault().getAiService(); showRegions = UiActivator.getDefault().getPreferenceStore().getInt(PreferenceConstants.MAXREGIONS); startPredictionJob(assets); } private VocabManager getVocabManager() { if (vocabManager == null) vocabManager = new VocabManager(Core.getCore().getDbManager().getMeta(true).getVocabularies(), this); return vocabManager; } public void predictionReady(String assetId) { if (currentAsset != null && assetId == currentAsset.getStringId()) { final Shell shell = getShell(); if (!shell.isDisposed()) shell.getDisplay().asyncExec(() -> { if (!shell.isDisposed()) fillValues(false); }); } } private void startPredictionJob(List<Asset> assets) { Job.getJobManager().cancel(this); if (aiService != null && aiService.isEnabled()) new PredictionJob(assets, predictions).schedule(); } private void constructTree(Map<String, Category> categories) { root = new Node(null, null); if (categories != null) { for (Category category : categories.values()) if (category != null) root.addChild(createCatTree(root, category)); configureTree(); } } private void configureTree() { root.sort(); Point dim = new Point(0, 0); root.configureTree(dim, -1); depth = dim.x; width = dim.y; } private Node createCatTree(Node parent, Category category) { Node node = new Node(parent, category); Map<String, Category> subCategories = category.getSubCategory(); if (subCategories != null) for (Category sub : subCategories.values()) if (sub != null) node.addChild(createCatTree(node, sub)); return node; } @Override public void create() { super.create(); getShell().setText(Constants.APPLICATION_NAME); setTitle(Messages.CategorizeDialog_categorize_images); setMessage(size > 1 ? Messages.CategorizeDialog_select_cats : Messages.CategorizeDialog_select_cats1); fillValues(false); } @Override protected Control createDialogArea(Composite parent) { Composite area = (Composite) super.createDialogArea(parent); comp = new Composite(area, SWT.NONE); comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); comp.setLayout(new GridLayout(aiService != null ? 3 : 2, false)); createImageArea(); createCategoryArea(); if (aiService != null) createProposalArea(); hoveringController = new HoveringController(this); hoveringController.install(); return area; } @SuppressWarnings("unused") protected void createProposalArea() { Composite proposalArea = new Composite(comp, SWT.NONE); proposalArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); proposalArea.setLayout(new GridLayout(1, false)); proposalTitle = new Label(proposalArea, SWT.NONE); proposalTitle.setFont(JFaceResources.getHeaderFont()); proposalTitle.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); setProposalTitel(); stack = new Composite(proposalArea, SWT.BORDER); stack.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); stackLayout = new StackLayout(); stack.setLayout(stackLayout); PairLabelProvider pairLabelProvider = new PairLabelProvider(); CategoryLabelProvider catLabelProvider = new CategoryLabelProvider(getVocabManager()); ISelectionChangedListener selectionChangedListener = new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { updateButtons(); } }; // Unsplit version propComp = new Composite(stack, SWT.NONE); propComp.setLayout(new GridLayout(2, false)); Label label = new Label(propComp, SWT.NONE); label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 2, 1)); label.setText(Messages.CategorizeDialog_mark_keywords); proposalViewer = CheckboxTableViewer.newCheckList(propComp, SWT.V_SCROLL); GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); layoutData.widthHint = 200; proposalViewer.getTable().setLayoutData(layoutData); TableViewerColumn col1 = new TableViewerColumn(proposalViewer, SWT.NONE); col1.getColumn().setWidth(150); col1.setLabelProvider(catLabelProvider); TableViewerColumn col2 = new TableViewerColumn(proposalViewer, SWT.NONE); col2.getColumn().setWidth(70); col2.setLabelProvider(pairLabelProvider); proposalViewer.setContentProvider(ArrayContentProvider.getInstance()); proposalViewer.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY, new Transfer[] { selectionTransfer }, new ProposalDragSourceListener(proposalViewer)); proposalViewer.addSelectionChangedListener(selectionChangedListener); ZColumnViewerToolTipSupport.enableFor(proposalViewer); Composite buttonArea = new Composite(propComp, SWT.NONE); buttonArea.setLayoutData(new GridData(SWT.END, SWT.BEGINNING, false, false)); buttonArea.setLayout(new GridLayout(1, false)); new AllNoneGroup(buttonArea, new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { proposalViewer.setAllChecked(e.widget.getData() == AllNoneGroup.ALL); updateButtons(); } }); Button button = new Button(buttonArea, SWT.PUSH); button.setText(Messages.CategorizeDialog_select_unpaired); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { Token[] tokens = (Token[]) proposalViewer.getInput(); for (Token tok : tokens) { proposalViewer.setChecked(tok, tok.getMatch() == UNCHECKED); } } }); // Split version splitComp = new Composite(stack, SWT.NONE); splitComp.setLayout(new GridLayout(2, false)); Label catLabel = new Label(splitComp, SWT.NONE); catLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, true, false, 2, 1)); catLabel.setFont(JFaceResources.getBannerFont()); catLabel.setText(Messages.CategorizeDialog_proposed_as_categories); Label catLabel2 = new Label(splitComp, SWT.NONE); catLabel2.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, true, false, 2, 1)); catLabel2.setText(Messages.CategorizeDialog_can_be_marked_as_keywords); proposalViewer1 = CheckboxTableViewer.newCheckList(splitComp, SWT.V_SCROLL); layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); layoutData.widthHint = 200; layoutData.heightHint = 100; proposalViewer1.getTable().setLayoutData(layoutData); col1 = new TableViewerColumn(proposalViewer1, SWT.NONE); col1.getColumn().setWidth(150); col1.setLabelProvider(catLabelProvider); col2 = new TableViewerColumn(proposalViewer1, SWT.NONE); col2.getColumn().setWidth(70); col2.setLabelProvider(pairLabelProvider); proposalViewer1.setContentProvider(ArrayContentProvider.getInstance()); proposalViewer1.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY, new Transfer[] { selectionTransfer }, new ProposalDragSourceListener(proposalViewer1)); proposalViewer1.addSelectionChangedListener(selectionChangedListener); ColumnViewerToolTipSupport.enableFor(proposalViewer1); Composite buttonArea1 = new Composite(splitComp, SWT.NONE); buttonArea1.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, true, false)); buttonArea1.setLayout(new GridLayout(1, false)); new AllNoneGroup(buttonArea1, new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { proposalViewer1.setAllChecked(e.widget.getData() == AllNoneGroup.ALL); updateButtons(); } }); button = new Button(buttonArea1, SWT.PUSH); button.setText(Messages.CategorizeDialog_select_unpaired); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { Token[] tokens = (Token[]) proposalViewer1.getInput(); for (Token tok : tokens) proposalViewer1.setChecked(tok, tok.getMatch() == UNCHECKED); } }); Label keyLabel = new Label(splitComp, SWT.NONE); keyLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, true, true, 2, 1)); keyLabel.setFont(JFaceResources.getBannerFont()); keyLabel.setText(Messages.CategorizeDialog_proposed_as_keywords); proposalViewer2 = CheckboxTableViewer.newCheckList(splitComp, SWT.V_SCROLL); layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); layoutData.widthHint = 200; layoutData.heightHint = 300; proposalViewer2.getTable().setLayoutData(layoutData); proposalViewer2.setLabelProvider(new ColumnLabelProvider()); proposalViewer2.setContentProvider(ArrayContentProvider.getInstance()); proposalViewer2.addSelectionChangedListener(selectionChangedListener); Composite buttonArea2 = new Composite(splitComp, SWT.NONE); buttonArea2.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, true, false)); buttonArea2.setLayout(new GridLayout(1, false)); new AllNoneGroup(buttonArea2, new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { proposalViewer2.setAllChecked(e.widget.getData() == AllNoneGroup.ALL); updateButtons(); } }); // Messages msgComp = new Composite(stack, SWT.NONE); msgComp.setLayout(new GridLayout(1, false)); msgLabel = new Label(msgComp, SWT.CENTER | SWT.WRAP); GridData ldata = new GridData(SWT.FILL, SWT.CENTER, true, true); ldata.heightHint = 30; msgLabel.setLayoutData(ldata); CLink aiLink = new CLink(proposalArea, SWT.NONE); aiLink.setText(Messages.CategorizeDialog_configure); aiLink.setToolTipText(Messages.CategorizeDialog_user_preferences); aiLink.addListener(new Listener() { @Override public void handleEvent(Event event) { if (aiService != null) { boolean wasEnabled = aiService.isEnabled(); if (wasEnabled) Job.getJobManager().cancel(this); if (aiService.configure(getShell())) { boolean enabled = aiService.isEnabled(); setProposalTitel(); List<Asset> reordered; int p = assets.indexOf(currentAsset); reordered = p > 0 ? assets.subList(p, assets.size()) : assets; for (Asset asset : reordered) predictions.remove(asset.getStringId()); fillValues(false); // TODO could be improved when language can be // controlled through API if (enabled) startPredictionJob(reordered); } } } }); } @SuppressWarnings("unused") protected void createCategoryArea() { Composite catArea = new Composite(comp, SWT.NONE); catArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); catArea.setLayout(new GridLayout(1, false)); Label catLabel = new Label(catArea, SWT.NONE); catLabel.setFont(JFaceResources.getHeaderFont()); catLabel.setText(Messages.CategorizeDialog_categories); textLayout = new TextLayout(getShell().getDisplay()); textLayout.setAlignment(SWT.CENTER); catCanvas = new Canvas(catArea, SWT.BORDER); GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); layoutData.widthHint = Math.min(800, depth * 200); layoutData.heightHint = Math.min(600, width * 20); catCanvas.setLayoutData(layoutData); catCanvas.addPaintListener(new PaintListener() { @Override public void paintControl(PaintEvent e) { Rectangle clientArea = catCanvas.getClientArea(); e.gc.fillRectangle(clientArea); root.draw(e.gc, MARGINS, MARGINS, Math.max(20, (clientArea.width - 2 * MARGINS) / (depth + 1)), Math.max(15, (clientArea.height - 2 * MARGINS) / (width + 1))); } }); catCanvas.addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent e) { boolean alt = (e.stateMask & SWT.ALT) == SWT.ALT; Node found = findObject(e); if (found != null) { int check = found.getChecked(); switch (check) { case CHECKED: found.setChecked(alt ? SUPPLEMENTAL : UNCHECKED, false); break; case SUPPLEMENTAL: case PROPOSED: if (alt) found.setChecked(UNCHECKED, false); else { root.degrade(PROPOSED, SUPPROPOSED); root.degrade(CHECKED, SUPPLEMENTAL); found.setChecked(CHECKED, false); } break; case SUPPROPOSED: found.setChecked(alt ? UNCHECKED : SUPPLEMENTAL, false); break; default: if (alt || forcePrimary) { root.degrade(PROPOSED, SUPPROPOSED); root.degrade(CHECKED, SUPPLEMENTAL); found.setChecked(CHECKED, false); } else found.setChecked(SUPPLEMENTAL, false); break; } drawCat(); forcePrimary = false; } } }); catCanvas.addKeyListener(this); new ProposalDropTargetListener(catCanvas, DND.DROP_MOVE | DND.DROP_COPY); Composite linkArea = new Composite(catArea, SWT.NONE); linkArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); GridLayout layout = new GridLayout(2, false); layout.marginHeight = 0; linkArea.setLayout(layout); CLink catLink = new CLink(linkArea, SWT.NONE); catLink.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false)); catLink.setText(Messages.CategorizeDialog_configure); catLink.setToolTipText(Messages.CategorizeDialog_configure_tooltip); catLink.addListener(new Listener() { @Override public void handleEvent(Event event) { final Shell shell = getShell(); BusyIndicator.showWhile(shell.getDisplay(), () -> { IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (activeWorkbenchWindow != null) { IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage(); if (activePage != null) { EditMetaDialog mdialog = new EditMetaDialog(shell, activePage, Core.getCore().getDbManager(), false, null); mdialog.setInitialPage(EditMetaDialog.CATEGORIES); if (catBackup != null) mdialog.setCategories(catBackup); if (mdialog.open() == EditMetaDialog.OK) { categories = mdialog.getCategories(); catBackup = null; Node oldRoot = root; constructTree(categories); oldRoot.transferTo(root); drawCat(); updateButtons(); } } } }); } }); acceptLink = new CLink(linkArea, SWT.NONE); acceptLink.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, false)); acceptLink.setText(Messages.CategorizeDialog_accept_proposals); acceptLink.setToolTipText(Messages.CategorizeDialog_accept_proposals_tooltip); acceptLink.addListener(new Listener() { @Override public void handleEvent(Event event) { root.acceptProposals(root.has(CHECKED)); drawCat(); updateButtons(); } }); } protected void createImageArea() { Composite imageArea = new Composite(comp, SWT.NONE); imageArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); imageArea.setLayout(new GridLayout(1, false)); Label imageLabel = new Label(imageArea, SWT.NONE); imageLabel.setFont(JFaceResources.getHeaderFont()); imageLabel.setText(Messages.CategorizeDialog_image); imageCanvas = new Canvas(imageArea, SWT.BORDER); GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); layoutData.widthHint = 350; layoutData.heightHint = 450; imageCanvas.setLayoutData(layoutData); imageCanvas.addPaintListener(new PaintListener() { @Override public void paintControl(PaintEvent e) { Image image = imageCache.getImage(currentAsset); imageBounds = image.getBounds(); int imageSize = Math.max(imageBounds.width, imageBounds.height); Rectangle clientArea = imageCanvas.getClientArea(); GC gc = e.gc; gc.fillRectangle(clientArea); int canvasSize = Math.max(10, Math.min(clientArea.width, clientArea.height) - 2 * MARGINS); double factor = (double) Math.min(320, canvasSize) / imageSize; int destWidth = (int) (imageBounds.width * factor); int destHeight = (int) (imageBounds.height * factor); int destX = (clientArea.width - destWidth) / 2; int destY = (Math.min(350, clientArea.height) - destHeight) / 2; gc.drawImage(image, 0, 0, imageBounds.width, imageBounds.height, destX, destY, destWidth, destHeight); currentRegions = null; if (showRegions > 0) { Color color = gc.getForeground(); currentRegions = UiUtilities.drawRegions(gc, currentAsset, destX, destY, destWidth, destHeight, true, showRegions, true, null); gc.setForeground(color); } if (newFaces != null) { Color color = gc.getForeground(); gc.setForeground(e.display.getSystemColor(SWT.COLOR_GREEN)); for (Rectangle rectangle : newFaces) { int fWidth = (int) (rectangle.width * factor); int fHeight = (int) (rectangle.height * factor); int fx = (int) (rectangle.x * factor); int fy = (int) (rectangle.y * factor); gc.drawRectangle(fx + destX, fy + destY, fWidth, fHeight); } gc.setForeground(color); } StringBuilder sb = new StringBuilder(); String title = currentAsset.getTitle(); if (title == null || title.isEmpty()) title = currentAsset.getName(); sb.append(title).append('\n'); String headline = currentAsset.getHeadline(); if (headline != null && !headline.isEmpty()) sb.append(headline).append('\n'); String description = currentAsset.getImageDescription(); if (description != null && !description.isEmpty()) sb.append(description).append('\n'); String[] keyword = currentAsset.getKeyword(); if (keyword != null && keyword.length > 0) sb.append(Core.toStringList(keyword, ", ")).append('\n'); //$NON-NLS-1$ sb.append("\n\n").append(NLS.bind(Messages.CategorizeDialog_x_of_y, current + 1, size)); //$NON-NLS-1$ textLayout.setWidth(destWidth); textLayout.setText(sb.toString()); textLayout.draw(gc, destX, destY + destHeight + MARGINS, -1, -1, null, null); String safety = QueryField.SAFETY.value2text(QueryField.SAFETY.obtainFieldValue(currentAsset), ""); //$NON-NLS-1$ Point tx = gc.textExtent(safety); gc.drawText(safety, clientArea.width - tx.x - 5, clientArea.height - tx.y - 5, true); } }); imageCanvas.addKeyListener(this); CGroup subImageArea = UiUtilities.createGroup(imageArea, 2, Messages.CategorizeDialog_settings); if (aiService != null) faceButton = WidgetFactory.createCheckButton(subImageArea, Messages.CategorizeDialog_use_new_faces, new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); new Label(subImageArea, SWT.NONE).setText(Messages.CategorizeDialog_new_description); descriptionField = new CheckedText(subImageArea, SWT.WRAP); GridData ldata = new GridData(SWT.FILL, SWT.CENTER, true, false); ldata.heightHint = 30; descriptionField.setLayoutData(ldata); new Label(subImageArea, SWT.NONE).setText(Messages.CategorizeDialog_privacy); newPrivacyGroup = new RadioButtonGroup(subImageArea, null, SWT.HORIZONTAL, Messages.CategorizeDialog_public, Messages.CategorizeDialog_medium, Messages.CategorizeDialog_private); newPrivacyGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); } private void setProposalTitel() { if (aiService != null) proposalTitle.setText( aiService.isEnabled() ? aiService.getTitle(null) : Messages.CategorizeDialog_service_disabled); } private void fillValues(boolean clear) { currentAsset = assets.get(current); int safety = currentAsset.getSafety(); Prediction prediction = null; newFaces = null; String imageDescription = currentAsset.getImageDescription(); boolean markKnownOnly = true; float markAbove = 0.99f; descriptionField.setText(imageDescription == null ? "" : imageDescription); //$NON-NLS-1$ if (aiService != null && aiService.isEnabled()) { markKnownOnly = aiService.getMarkKnownOnly(null); markAbove = aiService.getMarkAbove(null); prediction = predictions.get(currentAsset.getStringId()); if (prediction == null) { msgLabel.setText(Messages.CategorizeDialog_query_pending); stackLayout.topControl = msgComp; newFaces = null; faceButton.setEnabled(false); faceButton.setSelection(false); } else { if (prediction.getConcepts() != null) { if (prediction.getKeywords() != null) { proposalViewer1.setInput(prediction.getConcepts()); proposalViewer2.setInput(prediction.getKeywords()); stackLayout.topControl = splitComp; } else { proposalViewer.setInput(prediction.getConcepts()); stackLayout.topControl = propComp; } } else { msgLabel.setText(prediction.getStatus().getMessage()); stackLayout.topControl = msgComp; } float safeForWork = Math.max(prediction.getAdultScore(), prediction.getRacyScore()); if (safeForWork >= 0) safety = safeForWork > 0.7 ? QueryField.SAFETY_SAFE : safeForWork > 0.3 ? QueryField.SAFETY_MODERATE : QueryField.SAFETY_RESTRICTED; if (prediction.getDescription() != null && descriptionField.getText().isEmpty()) descriptionField.setText(prediction.getDescription()); } } else if (aiService != null) { msgLabel.setText(Messages.CategorizeDialog_deactivated); stackLayout.topControl = msgComp; newFaces = null; faceButton.setEnabled(false); faceButton.setSelection(false); } if (stack != null) stack.layout(); if (clear) root.setChecked(UNCHECKED, true); String primary; String[] supplementalCats; CatResult currentResult = result[current]; if (currentResult != null) { primary = currentResult.getPrimary(); supplementalCats = currentResult.getSupplemental(); newPrivacyGroup.setSelection(currentResult.getPrivacy()); descriptionField.setText(currentResult.getDescription()); } else { primary = currentAsset.getCategory(); supplementalCats = currentAsset.getSupplementalCats(); setPrivacy(newPrivacyGroup, safety); } for (String sup : supplementalCats) if (sup != null && !sup.isEmpty()) { Node found = root.find(sup); if (found != null) found.setChecked(SUPPLEMENTAL, false); } forcePrimary = true; if (primary != null && !primary.isEmpty()) { forcePrimary = false; Node found = root.find(primary); if (found != null) found.setChecked(CHECKED, false); } if (currentResult != null) { String proposal = currentResult.getProposal(); String[] supProposals = currentResult.getSupProposals(); for (String sup : supProposals) if (sup != null && !sup.isEmpty()) { Node found = root.find(sup); if (found != null) found.setChecked(SUPPROPOSED, false); } Node found = root.find(proposal); if (found != null) found.setChecked(PROPOSED, false); if (prediction != null && proposalViewer != null) { Set<String> keywords = currentResult.getKeywords(); if (keywords != null) { Token[] tokens = prediction.getConcepts(); for (String kw : keywords) for (Token token : tokens) { if (kw.equals(token.getLabel())) { proposalViewer.setChecked(token, true); proposalViewer1.setChecked(token, true); proposalViewer2.setChecked(token, true); break; } } } } newFaces = currentResult.getNewFaces(); } else if (prediction != null && proposalViewer != null) { boolean hasPrimary = root.has(CHECKED | PROPOSED); Node primaryNode = null; Token[] tokens = prediction.getConcepts(); Set<String> keywords = meta.getKeywords(); for (Token token : tokens) { String label = token.getLabel(); Node found = root.find(label); if (found != null && found.getChecked() != CHECKED && found.getChecked() != SUPPLEMENTAL) { if (hasPrimary || primaryNode != null && primaryNode != found) { found.setChecked(SUPPROPOSED, false); token.setMatch(SUPPROPOSED); } else { found.setChecked(PROPOSED, false); token.setMatch(PROPOSED); primaryNode = found; } token.setCategory(found.getCat().getLabel()); proposalViewer.update(token, null); proposalViewer1.update(token, null); } if (!markKnownOnly || keywords.contains(label) || newKeywords.contains(label)) { if (token.score > markAbove) { proposalViewer.setChecked(token, true); proposalViewer1.setChecked(token, true); } } } newFaces = prediction.getFaces(); } drawImage(); drawCat(); updateButtons(); } protected void setPrivacy(RadioButtonGroup newPrivacyGroup2, int safety) { switch (safety) { case QueryField.SAFETY_RESTRICTED: newPrivacyGroup2.setSelection(2); break; case QueryField.SAFETY_MODERATE: newPrivacyGroup2.setSelection(1); break; default: newPrivacyGroup2.setSelection(0); break; } } private void drawCat() { catCanvas.redraw(); } private void drawImage() { imageCanvas.redraw(); } @Override protected void createButtonsForButtonBar(Composite parent) { if (size > 1) { createButton(parent, BACK_ID, Messages.CategorizeDialog_back, Messages.CategorizeDialog_previous_tooltip, false); createButton(parent, NEXT_ID, Messages.CategorizeDialog_next, Messages.CategorizeDialog_next_tooltip, false); createButton(parent, CLONE_ID, Messages.CategorizeDialog_clone, Messages.CategorizeDialog_clone_tooltip, true); } createButton(parent, DONE_ID, Messages.CategorizeDialog_done, Messages.CategorizeDialog_done_tooltip, true); createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, Messages.CategorizeDialog_cancel_tooltip, false); } private void createButton(Composite parent, int id, String label, String tooltip, boolean defaultButton) { createButton(parent, id, label, defaultButton).setToolTipText(tooltip); } @Override protected void buttonPressed(int buttonId) { switch (buttonId) { case BACK_ID: processSelection(); --current; cloned = false; fillValues(true); break; case NEXT_ID: processSelection(); ++current; fillValues(true); break; case CLONE_ID: if (size > 1 && current > 0 && !cloned) { result[current] = result[current - 1]; if (current < size - 1) ++current; else cloned = true; fillValues(true); } break; case DONE_ID: processSelection(); okPressed(); break; default: if (catBackup != null) meta.setCategory(catBackup); cancelPressed(); } } private void processSelection() { List<String> supplemental = new ArrayList<>(); String primary = root.getSelection(supplemental, CHECKED, SUPPLEMENTAL); List<String> supProposals = new ArrayList<>(); String proposal = root.getSelection(supProposals, PROPOSED, SUPPROPOSED); Set<String> proposedKeywords = null; if (aiService != null) { if (stackLayout.topControl == propComp) { Object[] checkedElements = proposalViewer.getCheckedElements(); if (checkedElements.length > 0) { proposedKeywords = new HashSet<>(checkedElements.length * 3 / 2); for (Object object : checkedElements) if (object instanceof Token) proposedKeywords.add(((Token) object).getLabel()); newKeywords.addAll(proposedKeywords); } } } result[current] = new CatResult(primary, supplemental.toArray(new String[supplemental.size()]), proposal, supProposals.toArray(new String[supProposals.size()]), proposedKeywords, newPrivacyGroup.getSelection(), descriptionField.getText(), (faceButton != null && faceButton.getSelection()) ? imageBounds : null, newFaces); } @Override public boolean close() { Job.getJobManager().cancel(this); if (aiService != null) { CoreActivator.getDefault().ungetAiService(aiService, null); aiService = null; } if (textLayout != null) { textLayout.dispose(); textLayout = null; } return super.close(); } private void updateButtons() { if (size > 1) { getButton(BACK_ID).setEnabled(current > 0); getButton(NEXT_ID).setEnabled(current < size - 1); } Button cloneButton = getButton(CLONE_ID); if (cloneButton != null) cloneButton.setEnabled(current > 0 && !cloned); if (aiService != null && aiService.isEnabled()) { acceptLink.setVisible(root.has(SUPPROPOSED | PROPOSED)); if (aiService.checkFaces(null)) { faceButton.setVisible(true); boolean enabled = newFaces != null && !newFaces.isEmpty(); faceButton.setEnabled(enabled); int noPersons = currentAsset.getNoPersons(); if (enabled && noPersons <= newFaces.size()) { boolean named = false; if (currentRegions != null) for (ImageRegion region : currentRegions) { String name = region.name; if (name != null && !name.isEmpty() && !"?".equals(name)) { //$NON-NLS-1$ named = true; break; } } faceButton.setSelection(!named); } else faceButton.setSelection(false); } else faceButton.setVisible(false); } else { acceptLink.setVisible(false); faceButton.setVisible(false); } } public CatResult[] getResult() { VocabManager vmanager = getVocabManager(); for (CatResult catres : result) { if (catres != null) { Set<String> keywords = catres.getKeywords(); if (keywords != null) { String[] kw = keywords.toArray(new String[keywords.size()]); for (String keyword : kw) { String vocab = vmanager.getVocab(keyword); if (vocab != null) { keywords.remove(keyword); keywords.add(vocab); } } } } } return result; } @Override public Control getControl() { return null; } @Override public String getTooltip(int mx, int my) { return null; } @Override public Node findObject(MouseEvent event) { return root.findNode(event.x, event.y); } @Override public ImageRegion[] findAllRegions(MouseEvent event) { return null; } @Override public IGalleryHover getGalleryHover(MouseEvent event) { return new CatDialogHover(); } @Override public Control[] getControls() { return msgLabel == null ? new Control[] { imageCanvas, catCanvas } : new Control[] { imageCanvas, catCanvas, msgLabel }; } @Override public void keyPressed(KeyEvent e) { switch (e.character) { case SWT.CR: buttonPressed(DONE_ID); break; case SWT.ESC: buttonPressed(IDialogConstants.CANCEL_ID); break; default: switch (e.keyCode & SWT.KEY_MASK) { case SWT.ARROW_LEFT: if (current > 1) buttonPressed(BACK_ID); break; case SWT.ARROW_RIGHT: if (current < size - 1) { if ((e.stateMask & SWT.CTRL) == SWT.CTRL) { if (current > 1) buttonPressed(CLONE_ID); } else buttonPressed(NEXT_ID); } break; } break; } } @Override public void keyReleased(KeyEvent e) { // do nothing } public Map<String, Category> getCategories() { return categories; } public Map<String, Category> getCatBackup() { return catBackup; } }