org.eclipselabs.e4.tapiji.translator.ui.treeviewer.TreeViewerView.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipselabs.e4.tapiji.translator.ui.treeviewer.TreeViewerView.java

Source

/*******************************************************************************
 * Copyright (c) 2012 Martin Reiterer.
 * All rights reserved. This program and the accompanying materials
 * are 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:
 * Martin Reiterer - initial API and implementation
 * Christian Behon - refactor from e3 to e4
 ******************************************************************************/
package org.eclipselabs.e4.tapiji.translator.ui.treeviewer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Stream;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.e4.core.commands.ECommandService;
import org.eclipse.e4.core.commands.EHandlerService;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Creatable;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.services.EMenuService;
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnViewerEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.TreeViewerEditor;
import org.eclipse.jface.viewers.TreeViewerFocusCellManager;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
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.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipselabs.e4.tapiji.logger.Log;
import org.eclipselabs.e4.tapiji.translator.model.Glossary;
import org.eclipselabs.e4.tapiji.translator.model.Term;
import org.eclipselabs.e4.tapiji.translator.model.Translation;
import org.eclipselabs.e4.tapiji.translator.preference.StoreInstanceState;
import org.eclipselabs.e4.tapiji.translator.ui.treeviewer.provider.TreeViewerContentProvider;
import org.eclipselabs.e4.tapiji.translator.ui.treeviewer.provider.TreeViewerLabelProvider;
import org.eclipselabs.e4.tapiji.translator.ui.widget.dnd.GlossaryDragSource;
import org.eclipselabs.e4.tapiji.translator.ui.widget.dnd.GlossaryDropTarget;
import org.eclipselabs.e4.tapiji.translator.ui.widget.dnd.TermTransfer;
import org.eclipselabs.e4.tapiji.translator.ui.widget.filter.ExactMatcher;
import org.eclipselabs.e4.tapiji.translator.ui.widget.filter.FuzzyMatcher;
import org.eclipselabs.e4.tapiji.translator.ui.widget.filter.SelectiveMatcher;
import org.eclipselabs.e4.tapiji.translator.ui.widget.sorter.SortInfo;
import org.eclipselabs.e4.tapiji.translator.ui.widget.sorter.TreeViewerSortOrder;
import org.eclipselabs.e4.tapiji.utils.LocaleUtils;

@Creatable
@Singleton
public final class TreeViewerView extends Composite implements IResourceChangeListener, TreeViewerContract.View {

    private static final String TAG = TreeViewerView.class.getSimpleName();
    private static final String TREE_VIEWER_MENU_ID = "org.eclipselabs.e4.tapiji.translator.popupmenu.treeview";
    private static final String TREE_VIEWER_MENU_EMPTY_ID = "org.eclipselabs.e4.tapiji.translator.popupmenu.treeview.empty";

    private static final float DEFAULT_MATCHING_PRECISION = .75f;
    protected static final String COMMAND_DELETE_KEY = "org.eclipselabs.e4.tapiji.translator.command.removeTerm";

    @Inject
    private StoreInstanceState storeInstanceState;

    @Inject
    private ESelectionService selectionService;

    @Inject
    private TreeViewerPresenter presenter;

    @Inject
    private EMenuService menuService;

    @Inject
    private ECommandService commandService;

    @Inject
    private EHandlerService handlerService;

    private boolean isColumnEditable;
    private boolean isFuzzyMatchingEnabled = false;
    private final boolean selectiveViewEnabled = false;

    private TreeViewer treeViewer;

    private SortInfo sortInfo;
    private String referenceLanguage;
    private TreeViewerLabelProvider treeViewerLabelProvider;
    private String[] translations;

    private TreeViewerSortOrder columnSorter;
    private ExactMatcher matcher;

    private final List<String> displayedTranslations = new ArrayList<String>();

    private Tree tree;

    public TreeViewerView(Composite parent) {
        super(parent, SWT.FILL);
        final GridLayout gridLayout = new GridLayout(1, false);
        gridLayout.marginHeight = 0;
        gridLayout.marginWidth = 0;
        setLayout(gridLayout);
        setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
    }

