/********************************************************************************
* *
* (c) Copyright 2010 Verizon Communications USA and The Open University UK *
* *
* This software is freely distributed in accordance with *
* the GNU Lesser General Public (LGPL) license, version 3 or later *
* as published by the Free Software Foundation. *
* For details see LGPL: http://www.fsf.org/licensing/licenses/lgpl.html *
* and GPL: http://www.fsf.org/licensing/licenses/gpl-3.0.html *
* *
* This software is provided by the copyright holders and contributors "as is" *
* and any express or implied warranties, including, but not limited to, the *
* implied warranties of merchantability and fitness for a particular purpose *
* are disclaimed. In no event shall the copyright owner or contributors be *
* liable for any direct, indirect, incidental, special, exemplary, or *
* consequential damages (including, but not limited to, procurement of *
* substitute goods or services; loss of use, data, or profits; or business *
* interruption) however caused and on any theory of liability, whether in *
* contract, strict liability, or tort (including negligence or otherwise) *
* arising in any way out of the use of this software, even if advised of the *
* possibility of such damage. *
* *
********************************************************************************/
package com.compendium.ui.panels;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import com.compendium.LanguageProperties;
import com.compendium.ProjectCompendium;
import com.compendium.core.CoreUtilities;
import com.compendium.core.datamodel.IModel;
import com.compendium.core.datamodel.LinkProperties;
import com.compendium.core.datamodel.NodeSummary;
import com.compendium.core.datamodel.PCSession;
import com.compendium.ui.FormatProperties;
import com.compendium.ui.UILink;
import com.compendium.ui.UINavList;
import com.compendium.ui.UINode;
import com.compendium.ui.UIUtilities;
import com.compendium.ui.UIViewPane;
import com.compendium.ui.dialogs.UINodeContentDialog;
import com.compendium.ui.plaf.ViewPaneUI;
/**
* Displays a list of node labels whose labels start with the passed string.
*
* @author Michelle Bachler
*/
public class UIHintNodeLabelPanel extends JPanel {
/** The list of nodes whose labels start with the passed String.*/
private UINavList lstNodes = null;
/** The current view pane.*/
private UIViewPane oPane = null;
/** The node whose label we are trying to match.*/
private UINode oNode = null;
/** The currently selected index of the node list.*/
private int selectedIndex = 0;
/** The current IModel object to use to access the database.*/
private IModel model = null;
/** The current PCSession object to use when accessing the database.*/
private PCSession session = null;
/**
* Constructor. Searches the database and displays a list of node labels starting with the passed string.
*
* @param UIViewPane uiviewpane, the view pane we are to draw this panel in.
* @param NodeSummary node, the node whose label is being searched.
* @param int xPos, the x position to draw this panel.
* @param int yPos, the y position to draw this panel.
* @param String text, the node label text to search on.
*/
public UIHintNodeLabelPanel(UIViewPane uiviewpane, UINode node, int xPos, int yPos, String text) throws Exception {
oPane = uiviewpane;
oNode = node;
model = oNode.getNode().getModel();
session = oNode.getNode().getSession();
if (model != null) {
if (session == null)
session = model.getSession();
}
else {
model = ProjectCompendium.APP.getModel();
session = model.getSession();
}
setBorder(new LineBorder(Color.black, 1));
setLocation(xPos, yPos);
BorderLayout layout = new BorderLayout();
layout.setHgap(0);
layout.setVgap(0);
setLayout(layout);
setBackground(Color.white);
lstNodes = new UINavList();
lstNodes.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION );
NodeListCellRenderer nodeListRenderer = new NodeListCellRenderer();
lstNodes.setCellRenderer(nodeListRenderer);
lstNodes.setBackground(Color.white);
lstNodes.setBorder(null);
final UIViewPane pane = uiviewpane;
lstNodes.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 2) {
onTransclude();
pane.hideLabels();
}
e.consume();
}
});
lstNodes.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
int modifiers = e.getModifiers();
if (keyCode == KeyEvent.VK_ENTER && modifiers == 0) {
onTransclude();
pane.hideLabels();
e.consume();
}
else if (keyCode == KeyEvent.VK_UP && modifiers == 0) {
int index = lstNodes.getSelectedIndex();
if (index == 0) {
oNode.getUI().setEditing();
}
selectedIndex = index;
}
else if (keyCode == KeyEvent.VK_DOWN && modifiers == 0) {
selectedIndex = lstNodes.getSelectedIndex();
}
else if (keyCode == KeyEvent.VK_F1 && modifiers == 0) {
openContents();
}
}
});
JScrollPane sp = new JScrollPane(lstNodes, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
sp.setBorder(null);
sp.setPreferredSize(new Dimension(255,100));
if (!searchLabel(text, node.getNode().getId())) {
throw new Exception(LanguageProperties.getString(LanguageProperties.PANELS_BUNDLE, "UIHintNodeLabelPanel.noMatches")); //$NON-NLS-1$
}
add(sp);
setSize(getPreferredSize());
validate();
}
/**
* Search the database for the given string excluding in the results the passed nodeid.
* Load the results into the displayed list.
*
* @param String text, the text to match against the start of node labels.
* @param String nodeid, the id of the node to exclude from the search results.
* @return boolean, true if results found and loaded, else false.
*/
public boolean searchLabel(String text, String nodeid) {
try {
String cleantext = CoreUtilities.cleanSQLText(text, FormatProperties.nDatabaseType);
IModel model = ProjectCompendium.APP.getModel();
Vector vtNodes = model.getQueryService().searchTransclusions(model.getSession(), cleantext, nodeid);
if (vtNodes.size() > 0) {
vtNodes = CoreUtilities.sortList(vtNodes);
lstNodes.setListData(vtNodes);
return true;
}
}
catch(SQLException ex) {
ProjectCompendium.APP.displayError("Exception:" + ex.getMessage()); //$NON-NLS-1$
}
return false;
}
/**
* Force the cell renderer to recalculate font size.
*/
public void refresh() {
NodeListCellRenderer nodeListRenderer = new NodeListCellRenderer();
lstNodes.setCellRenderer(nodeListRenderer);
lstNodes.repaint();
}
/**
* This class draws the elements of the list of nodes whose labels match
*/
private class NodeListCellRenderer extends JLabel implements ListCellRenderer {
protected Border noFocusBorder;
NodeListCellRenderer() {
super();
noFocusBorder = new EmptyBorder(1, 1, 1, 1);
setOpaque(true);
setBorder(noFocusBorder);
Font font = getFont();
int scale = ProjectCompendium.APP.getToolBarManager().getTextZoom();
Font newFont = new Font(font.getName(), font.getStyle(), font.getSize()+ scale);
setFont(newFont);
}
public Component getListCellRendererComponent(
JList list,
Object value,
int modelIndex,
boolean isSelected,
boolean cellHasFocus) {
removeAll();
NodeSummary node = (NodeSummary)value;
ImageIcon icon = UINode.getNodeImageSmall(node.getType());
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
String text = (String)node.getLabel();
if(text.length() > 40) {
text = text.substring(0,39);
text += "...."; //$NON-NLS-1$
}
setBorder((cellHasFocus) ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder); //$NON-NLS-1$
setIcon(icon);
setText(text);
return this;
}
}
/**
* Open the contents popup for the currently selected node.
*/
public void openContents() {
Object obj = lstNodes.getSelectedValue();
if (obj != null) {
NodeSummary node = (NodeSummary)obj;
node.initialize(session, model);
UINodeContentDialog contentDialog = new UINodeContentDialog(ProjectCompendium.APP, node, UINodeContentDialog.CONTENTS_TAB);
UIUtilities.centerComponent(contentDialog, ProjectCompendium.APP);
contentDialog.setVisible(true);
}
}
/**
* Focus the first line in the node list
*/
public void focusList() {
lstNodes.requestFocus();
lstNodes.setSelectedIndex(0);
}
/**
* Replace the passed node with the one selected from the list of Nodes with matching text.
*/
private void onTransclude() {
Object obj = lstNodes.getSelectedValue();
if (obj != null) {
NodeSummary node = (NodeSummary)obj;
if (oNode != null) {
ViewPaneUI viewpaneui = oPane.getUI();
Point loc = oNode.getNodePosition().getPos();
int x = loc.x;
int y = loc.y;
// preserve links so they can be transfer to the new node.
Vector keepLinks = new Vector();
for(Enumeration es = oNode.getLinks();es.hasMoreElements();) {
UILink uilink = (UILink)es.nextElement();
keepLinks.addElement(uilink);
}
String oldNodeID = oNode.getNode().getId();
// CHECK TO SEE IF THE SELECTED NODE IS ALREADY IN THIS VIEW
// IF IT IS - ASK IF THEY WANT TO CREATE A SHORTCUT
Object obj2 = oPane.get(node.getId());
if (obj2 != null && obj2 instanceof UINode) {
UINode uinode = (UINode)obj2;
int answer = JOptionPane.showConfirmDialog(this,
LanguageProperties.getString(LanguageProperties.PANELS_BUNDLE, "UIHintNodeLabelPanel.message1a")+"\n\n"+
LanguageProperties.getString(LanguageProperties.PANELS_BUNDLE, "UIHintNodeLabelPanel.message1b")+"\n\n",
LanguageProperties.getString(LanguageProperties.PANELS_BUNDLE, "UIHintNodeLabelPanel.message1Title"), //$NON-NLS-1$ //$NON-NLS-2$
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if (answer == JOptionPane.YES_OPTION) {
viewpaneui.onDelete(); // DO I REALLY WANT TO PURGE AT THIS POINT?
UINode uiNode = viewpaneui.createShortCutNode(uinode, x, y);
restoreLinks(keepLinks, oldNodeID, uiNode, viewpaneui);
}
else {
return;
}
}
else {
node.initialize(session, model);
viewpaneui.onDelete();
UINode uiNode = viewpaneui.addNodeToView(node, x, y);
restoreLinks(keepLinks, oldNodeID, uiNode, viewpaneui);
}
}
}
}
/**
* Restore any links that where on the node that was replaced with the transclusion
* @param links the links to restore
* @param oldNodeID the id that the node had before it was replaced
* @param newNode the new translcuded node
* @param viewui the view they are all in
*/
private void restoreLinks(Vector links, String oldNodeID, UINode newNode, ViewPaneUI viewui) {
int count = links.size();
for(int i=0; i<count; i++) {
UILink uilink = (UILink)links.elementAt(i);
LinkProperties props = uilink.getLinkProperties();
UINode fromNode = uilink.getFromNode();
UINode toNode = uilink.getToNode();
if (fromNode == null || fromNode.getNode() == null ||
fromNode.getNode().getId().equals(oldNodeID)) {
viewui.createLink(newNode, toNode, UIUtilities.getLinkType(newNode), props);
} else if (toNode == null || toNode.getNode() == null ||
toNode.getNode().getId().equals(oldNodeID) ) {
viewui.createLink(fromNode, newNode, UIUtilities.getLinkType(newNode), props);
}
}
}
}