/************************************************************************************************** * Copyright (c) 2010 Fabian Steeg. 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 * <p/> * Contributors: Fabian Steeg - initial API and implementation *************************************************************************************************/ package de.uni_koeln.ub.drc.ui.views; import java.util.ArrayList; import java.util.List; import javax.swing.UIManager; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import scala.collection.JavaConversions; import de.uni_koeln.ub.drc.data.Page; import de.uni_koeln.ub.drc.data.User; import de.uni_koeln.ub.drc.data.Word; import de.uni_koeln.ub.drc.ui.DrcUiActivator; import de.uni_koeln.ub.drc.ui.Messages; import de.uni_koeln.ub.drc.ui.facades.CSSSWTConstantsHelper; import de.uni_koeln.ub.drc.ui.facades.TextHelper; /** * Composite holding the edit area. Used by the {@link EditView}. * * @author Fabian Steeg (fsteeg), Mihail Atanassov (matana) */ public class EditComposite extends Composite { private Composite parent; private Page page; private boolean commitChanges = false; private List<Text> words; private List<Composite> lines = new ArrayList<Composite>(); private Label status; private EditView editView; /** * @param editView * The parent edit view for this composite * @param style * The style bits for this composite */ public EditComposite(final EditView editView, final int style) { super(editView.sc, style); this.editView = editView; this.parent = editView.sc; this.status = editView.label; parent.getShell().setBackgroundMode(SWT.INHERIT_DEFAULT); GridLayout layout = new GridLayout(1, false); this.setLayout(layout); commitChanges = true; addWrapOnResizeListener(parent); setCssName(this); } /** * @return The text widgets representing the words in the current page */ public List<Text> getWords() { return words; } /** * @param page * Update the content of this composite with the given page */ public void update(final Page page) { this.page = page; updatePage(parent); } Page getPage() { return page; } private void addWrapOnResizeListener(final Composite parent) { parent.addControlListener(new ControlListener() { @Override public void controlResized(final ControlEvent e) { for (Composite line : lines) { if (!line.isDisposed()) { setLineLayout(line); } } } @Override public void controlMoved(final ControlEvent e) { } }); } private void updatePage(final Composite parent) { words = addTextFrom(page, this); } private List<Text> addTextFrom(final Page page, final Composite c) { if (lines != null) { for (Composite line : lines) { line.dispose(); } } List<Text> list = new ArrayList<Text>(); this.page = page; Composite lineComposite = new Composite(c, SWT.NONE); setLineLayout(lineComposite); if (lines != null) lines.add(lineComposite); for (Word word : JavaConversions.asJavaIterable(page.words())) { if (word.original().equals(Page.ParagraphMarker())) { lineComposite = new Composite(c, SWT.NONE); setLineLayout(lineComposite); lines.add(lineComposite); } else { Text text = new Text(lineComposite, SWT.NONE); setCssName(text); text.setText(TextHelper.fixForDisplay(word.history().top() .form())); handleEmptyText(text); // option: word.isPossibleError() ? UNCHECKED : DEFAULT text.setForeground(parent.getDisplay().getSystemColor(DEFAULT)); text.setData(Word.class.toString(), word); text.setData(Page.class.toString(), page); addListeners(text); text.setEditable(!word.isLocked() && !page.done()); list.add(text); } } this.layout(); return list; } private void setCssName(final Control control) { control.setData(CSSSWTConstantsHelper.getCSS(), "editComposite"); //$NON-NLS-1$ } private void setLineLayout(final Composite lineComposite) { setCssName(lineComposite); RowLayout layout = new RowLayout(); GridData data = new GridData(); int scrollBarSize = ((Integer) UIManager.get("ScrollBar.width")); //$NON-NLS-1$ data.widthHint = lineComposite.computeSize(getSize().x, getSize().y).x - scrollBarSize; lineComposite.setLayoutData(data); lineComposite.setLayout(layout); } private void addListeners(final Text text) { addFocusListener(text); addModifyListener(text); } private Text prev; final static int ACTIVE = SWT.COLOR_DARK_GREEN; final static int DUBIOUS = SWT.COLOR_RED; final static int DEFAULT = SWT.COLOR_BLACK; final static int UNCHECKED = SWT.COLOR_BLACK; // no coloring for now /** * @return The previous text widget */ public Text getPrev() { return prev; } private void addModifyListener(final Text text) { text.addModifyListener(new ModifyListener() { @Override public void modifyText(final ModifyEvent e) { User user = DrcUiActivator.getDefault().currentUser(); user.latestPage_$eq(page.id()); user.latestWord_$eq(words.indexOf(text)); /* * Reset any warning color during editing (we check when focus * is lost, see below): */ text.setForeground(text.getDisplay().getSystemColor(ACTIVE)); if (commitChanges) { editView.setDirty(true); } handleEmptyText(text); text.pack(true); text.getParent().layout(); /* * Workaround: on Windows, when adding text at the end of the * widget, text at the beginning is pushed out of the widget and * not visible - so we jump to beginning and then back: */ int pos = text.getCaretPosition(); text.setSelection(0); text.setSelection(pos); } }); } private void handleEmptyText(final Text text) { if (text.getText().length() == 0) { text.setText("\u2026"); // ellipsis //$NON-NLS-1$ } } private void addFocusListener(final Text text) { text.addFocusListener(new FocusListener() { @Override public void focusLost(final FocusEvent e) { prev = text; // remember so we can clear only when new focus // gained, not when lost // FIXME: Wrong layout of '&' in rap checkWordValidity(text); } private void checkWordValidity(final Text text) { String current = text.getText(); Word word = (Word) text.getData(Word.class.toString()); String reference = word.history().top().form(); if (current.length() != reference.length() || (current.contains(" ") && !reference.contains(" "))) { //$NON-NLS-1$ //$NON-NLS-2$ text.setForeground(text.getDisplay() .getSystemColor(DUBIOUS)); setMessage(Messages.get().YourRecentEdit); } else { status.setText(""); //$NON-NLS-1$ } } @Override public void focusGained(final FocusEvent e) { text.clearSelection(); // use only our persistent marking below Word word = (Word) text.getData(Word.class.toString()); if (word.isLocked()) { setMessage(String.format( Messages.get().Entry + " '%s' " + Messages.get().IsLocked, text.getText())); //$NON-NLS-1$ } text.setEditable(!word.isLocked() && !page.done()); DrcUiActivator.find(CheckView.class).setSelection(text); DrcUiActivator.find(SpecialCharacterView.class).setText(text); DrcUiActivator.find(WordView.class).selectedWord(word, text); DrcUiActivator.find(TagView.class).setWord(word); text.setToolTipText(word.formattedHistory()); if (prev != null && !prev.isDisposed() && !prev.getForeground().equals( text.getDisplay().getSystemColor(DUBIOUS))) { prev.setForeground(text.getDisplay() .getSystemColor(DEFAULT)); } text.setForeground(text.getDisplay().getSystemColor(ACTIVE)); } private void setMessage(String t) { status.setText(t); status.setForeground(status.getDisplay() .getSystemColor(DUBIOUS)); } }); } }