    @PostConstruct
    private void onCreate() {
        this.presenter.setView(this);
        this.translations = presenter.getGlossary().getTranslations();
        this.treeViewer = new TreeViewer(this, SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE);
        this.treeViewer.getTree().setHeaderVisible(false);
        this.treeViewer.getTree().setLinesVisible(false);
        this.treeViewer.setAutoExpandLevel(2);

        this.treeViewer.addSelectionChangedListener((event) -> {
            selectionService.setSelection(((IStructuredSelection) treeViewer.getSelection()).getFirstElement());
        });

        this.treeViewer.getTree().addMouseListener(new MouseAdapter() {

            @Override
            public void mouseDoubleClick(MouseEvent event) {
                final Object element = selectionService.getSelection();
                if (treeViewer.isExpandable(element)) {
                    if (treeViewer.getExpandedState(element)) {
                        treeViewer.collapseToLevel(element, 1);
                    } else {
                        treeViewer.expandToLevel(element, 1);
                    }
                }
            }
        });

        this.treeViewer.getTree().addKeyListener(new KeyAdapter() {

            @SuppressWarnings("restriction")
            @Override
            public void keyReleased(KeyEvent event) {
                if (event.character == SWT.DEL) {
                    handlerService.executeHandler(
                            commandService.createCommand(COMMAND_DELETE_KEY, Collections.emptyMap()));
                }

            }
        });
        this.tree = treeViewer.getTree();
        this.tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

        TreeViewerEditor.create(treeViewer,
                new TreeViewerFocusCellManager(treeViewer, new FocusCellOwnerDrawHighlighter(treeViewer)),
                createColumnActivationStrategy(),
                ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
                        | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION
                        | ColumnViewerEditor.KEEP_EDITOR_ON_DOUBLE_CLICK);
        dragAndDrop();
        registerTreeMenu(TREE_VIEWER_MENU_EMPTY_ID);
    }

    private void initializeWidget() {
        if (translations.length > 0) {
            createLocaleColumns();
            treeViewerLabelProvider = TreeViewerLabelProvider.newInstance(treeViewer, displayedTranslations,
                    displayedTranslations.indexOf(referenceLanguage));
            treeViewerLabelProvider.isSearchEnabled(isFuzzyMatchingEnabled);
            treeViewer.setLabelProvider(treeViewerLabelProvider);
            treeViewer.setContentProvider(TreeViewerContentProvider.newInstance());
            tree.setHeaderVisible(true);
            tree.setLinesVisible(true);
        } else {
            tree.setHeaderVisible(false);
            tree.setLinesVisible(false);
        }
    }

    private void createLocaleColumns() {
        displayedTranslations.clear();
        final TextCellEditor textCellEditor = new TextCellEditor(tree);
        int columnIndex = 0;
        createColumn(referenceLanguage, columnIndex, textCellEditor);
        Log.d(TAG, "" + columnIndex + " " + referenceLanguage);
        columnIndex++;
        displayedTranslations.add(referenceLanguage);
        Log.d(TAG, "" + columnIndex);
        for (final String languageCode : translations) {
            if (languageCode.equalsIgnoreCase(referenceLanguage)) {
                continue;
            }
            displayedTranslations.add(languageCode);
            createColumn(languageCode, columnIndex, textCellEditor);
            columnIndex++;
            Log.d(TAG, "" + columnIndex + " " + languageCode);
        }
    }

    private void createColumn(final String languageCode, final int columnIndex,
            final TextCellEditor textCellEditor) {
        final Locale locale = LocaleUtils.getLocaleFromLanguageCode(languageCode);
        final TreeViewerColumn column = new TreeViewerColumn(treeViewer, SWT.NONE);
        column.getColumn().setWidth(200);
        column.getColumn().setMoveable(false);
        column.getColumn().setResizable(true);
        column.getColumn().setText(locale.getDisplayName());
        column.getColumn().addSelectionListener(createColumnSelectionListener(columnIndex));
        column.setEditingSupport(createEditingSupportFor(textCellEditor, columnIndex, languageCode));

    }

    private void showHideColumn(final String languageCode) {
        final String language = LocaleUtils.getLocaleFromLanguageCode(languageCode).getDisplayName();
        Stream.of(tree.getColumns()).filter(column -> language.equals(column.getText())).forEach(column -> {
            if (column.getWidth() == 0) {
                column.setWidth(200);
                column.setResizable(true);
            } else {
                column.setWidth(0);
                column.setResizable(false);
            }
        });
    }

