edu.uchicago.cs.hao.texdojo.bibeditor.editors.EditorUI.java Source code

Java tutorial

Introduction

Here is the source code for edu.uchicago.cs.hao.texdojo.bibeditor.editors.EditorUI.java

Source

/*******************************************************************************
 * Copyright (c) Oct 2016 Hao Jiang.
 * 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:
 *    Hao Jiang - initial API and implementation and/or initial documentation
 *******************************************************************************/

package edu.uchicago.cs.hao.texdojo.bibeditor.editors;

import java.beans.IndexedPropertyChangeEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.function.Consumer;

import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.MessageConsole;

import edu.uchicago.cs.hao.texdojo.bibeditor.filemodel.BibEntry;
import edu.uchicago.cs.hao.texdojo.bibeditor.filemodel.BibModel;
import edu.uchicago.cs.hao.texdojo.bibeditor.filemodel.BibParser;
import edu.uchicago.cs.hao.texdojo.bibeditor.filemodel.BibParser.Token;
import edu.uchicago.cs.hao.texdojo.bibeditor.filemodel.BibParser.TokenType;
import edu.uchicago.cs.hao.texdojo.bibeditor.filemodel.BibProp;
import edu.uchicago.cs.hao.texdojo.bibeditor.filemodel.EntryType;

public class EditorUI implements PropertyChangeListener {

    private BibModel model;

    public BibEntry selected() {
        StructuredSelection sel = (StructuredSelection) table.getSelection();
        if (sel.isEmpty())
            return null;
        return (BibEntry) sel.getFirstElement();
    }

    public BibEntry[] allSelected() {
        StructuredSelection sel = (StructuredSelection) table.getSelection();
        if (sel == null || sel.isEmpty())
            return null;
        Object[] sels = sel.toArray();
        BibEntry[] allsels = new BibEntry[sels.length];
        for (int i = 0; i < sels.length; i++) {
            allsels[i] = (BibEntry) sels[i];
        }
        return allsels;
    }

    private boolean dirty;

    private PropertyChangeSupport support;

    // Listeners

    private ModifyListener textModifyListener = new ModifyListener() {
        @Override
        public void modifyText(ModifyEvent e) {
            if (selected() != null) {
                // Try parse the content, block the change if syntex incorrect
                String text = editText.getText();
                try {
                    BibModel tempmodel = new BibParser().parse(text);
                    if (1 != tempmodel.getEntries().size())
                        throw new IllegalArgumentException();
                    else {
                        // Update table info
                        BibEntry newEntry = tempmodel.getEntries().get(0);
                        // Reset selection
                        EditorUI.this.model.replaceEntry(selected(), newEntry);
                        table.setSelection(new StructuredSelection(newEntry));
                    }
                    // Add color to the text
                    updateTextContent(editText.getText());
                    EditorUI.this.setDirty(true);
                    editText.setBackground(null);
                } catch (Exception ex) {
                    editText.setBackground(Resources.color(Resources.COLOR_WARNBACK));
                }

            }
        }
    };

    // Components
    private TableViewer table;

    private ColumnViewerComparator tableComparator;

    private StyledText editText;

    private MenuManager menuManager;

    public MenuManager getMenuManager() {
        return menuManager;
    }

    public TableViewer getTable() {
        return table;
    }

    public StyledText getText() {
        return editText;
    }

