/*
* org.openmicroscopy.shoola.util.ui.omeeditpane.OMEWikiComponent
*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2015 University of Dundee. All rights reserved.
*
*
* This program 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.
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.util.ui.omeeditpane;
//Java imports
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusListener;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.border.Border;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import org.openmicroscopy.shoola.util.CommonsLangUtils;
import org.openmicroscopy.shoola.util.ui.IconManager;
import org.openmicroscopy.shoola.util.ui.UIUtilities;
/**
* The Wiki component.
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author Donald MacDonald
* <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a>
* @version 3.0
* @since 3.0-Beta4
*/
public class OMEWikiComponent
extends JPanel
implements ActionListener
{
/** Bounds property indicating that a data object has been selected. */
public static final String WIKI_DATA_OBJECT_PROPERTY = "wikiDataObject";
/** Bounds property indicating that a data object has been selected. */
public static final String WIKI_DATA_OBJECT_ONE_CLICK_PROPERTY =
"wikiDataObjectOneClick";
/** Bounds property indicating that the text has been updated. */
public static final String TEXT_UPDATE_PROPERTY = "textUpdate";
/** Regular expression for text. */
public static final String TEXTREGEX = OMEWikiConstants.TEXTREGEX;
/** Regular for a sentence. */
public static final String SENTENCEREGEX = OMEWikiConstants.SENTENCEREGEX;
/** Regular for a sequence of characters. */
public static final String CHARACTERREGEX = OMEWikiConstants.CHARACTERREGEX;
/** Regular expression for a <code>Wiki</code> link. */
public static final String WIKILINKREGEX = OMEWikiConstants.WIKILINKREGEX;
/** Regular expression defining Thumbnail. */
public static final String THUMBNAILREGEX = OMEWikiConstants.THUMBNAILREGEX;
/** Regular expression defining Dataset. */
public static final String DATASETREGEX = OMEWikiConstants.DATASETREGEX;
/** Regular expression defining Project. */
public static final String PROJECTREGEX = OMEWikiConstants.PROJECTREGEX;
/** Regular expression defining Image. */
public static final String IMAGEREGEX = OMEWikiConstants.IMAGEREGEX;
/** Regular expression defining Wiki Heading. */
public static final String HEADINGREGEX = OMEWikiConstants.HEADINGREGEX;
/** Regular expression for a bullet list. */
public static final String BULLETREGEX = OMEWikiConstants.BULLETREGEX;
/** Regular expression for bold. */
public static final String BOLDREGEX = OMEWikiConstants.BOLDREGEX;
/** Italic regular expression. */
public static final String ITALICREGEX = OMEWikiConstants.ITALICREGEX;
/** Italic and bold regular expression. */
public static final String ITALICBOLDREGEX =
OMEWikiConstants.ITALICBOLDREGEX;
/** Indent regular expression. */
public static final String INDENTREGEX = OMEWikiConstants.INDENTREGEX;
/** regular expression defining a URL. */
public static final String URLREGEX = OMEWikiConstants.URLREGEX;
/** regular expression for names linked. */
public static final String NAMEDLINKREGEX = OMEWikiConstants.NAMEDLINKREGEX;
/** Action id to create an hyperlink. */
private static final int HYPERLINK = 0;
/** Action id to create an image's entry. */
private static final int IMAGE = 1;
/** Action id to create a protocol's entry. */
private static final int PROTOCOL = 2;
/** The number of columns before splitting text.*/
private static final int COLUMNS = 45;
/** The formatters installed by default. */
private static Map<String, FormatSelectionAction> DEFAULT_FORMATTERS;
static {
DEFAULT_FORMATTERS = new LinkedHashMap<String, FormatSelectionAction>();
DEFAULT_FORMATTERS.put(URLREGEX,
new FormatSelectionAction(
new ColourFormatter(Formatter.DEFAULT_URL, false),
new URLLaunchAction()));
/*
DEFAULT_FORMATTERS.put(IMAGEREGEX,
new FormatSelectionAction(
new ColourFormatter(Formatter.DEFAULT_LINK),
new ElementSelectionAction(WikiDataObject.IMAGE)));
DEFAULT_FORMATTERS.put(PROTOCOLREGEX,
new FormatSelectionAction(
new ColourFormatter(Formatter.PROTOCOL_LINK),
new ElementSelectionAction(WikiDataObject.PROTOCOL)));
*/
}
/** The edit pane. */
private OMEEditPane pane;
/** The tool bar. */
private JToolBar toolBar;
/** The default components displayed in the tool bar. */
private List<JButton> toolBarActions;
/** This text will be removed when starting typing. */
private String defaultText;
/** Flag indicating that one click is supported if <code>true</code>. */
private boolean allowOneClick;
/** Flag indicating to wrap or not the word.*/
private boolean wrapWord;
/** The default number of columns before formatting the text.*/
private int columns;
/**
* Replaces the line separator by space when saving the data.
*
* @param value The value to handle.
* @param removeSpace Pass <code>true</code> to remove the spaces,
* <code>false</code> otherwise.
* @return See above.
*/
public static String prepare(String value, boolean removeSpace)
{
String v = value.replaceAll(CommonsLangUtils.LINE_SEPARATOR, " ");
if (removeSpace) return v.replaceAll(" ", "");
return v;
}
/** Installs the default actions. */
private void installDefaultAction()
{
toolBarActions = new ArrayList<JButton>();
IconManager icons = IconManager.getInstance();
JButton b = new JButton(icons.getIcon(IconManager.HYPERLINK));
b.addActionListener(this);
b.setActionCommand(""+HYPERLINK);
b.setToolTipText(OMEWikiConstants.HYPERLINK_TOOLTIP);
toolBarActions.add(b);
/*
b = new JButton(icons.getIcon(IconManager.IMAGE));
b.setToolTipText(OMEWikiConstants.IMAGE_TOOLTIP);
b.addActionListener(this);
b.setActionCommand(""+IMAGE);
toolBarActions.add(b);
b = new JButton(icons.getIcon(IconManager.FILE_EDITOR));
b.setToolTipText(OMEWikiConstants.PROTOCOL_TOOLTIP);
b.addActionListener(this);
b.setActionCommand(""+PROTOCOL);
UIUtilities.unifiedButtonLookAndFeel(b);
toolBarActions.add(b);
*/
}
/**
* Creates a new component.
*
* @param formatters The formatters for the text.
* @param toolbar Pass <code>true</code> to install a default toolbar,
* <code>false</code> otherwise.
*/
private void initComponents(Map<String, FormatSelectionAction> formatters,
boolean toolbar)
{
columns = COLUMNS;
wrapWord = true;
defaultText = "";
pane = new OMEEditPane(this, formatters);
pane.setMaximumSize(new Dimension(100,100));
if (toolbar) {
installDefaultAction();
toolBar = new JToolBar();
toolBar.setBackground(UIUtilities.BACKGROUND_COLOR);
toolBar.setBorder(null);
toolBar.setFloatable(false);
for (JButton button : toolBarActions) {
toolBar.add(button);
}
}
setBackground(UIUtilities.BACKGROUND);
}
/** Builds and lays out the UI. */
private void buildGUI()
{
if (toolBar != null) {
JPanel p = new JPanel();
p.setBackground(UIUtilities.BACKGROUND_COLOR);
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
p.add(Box.createVerticalStrut(5));
JPanel bar = UIUtilities.buildComponentPanel(toolBar, 0, 0);
bar.setBackground(UIUtilities.BACKGROUND_COLOR);
p.add(bar);
p.add(Box.createVerticalStrut(2));
add(p, BorderLayout.NORTH);
}
setLayout(new BorderLayout());
add(pane, BorderLayout.CENTER);
}
/** Creates a default new instance. */
public OMEWikiComponent()
{
this(DEFAULT_FORMATTERS, true);
}
/**
* Creates a new instance with default formatters.
*
* @param toolBar Pass <code>true</code> to install a default toolbar,
* <code>false</code> otherwise.
*/
public OMEWikiComponent(boolean toolBar)
{
this(DEFAULT_FORMATTERS, toolBar);
}
/**
* Returns the default text or an empty string.
*
* @return See above.
*/
String getDefaultText() { return defaultText; }
/**
* Creates a new instance.
*
* @param formatters The formatters for the text.
* @param toolBar Pass <code>true</code> to install a default toolbar,
* <code>false</code> otherwise.
*/
public OMEWikiComponent(Map<String, FormatSelectionAction> formatters,
boolean toolBar)
{
for (Entry<String,FormatSelectionAction> formatterMap : DEFAULT_FORMATTERS.entrySet()) {
String key = formatterMap.getKey();
if (!formatters.containsKey(key))
formatters.put(key, formatterMap.getValue());
}
initComponents(formatters, toolBar);
buildGUI();
}
/**
* Called when the mouse is pressed and calls the actionPerformed event for
* the appropriate SelectionAction of the formatter.value.
*
* @param action The action to handle.
* @param text The selected text.
* @param count The number of count.
*/
void onSelection(SelectionAction action, String text, int count)
{
if (action == null) return;
int ref = 2;
if (!isEnabled()) {
if (action instanceof URLLaunchAction && count == 1) {
action.onSelection(text);
} else {
if ((action instanceof ElementSelectionAction)) {
action.onSelection(text);
ElementSelectionAction a = (ElementSelectionAction) action;
int index = a.getWikiDataObjectIndex();
long id = a.getObjectID();
if (id >= 0) {
WikiDataObject object = new WikiDataObject(index, id);
if (allowOneClick) {
if (count == 1) {
firePropertyChange(
WIKI_DATA_OBJECT_ONE_CLICK_PROPERTY,
null, object);
}
else if (count == 2)
firePropertyChange(WIKI_DATA_OBJECT_PROPERTY,
null, object);
} else {
if (count == 1)
firePropertyChange(WIKI_DATA_OBJECT_PROPERTY,
null, object);
}
}
}
}
} else {
if (action instanceof ElementSelectionAction && count == ref) {
action.onSelection(text);
ElementSelectionAction a = (ElementSelectionAction) action;
int index = a.getWikiDataObjectIndex();
long id = a.getObjectID();
if (id >= 0) {
WikiDataObject object = new WikiDataObject(index, id);
firePropertyChange(WIKI_DATA_OBJECT_PROPERTY, null, object);
}
} else if (action instanceof URLLaunchAction) {
if (allowOneClick) ref = 1;
if (count == ref) action.onSelection(text);
}
}
}
/**
* Returns <code>true</code> if the passed text is the default text,
* <code>false</code> otherwise.
*
* @param text The value to check.
* @return See above.
*/
boolean isDefaultText(String text)
{
if (text == null) return false;
return (defaultText.equals(text.trim()));
}
/**
* Installs formatter for various objects.
*/
public void installObjectFormatters()
{
pane.addFormatter(IMAGEREGEX,
new FormatSelectionAction(
new ColourFormatter(Formatter.DEFAULT_LINK, false),
new ElementSelectionAction(WikiDataObject.IMAGE)));
pane.addFormatter(DATASETREGEX,
new FormatSelectionAction(
new ColourFormatter(Formatter.DEFAULT_LINK, false),
new ElementSelectionAction(WikiDataObject.DATASET)));
pane.addFormatter(PROJECTREGEX,
new FormatSelectionAction(
new ColourFormatter(Formatter.DEFAULT_LINK, false),
new ElementSelectionAction(WikiDataObject.PROJECT)));
}
/**
* Sets the default text.
*
* @param text The value to set.
*/
public void setDefaultText(String text)
{
if (text == null) return;
defaultText = text.trim();
}
/**
* Selects all the text in the <code>TextComponent</code>.
* Does nothing on a <code>null</code> or empty document.
*/
public void selectAll() { pane.selectAll(); }
/**
* Sets the position of the text insertion caret for the
* <code>TextComponent</code>.
*
* @param n The position.
*/
public void setCaretPosition(int n) { pane.setCaretPosition(n); }
/**
* Sets the text.
*
* @param text The value to set.
*/
public void setText(String text) { pane.setText(text); }
/**
* Returns the text.
*
* @return See above.
*/
public String getText() { return pane.getText(); }
/**
* Adds the specified listener to the {@link #pane}.
*
* @param listener The listener to add.
*/
public void addDocumentListener(DocumentListener listener)
{
if (listener != null) pane.getDocument().addDocumentListener(listener);
}
/**
* Removes the specified listener from the {@link #pane}.
*
* @param listener The listener to add.
*/
public void removeDocumentListener(DocumentListener listener)
{
if (listener != null)
pane.getDocument().removeDocumentListener(listener);
}
/**
* Sets the border of the component.
*
* @param border The component to set.
*/
public void setComponentBorder(Border border)
{
pane.setBorder(border);
}
/**
* Sets the value indicating that the one click is supported if the
* <code>enabled</code> flag is <code>false</code>.
*
* @param allowOneClick Pass <code>true</code> to allow one click event,
* <code>false</code> otherwise.
*/
public void setAllowOneClick(boolean allowOneClick)
{
this.allowOneClick = allowOneClick;
}
/**
* Indicates to wrap the text or not.
*
* @param wrapWord Pass <code>true</code> to wrap the text,
* <code>false</code> otherwise.
*/
public void setWrapWord(boolean wrapWord)
{
this.wrapWord = wrapWord;
}
/**
* Invokes when the text needs to be wrapped.
*
* @param width The width to use.
* @param newLineStr The string used for new line.
*/
public void wrapText(int width, String newLineStr)
{
if (pane == null)
return;
String value = getText();
if (value == null) return;
value = prepare(value, false);
FontMetrics fm = getFontMetrics(getFont());
int charWidth = fm.charWidth('m');
columns = (int) (1.5 * width) / charWidth;
setText(CommonsLangUtils.wrap(value, columns, newLineStr, wrapWord));
}
/**
* Overridden to set the flag for all components.
* @see JPanel#setEnabled(boolean)
*/
public void setEnabled(boolean enabled)
{
super.setEnabled(enabled);
if (pane != null) pane.setEditable(enabled);
if(toolBarActions != null)
{
for (JButton toolBarButton : toolBarActions) {
toolBarButton.setEnabled(enabled);
}
}
}
/**
* Overridden to set the background color of all the components.
* @see JPanel#setBackground(Color)
*/
public void setBackground(Color color)
{
super.setBackground(color);
Component[] comp = getComponents();
if (comp != null) {
for (int i = 0; i < comp.length; i++) {
if (comp[i] instanceof JComponent) {
((JComponent) comp[i]).setBackground(color);
}
}
}
if (pane != null) pane.setBackground(color);
if (toolBar != null) {
toolBar.setBackground(color);
comp = toolBar.getComponents();
for (int i = 0; i < comp.length; i++) {
if (comp[i] instanceof JComponent) {
((JComponent) comp[i]).setBackground(color);
}
}
}
}
/**
* Overridden to set the foreground color of the {@link #pane}.
* @see JPanel#setForeground(Color)
*/
public void setForeground(Color color)
{
if (pane != null) pane.setForeground(color);
}
/**
* Overridden to set the font of {@link #pane}.
* @see JPanel#setFont(Font)
*/
public void setFont(Font font)
{
if (pane != null) pane.setFont(font);
}
/**
* Overridden to set the font of {@link #pane}.
* @see JPanel#getFont()
*/
public Font getFont()
{
if (pane == null) return super.getFont();
return pane.getFont();
}
/**
* Inserts text depending on the action.
* @see ActionListener#actionPerformed(ActionEvent)
*/
public void actionPerformed(ActionEvent e)
{
int index = Integer.parseInt(e.getActionCommand());
String s = getText();
switch (index) {
case IMAGE:
if (isDefaultText(s))
setText(OMEWikiConstants.DEFAULT_IMAGE);
else setText(s+" "+OMEWikiConstants.DEFAULT_IMAGE);
pane.requestFocus();
break;
case HYPERLINK:
if (isDefaultText(s))
setText(OMEWikiConstants.DEFAULT_HYPERLINK);
else setText(s+" "+OMEWikiConstants.DEFAULT_HYPERLINK);
pane.requestFocus();
break;
case PROTOCOL:
if (isDefaultText(s))
setText(OMEWikiConstants.DEFAULT_PROTOCOL);
else setText(s+" "+OMEWikiConstants.DEFAULT_PROTOCOL);
pane.requestFocus();
}
}
@Override
public void addFocusListener(FocusListener l) {
pane.addFocusListener(l);
}
/** Get reference to the underlying {@link Document} */
public Document getDocument() {
return pane.getDocument();
}
/** Invokes when the text is modified.*/
void onUpdate() {
firePropertyChange(TEXT_UPDATE_PROPERTY, Boolean.FALSE, Boolean.TRUE);
}
}