    @Override
    public void registerTreeMenu(String menuId) {
        this.menuService.registerContextMenu(this.treeViewer.getControl(), menuId);
    }

    private void setTreeStructure(final boolean grouped) {
        ((TreeViewerContentProvider) treeViewer.getContentProvider()).setGrouped(grouped);
        if (treeViewer.getInput() == null) {
            treeViewer.setUseHashlookup(false);
        }
    }

    private void clearTreeViewer() {
        treeViewer.getTree().clearAll(true);
        for (final TreeColumn column : tree.getColumns()) {
            column.dispose();
        }
    }

    private void initMatchers() {
        treeViewer.resetFilters();
        if (isFuzzyMatchingEnabled) {
            matcher = new FuzzyMatcher(treeViewer);
            ((FuzzyMatcher) matcher).setMinimumSimilarity(DEFAULT_MATCHING_PRECISION);
        } else {
            matcher = new ExactMatcher(treeViewer);
        }

        matcher.setPattern((matcher != null) ? matcher.getPattern() : "");

        if (this.selectiveViewEnabled) {
            new SelectiveMatcher(treeViewer);
        }
    }

    private void dragAndDrop() {
        final Transfer[] transferTypes = new Transfer[] { TermTransfer.getInstance() };
        treeViewer.addDragSupport(DND.DROP_MOVE, transferTypes,
                GlossaryDragSource.create(treeViewer, presenter.getGlossary()));
        treeViewer.addDropSupport(DND.DROP_MOVE, transferTypes, GlossaryDropTarget.create(treeViewer));
    }

    private void referenceLanguage() {
        if (!storeInstanceState.getReferenceLanguage().isEmpty()) {
            this.referenceLanguage = storeInstanceState.getReferenceLanguage();
            Log.d(TAG, "REFERENCE LANGUAGE FROM STORAGE" + referenceLanguage);
        } else {
            this.referenceLanguage = translations[0];
            storeInstanceState.setReferenceLanguage(referenceLanguage);
            Log.d(TAG, "REFERENCE USE DEFAULT" + referenceLanguage);
        }
    }

    private void columnSorter(final Glossary glossary) {
        columnSorter = new TreeViewerSortOrder(treeViewer, sortInfo, glossary.getIndexOfLocale(referenceLanguage),
                glossary.info.translations);
        treeViewer.setComparator(columnSorter);
    }

    private EditingSupport createEditingSupportFor(final TextCellEditor textCellEditor, final int columnCnt,
            final String languageCode) {
        return new EditingSupport(treeViewer) {

            @Override
            protected boolean canEdit(final Object element) {
                return isColumnEditable;
            }

            @Override
            protected CellEditor getCellEditor(final Object element) {
                return textCellEditor;
            }

            @Override
            protected Object getValue(final Object element) {
                return treeViewerLabelProvider.getColumnText(element, columnCnt);
            }

            @Override
            protected void setValue(final Object element, final Object value) {

                if (element instanceof Term) {
                    treeViewer.setSelection(new StructuredSelection(element), true);

                    final Translation translation = ((Term) element).getTranslation(languageCode);
                    if (translation != null) {
                        Log.d(TAG, "EDIT COLUMN:" + value);
                        translation.value = (String) value;
                        getViewer().update(element, null);
                        saveGlossaryAsync();
                    }
                }
            }

            private void saveGlossaryAsync() {
                presenter.updateGlossary(
                        ((TreeViewerContentProvider) treeViewer.getContentProvider()).getGlossary());
            }
        };
    }

    private boolean isSearchTreeGrouped() {
        return (matcher.getPattern().trim().length() < 0) && (columnSorter.getSortInfo().getColumnIndex() == 0);
    }

    @Override
    public void enableFuzzyMatching(final boolean enable) {
        Log.d(TAG, String.format("Enable fuzzy logic: %s", enable));
        isFuzzyMatchingEnabled = enable;
        String pattern = "";
        if (matcher != null) {
            pattern = matcher.getPattern();
            if (!isFuzzyMatchingEnabled && enable) {
                if ((matcher.getPattern().trim().length() > 1) && matcher.getPattern().startsWith("*")
                        && matcher.getPattern().endsWith("*")) {
                    pattern = pattern.substring(1).substring(0, pattern.length() - 2);
                }
                matcher.setPattern(null);
            }
        }
        initMatchers();
        if (treeViewerLabelProvider != null) {
            treeViewerLabelProvider.isSearchEnabled(enable);
        }
        matcher.setPattern(pattern);
        treeViewer.refresh();
    }