    public EditorUI() {
        super();
        support = new PropertyChangeSupport(this);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        support.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        support.removePropertyChangeListener(listener);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getSource() instanceof BibModel) {

            if ("addEntry".equals(evt.getPropertyName())) {
                // Disable comparator
                table.setComparator(null);
                table.insert(evt.getNewValue(), model.getEntries().size() - 1);
                table.setSelection(new StructuredSelection(evt.getNewValue()));
                updateTextContent(evt.getNewValue().toString());
            }
            if ("removeEntry".equals(evt.getPropertyName())) {
                table.remove(evt.getOldValue());
                if (model.getEntries().size() > 0) {
                    BibEntry first = model.getEntries().get(0);
                    table.setSelection(new StructuredSelection(first));
                    updateTextContent(first.toString());
                } else {
                    updateTextContent("");
                }
            }
            if ("entries".equals(evt.getPropertyName())) {
                IndexedPropertyChangeEvent ipc = (IndexedPropertyChangeEvent) evt;
                if (ipc.getIndex() == -1) {
                    // Replace all
                    table.setInput(model.getEntries());
                } else {
                    table.replace(ipc.getNewValue(), ipc.getIndex());
                }
            }
            setDirty(true);
        }
    }

    public void createUI(Composite parent) {
        prepareColors();
        // plusIcon = new Image(Display.getCurrent(), "icons/toolbar_plus.gif");
        // minusIcon = new Image(Display.getCurrent(),
        // "icons/toolbar_minus.gif");

        SashForm form = new SashForm(parent, SWT.VERTICAL);
        form.setLayout(new FillLayout());

        createTable(form);

        createEditPanel(form);

        form.setWeights(new int[] { 70, 30 });

        createMenu();
    }

    public void dispose() {
        table = null;
        editText = null;
    }

    public boolean isDirty() {
        return dirty;
    }

    public void setDirty(boolean dirty) {
        boolean oldDirty = this.dirty;
        this.dirty = dirty;
        support.firePropertyChange("dirty", oldDirty, dirty);
    }

    public void save(File target, boolean preserveCase) {
        try {
            PrintWriter output = new PrintWriter(new FileOutputStream(target));

            for (BibEntry entry : model.getEntries()) {
                entry.setPreserveCase(preserveCase);
                output.println(entry.toString());
            }
            output.close();
            setDirty(false);

            table.refresh(true);

            BibEntry selected = selected();
            if (selected != null)
                updateTextContent(selected.toString());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void updateTextContent(String content) {
        editText.removeModifyListener(textModifyListener);

        try {
            if (!content.equals(editText.getText()))
                editText.setText(content);
            InputStream in = new ByteArrayInputStream(content.getBytes("UTF-8"));
            Iterable<Token> tokens = new BibParser().tokenize(in);
            tokens.forEach(new Consumer<Token>() {
                @Override
                public void accept(Token t) {
                    switch (t.getType()) {
                    case TokenType.TYPE:
                        editText.setStyleRange(new StyleRange(t.getFrom(), t.getLength(),
                                Resources.color(Resources.COLOR_BROWN), null, SWT.BOLD));
                        break;
                    case TokenType.KEY:
                        editText.setStyleRange(new StyleRange(t.getFrom(), t.getLength(),
                                Resources.color(Resources.COLOR_MAGENTA), null, SWT.BOLD));
                        break;
                    case TokenType.PROP_KEY:
                        editText.setStyleRange(new StyleRange(t.getFrom(), t.getLength(),
                                Resources.color(Resources.COLOR_DARKBLUE), null, SWT.BOLD));
                        break;
                    case TokenType.PROP_VAL:
                        editText.setStyleRange(new StyleRange(t.getFrom(), t.getLength(),
                                Resources.color(Resources.COLOR_GRASS), null, SWT.NORMAL));
                        break;
                    default:
                        break;
                    }
                }
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            editText.addModifyListener(textModifyListener);
        }

    }

    public BibModel getModel() {
        return model;
    }

    public void setModel(BibModel model) {
        if (this.model != null)
            this.model.removePropertyChangeListener(this);
        this.model = model;
        if (this.model != null)
            this.model.addPropertyChangeListener(this);
    }

    public static class BibEntryColumnLabelProvider extends ColumnLabelProvider {

        private int index;

        public BibEntryColumnLabelProvider(int index) {
            super();
            this.index = index;
        }

        @Override
        public String getText(Object element) {
            if (element instanceof BibEntry) {
                return extract(element, index);
            }
            return super.getText(element);
        }

        static String extract(Object element, int index) {
            BibEntry entry = (BibEntry) element;
            switch (index) {
            case 0:
                return entry.getId();
            case 1:
                return entry.getType();
            case 2:
                return entry.getProperty(BibProp.TITLE);
            case 3:
                return entry.getProperty(BibProp.YEAR);
            case 4:
                return entry.getProperty(BibProp.AUTHOR);
            default:
                return "";
            }
        }

        @Override
        public Color getBackground(Object element) {
            if (element instanceof BibEntry && ((BibEntry) element).isHighlight())
                return Resources.color(Resources.COLOR_HIGHLIGHT);
            return super.getBackground(element);
        }
    }

    public static class ColumnViewerComparator extends ViewerComparator {
        private int propertyIndex;
        private static final int DESCENDING = 1;
        private int direction = DESCENDING;

        public ColumnViewerComparator() {
            this.propertyIndex = 0;
            direction = DESCENDING;
        }

        public int getDirection() {
            return direction == 1 ? SWT.DOWN : SWT.UP;
        }

        public void setColumn(int column) {
            if (column == this.propertyIndex) {
                // Same column as last sort; toggle the direction
                direction = 1 - direction;
            } else {
                // New column; do an ascending sort
                this.propertyIndex = column;
                direction = DESCENDING;
            }
        }

        @Override
        public int compare(Viewer viewer, Object e1, Object e2) {
            String data1 = BibEntryColumnLabelProvider.extract(e1, propertyIndex);
            String data2 = BibEntryColumnLabelProvider.extract(e2, propertyIndex);
            if (null == data1)
                data1 = "";
            if (null == data2)
                data2 = "";
            int rc = data1.compareTo(data2);
            // If descending order, flip the direction
            if (direction == DESCENDING) {
                rc = -rc;
            }
            return rc;
        }
    }

    public class ColumnSelectionListener implements SelectionListener {

        int index = -1;

        public ColumnSelectionListener(int index) {
            super();
            this.index = index;
        }

        @Override
        public void widgetSelected(SelectionEvent e) {
            tableComparator.setColumn(this.index);
            table.setComparator(tableComparator);
            table.refresh();
        }

        @Override
        public void widgetDefaultSelected(SelectionEvent e) {

        }
    }

    /*
     * ======================================================================= UI
     * Section
     * =======================================================================
     */
    private void createTable(Composite form) {
        Composite tablePanel = new Composite(form, SWT.NONE);
        TableColumnLayout tableColumnLayout = new TableColumnLayout();
        tablePanel.setLayout(tableColumnLayout);

        table = new TableViewer(tablePanel, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
        table.setContentProvider(new ArrayContentProvider());

        TableColumn keyColumn = new TableColumn(table.getTable(), SWT.NONE);
        keyColumn.setText("cite_key");
        TableViewerColumn keyColumnViewer = new TableViewerColumn(table, keyColumn);
        keyColumnViewer.setLabelProvider(new BibEntryColumnLabelProvider(0));
        keyColumn.addSelectionListener(new ColumnSelectionListener(0));

        TableColumn typeColumn = new TableColumn(table.getTable(), SWT.NONE);
        typeColumn.setText("Type");
        TableViewerColumn typeColumnViewer = new TableViewerColumn(table, typeColumn);
        typeColumnViewer.setLabelProvider(new BibEntryColumnLabelProvider(1));
        typeColumn.addSelectionListener(new ColumnSelectionListener(1));

        TableColumn titleColumn = new TableColumn(table.getTable(), SWT.NONE);
        titleColumn.setText("Title");
        TableViewerColumn titleColumnViewer = new TableViewerColumn(table, titleColumn);
        titleColumnViewer.setLabelProvider(new BibEntryColumnLabelProvider(2));
        titleColumn.addSelectionListener(new ColumnSelectionListener(2));

        TableColumn yearColumn = new TableColumn(table.getTable(), SWT.NONE);
        yearColumn.setText("Year");
        TableViewerColumn yearColumnViewer = new TableViewerColumn(table, yearColumn);
        yearColumnViewer.setLabelProvider(new BibEntryColumnLabelProvider(3));
        yearColumn.addSelectionListener(new ColumnSelectionListener(3));

        TableColumn authorColumn = new TableColumn(table.getTable(), SWT.NONE);
        authorColumn.setText("Author");
        TableViewerColumn authorColumnViewer = new TableViewerColumn(table, authorColumn);
        authorColumnViewer.setLabelProvider(new BibEntryColumnLabelProvider(4));

        tableColumnLayout.setColumnData(keyColumn, new ColumnWeightData(5, 150, true));
        tableColumnLayout.setColumnData(typeColumn, new ColumnWeightData(5, 150, true));
        tableColumnLayout.setColumnData(titleColumn, new ColumnWeightData(50, 400, true));
        tableColumnLayout.setColumnData(yearColumn, new ColumnPixelData(50));
        tableColumnLayout.setColumnData(authorColumn, new ColumnWeightData(40, 400, true));

        table.setInput(model.getEntries());
        table.getTable().setLinesVisible(true);
        table.getTable().setHeaderVisible(true);

        table.getTable().addSelectionListener(new SelectionListener() {
            @Override
            public void widgetSelected(SelectionEvent event) {
                Object selection = ((StructuredSelection) table.getSelection()).getFirstElement();
                if (null != selection) {
                    updateTextContent(selection.toString());
                }
            }

            @Override
            public void widgetDefaultSelected(SelectionEvent event) {
                widgetSelected(event);
            }
        });
        // Supporting Table Sorting, only when clicking
        tableComparator = new ColumnViewerComparator();
        table.setComparator(null);
    }

    private void createEditPanel(Composite parent) {
        Composite editPanel = new Composite(parent, SWT.NONE);
        editPanel.setLayout(new FillLayout());
        editText = new StyledText(editPanel, SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
        editText.setFont(JFaceResources.getTextFont());
        editText.addModifyListener(textModifyListener);
        JFaceResources.getFontRegistry().addListener(new IPropertyChangeListener() {
            @Override
            public void propertyChange(org.eclipse.jface.util.PropertyChangeEvent event) {
                if (JFaceResources.getFontRegistry().equals(event.getSource())
                        && JFaceResources.TEXT_FONT.equals(event.getProperty())) {
                    editText.setFont(JFaceResources.getTextFont());
                }
                return;
            }
        });
    }

    public MessageConsole getConsole() {
        ConsolePlugin plugin = ConsolePlugin.getDefault();
        IConsoleManager conMan = plugin.getConsoleManager();
        IConsole[] existing = conMan.getConsoles();
        for (int i = 0; i < existing.length; i++)
            if (Constants.CONSOLE_NAME.equals(existing[i].getName()))
                return (MessageConsole) existing[i];
        // no console found, so create a new one
        MessageConsole myConsole = new MessageConsole(Constants.CONSOLE_NAME, null);
        conMan.addConsoles(new IConsole[] { myConsole });
        return myConsole;
    }

    private void createMenu() {
        menuManager = new MenuManager();
        Menu menu = menuManager.createContextMenu(table.getTable());
        // set the menu on the SWT widget
        table.getTable().setMenu(menu);
    }

    private void prepareColors() {
        ColorRegistry reg = JFaceResources.getColorRegistry();
        if (null == reg.get(Resources.COLOR_BROWN))
            reg.put(Resources.COLOR_BROWN, new RGB(66, 6, 14));
        if (null == reg.get(Resources.COLOR_DARKBLUE))
            reg.put(Resources.COLOR_DARKBLUE, new RGB(6, 45, 107));
        if (null == reg.get(Resources.COLOR_MAGENTA))
            reg.put(Resources.COLOR_MAGENTA, new RGB(147, 2, 22));
        if (null == reg.get(Resources.COLOR_GRASS))
            reg.put(Resources.COLOR_GRASS, new RGB(92, 114, 39));
        if (null == reg.get(Resources.COLOR_WARNBACK))
            reg.put(Resources.COLOR_WARNBACK, new RGB(255, 188, 196));
        if (null == reg.get(Resources.COLOR_HIGHLIGHT))
            reg.put(Resources.COLOR_HIGHLIGHT, new RGB(255, 250, 196));
    }

    /**
     * Search for the given text in title, author and keyword
     * 
     * @param text
     *            Keyword to search
     */
    public void search(String text) {
        if (text == null || text.isEmpty()) {
            // Clear all searches
            for (BibEntry entry : model.getEntries()) {
                entry.setHighlight(false);
                table.refresh(entry);
            }
        } else {
            String keyword = text.toLowerCase();
            for (BibEntry entry : model.getEntries()) {
                boolean highlight = entry.getProperty(EntryType.title).toLowerCase().contains(keyword)
                        || entry.getProperty(EntryType.author).toLowerCase().contains(keyword)
                        || entry.getProperty(EntryType.keywords).toLowerCase().contains(keyword);
                entry.setHighlight(highlight);
                table.refresh(entry);
            }
        }
    }
}