    @Override
    public void setSearchString(final String searchString) {
        if (null != matcher) {
            if (searchString.isEmpty()) {
                matcher.setPattern(null);
                setTreeStructure(true);
                treeViewerLabelProvider.isSearchEnabled(false);
            } else {
                matcher.setPattern(searchString);
                setTreeStructure(isSearchTreeGrouped());
                treeViewerLabelProvider.isSearchEnabled(true);
            }
            tree.setRedraw(true);
            treeViewer.refresh();
        }
    }

    @Override
    public void setMatchingPrecision(final float value) {
        if (matcher instanceof FuzzyMatcher) {
            ((FuzzyMatcher) matcher).setMinimumSimilarity(value);
            treeViewer.refresh();
        }
    }

    @Override
    public void setReferenceLanguage(final String referenceLanguage) {
        this.referenceLanguage = referenceLanguage;
    }

    @Override
    public void resourceChanged(final IResourceChangeEvent event) {
    }

    @Override
    public TreeViewer getTreeViewer() {
        return treeViewer;
    }

    @Override
    public void showHideTranslationColumn(final String languageCode) {
        showHideColumn(languageCode);
    }

    @Override
    public void setColumnEditable(final boolean isEditable) {
        this.isColumnEditable = isEditable;
    }

    @Override
    public void updateView(final Glossary glossary) {
        if (glossary != null) {
            tree.setRedraw(false);
            clearTreeViewer();
            translations = glossary.info.getTranslations();
            referenceLanguage();
            initializeWidget();
            columnSorter(glossary);
            initMatchers();
            treeViewer.setInput(glossary);
            registerTreeMenu(TREE_VIEWER_MENU_ID);
            tree.setRedraw(true);
            treeViewer.refresh();
        }
    }

    @Focus
    public void focus() {
        treeViewer.getControl().setFocus();
    }

    public static TreeViewerContract.View create(final Composite parent, IEclipseContext eclipseContext) {
        final TreeViewerView view = new TreeViewerView(parent);
        org.eclipse.e4.core.contexts.ContextInjectionFactory.inject(view, eclipseContext);

        return view;
    }

    private ColumnViewerEditorActivationStrategy createColumnActivationStrategy() {
        return new ColumnViewerEditorActivationStrategy(treeViewer) {

            @Override
            protected boolean isEditorActivationEvent(final ColumnViewerEditorActivationEvent event) {
                ViewerCell cell = (ViewerCell) event.getSource();
                boolean isEditorActivationEvent;
                if (cell.getColumnIndex() == 1) {
                    isEditorActivationEvent = event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
                            || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_CLICK_SELECTION
                            || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED
                                    && event.keyCode == ' ')
                            || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
                } else {
                    isEditorActivationEvent = event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
                            || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_CLICK_SELECTION
                            || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED
                                    && event.keyCode == ' ')
                            || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
                }
                return isEditorActivationEvent;
            }
        };
    }

    private SelectionListener createColumnSelectionListener(final int columnIndex) {
        return new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent selectionEvent) {
                updateColumnOrder(columnIndex);
            }

            private void updateColumnOrder(final int columnIndex) {
                if (columnSorter != null) {
                    final SortInfo sortInfo = columnSorter.getSortInfo();
                    if (columnIndex == sortInfo.getColumnIndex()) {
                        sortInfo.setDescending(!sortInfo.isDescending());
                    } else {
                        sortInfo.setColumnIndex(columnIndex);
                        sortInfo.setDescending(false);
                    }
                    columnSorter.setSortInfo(sortInfo);
                    setTreeStructure(columnIndex == 0);
                    treeViewer.refresh();
                }
            }

        };
    }

    @Override
    public void addSelection(Term term) {
        Log.d(TAG, "SELECTION" + term);
        treeViewer.setSelection(new StructuredSelection(term), true);
    }
}