/*
createObjectDialog.java
A Dialog to open an object from the database for a variety of operations.
Created: 31 October 1997
Module By: Mike Mulvaney
-----------------------------------------------------------------------
Ganymede Directory Management System
Copyright (C) 1996-2013
The University of Texas at Austin
Ganymede is a registered trademark of The University of Texas at Austin
Contact information
Author Email: ganymede_author@arlut.utexas.edu
Email mailing list: ganymede@arlut.utexas.edu
US Mail:
Computer Science Division
Applied Research Laboratories
The University of Texas at Austin
PO Box 8029, Austin TX 78713-8029
Telephone: (512) 835-3200
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, see <http://www.gnu.org/licenses/>.
*/
package arlut.csd.ganymede.client;
import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import arlut.csd.JDataComponent.TimedKeySelectionManager;
import arlut.csd.JDataComponent.listHandle;
import arlut.csd.JDialog.StandardDialog;
import arlut.csd.JDialog.StringDialog;
import arlut.csd.Util.TranslationService;
import arlut.csd.Util.VecQuickSort;
import arlut.csd.ganymede.common.BaseDump;
import arlut.csd.ganymede.common.Invid;
import arlut.csd.ganymede.common.Query;
import arlut.csd.ganymede.common.QueryDataNode;
import arlut.csd.ganymede.common.QueryResult;
import arlut.csd.ganymede.rmi.Base;
/*------------------------------------------------------------------------------
class
openObjectDialog
------------------------------------------------------------------------------*/
/**
*
* A Dialog to open an object from the database for a variety of operations.
*
*/
public class openObjectDialog extends StandardDialog implements ActionListener, MouseListener {
private final static boolean debug = false;
/**
* TranslationService object for handling string localization in the
* Ganymede client.
*/
static final TranslationService ts = TranslationService.getTranslationService("arlut.csd.ganymede.client.openObjectDialog");
static final String DEFAULT_OPEN = "open_default_type";
static final private String OPEN_OBJ = "Go";
static final private String CANCEL = "Cancel";
boolean
editableOnly = false;
long
lastClick = 0;
Invid
invid = null;
GridBagLayout
gbl;
GridBagConstraints
gbc;
gclient
client;
JPanel
middle;
JList
list = null;
JScrollPane
pane = null;
JComboBox
type;
JButton
ok;
JTextField
text;
listHandle
lastObject = null,
currentObject = null;
JLabel
titleL,
iconL;
ImageIcon
icon;
String selectedBaseName = null;
String selectedObjectName = null;
boolean selectedFound = false;
/* -- */
/**
* <p>This is the constructor for openObjectDialog. The thing worth
* noting about this is that when this object is first constructed,
* it checks gclient to see if an object node is selected in the
* gclient's tree. If so, it will set the object's type and name in
* the appropriate GUI fields as they are constructed.</p>
*
* <p>Note that this field-setting only occurs when this dialog is
* first constructed. I would have had to rewrite a lot of this
* class to make it so that the base/object name fields could have
* been set after the fact, so I just didn't. gclient is set up to
* dispose of an old instance of this and recreate one as necessary.
* It's a shameful hack, but it works, and it's not worth investing
* much more time here to avoid the redundant dialog creation.</p>
*/
public openObjectDialog(gclient client)
{
super(client, ts.l("init.dialog_title"), StandardDialog.ModalityType.DOCUMENT_MODAL); // "Open object"
this.client = client;
InvidNode selectedNode = client.getSelectedObjectNode();
if (selectedNode != null)
{
selectedBaseName = selectedNode.getTypeText();
// if we get the handle and query it for its label, we
// avoid getting the "(inactive") tacked on for inactive
// objects.
selectedObjectName = selectedNode.getHandle().getLabel();
selectedFound = true;
}
else
{
if (gclient.prefs != null)
{
selectedBaseName = gclient.prefs.get(DEFAULT_OPEN, null);
}
}
gbl = new GridBagLayout();
gbc = new GridBagConstraints();
getContentPane().setLayout(new BorderLayout());
middle = new JPanel(gbl);
getContentPane().add(middle, BorderLayout.CENTER);
gbc.insets = new Insets(4,4,4,4);
// Set up the dialog's icon (by default, no icon).
// gclient actually specifies the image
// by calling openObjectDialog's setIcon method.
this.icon = new ImageIcon();
iconL = new JLabel(icon);
iconL.setBorder(new EmptyBorder(10,15,10,15));
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 1;
gbl.setConstraints(iconL, gbc);
middle.add(iconL);
// "Choose object:"
titleL = new JLabel(ts.l("init.initial_title_label"), SwingConstants.CENTER);
titleL.setFont(new Font("Helvetica", Font.BOLD, 14));
titleL.setOpaque(true);
titleL.setBorder(client.emptyBorder5);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbl.setConstraints(titleL, gbc);
middle.add(titleL);
gbc.fill = GridBagConstraints.NONE;
gbc.gridwidth = 1;
type = new JComboBox();
type.setKeySelectionManager(new TimedKeySelectionManager());
// Ideally, we'd really like for our JComboBox's pop-ups to be
// able to go beyond the borders of our dialog. Unfortunately,
// the Swing library, up to and including Swing 1.1 beta 3, is
// hideously broken when it comes to handling pop-ups in dialogs.
// By leaving it lightweight, our pop-up will get truncated to the
// dialog's edges, but at least it will be fully displayed, with a
// scrollable menu region that fits within our dialog.
// ** type.setLightWeightPopupEnabled(false);
Vector<Base> bases = client.getBaseList();
Hashtable<Base, Short> baseToShort = client.getBaseToShort();
Hashtable<Base, String> baseNames = client.getBaseNames();
Vector<listHandle> listHandles = new Vector<listHandle>();
for (Base thisBase: bases)
{
String name = baseNames.get(thisBase);
if (!((BaseDump) thisBase).isEmbedded())
{
listHandle lh = new listHandle(name, baseToShort.get(thisBase));
listHandles.add(lh);
}
}
listHandles = client.sortListHandleVector(listHandles);
for (listHandle handle: listHandles)
{
type.addItem(handle);
}
if (selectedBaseName != null)
{
for (listHandle lh: listHandles)
{
if (lh.getLabel().equals(selectedBaseName))
{
type.setSelectedItem(lh);
break;
}
}
}
gbc.gridx = 0;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.NONE;
gbc.gridwidth = 2;
// "Object Type:"
JLabel oType = new JLabel(ts.l("init.type_label"));
gbl.setConstraints(oType, gbc);
middle.add(oType);
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridx = 2;
gbl.setConstraints(type, gbc);
middle.add(type);
// "Object Name:"
JLabel editTextL = new JLabel(ts.l("init.name_label"));
gbc.fill = GridBagConstraints.NONE;
gbc.gridwidth = 2;
gbc.gridx = 0;
gbc.gridy = 2;
gbl.setConstraints(editTextL, gbc);
middle.add(editTextL);
text = new JTextField(20);
if (selectedFound && selectedObjectName != null)
{
text.setText(selectedObjectName);
}
text.addActionListener(this);
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridx = 2;
gbl.setConstraints(text, gbc);
middle.add(text);
ok = new JButton(StringDialog.getDefaultOk());
ok.setActionCommand(OPEN_OBJ);
ok.addActionListener(this);
JButton neverMind = new JButton(StringDialog.getDefaultCancel());
neverMind.setActionCommand(CANCEL);
neverMind.addActionListener(this);
if (isRunningOnMac())
{
JPanel macPanel = new JPanel();
macPanel.setLayout(new BorderLayout());
JPanel buttonP = new JPanel();
buttonP.add(neverMind);
buttonP.add(ok);
macPanel.add(buttonP, BorderLayout.EAST);
getContentPane().add(macPanel, BorderLayout.SOUTH);
}
else
{
JPanel buttonP = new JPanel();
buttonP.add(ok);
buttonP.add(neverMind);
getContentPane().add(buttonP, BorderLayout.SOUTH);
}
setBounds(150,100, 200,100);
}
public Invid chooseInvid()
{
invalidate();
validate();
pack();
type.requestFocus();
setVisible(true);
return invid;
}
public void setText(String text)
{
titleL.setText(text);
}
public void setIcon(ImageIcon icon)
{
iconL.setIcon(icon);
}
public void setReturnEditableOnly(boolean editableOnly)
{
this.editableOnly = editableOnly;
}
public String getTypeString()
{
listHandle lh = (listHandle)type.getSelectedItem();
return lh.getLabel();
}
public void close(boolean foundOne)
{
// Make sure we return null if we didn't find one
if (!foundOne)
{
invid = null;
}
if (gclient.prefs != null)
{
gclient.prefs.put(DEFAULT_OPEN, getTypeString());
}
setVisible(false);
text.setText("");
if (list != null)
{
if (debug)
{
System.out.println("Removing the list");
}
pane.remove(list);
}
if (pane != null)
{
if (debug)
{
System.out.println("Removing pane");
}
middle.remove(pane);
}
if (debug)
{
System.out.println("Nulling the pane and list");
}
pane = null;
list = null;
}
public void actionPerformed(ActionEvent e)
{
if (debug)
{
System.out.println("Action performed: " + e.getActionCommand());
}
if (e.getSource() == text)
{
ok.doClick();
}
else if (e.getActionCommand().equals(OPEN_OBJ))
{
String string = text.getText();
if ((string == null) || (string.equals("")))
{
// "Error, no object label provided to object open dialog."
client.setStatus(ts.l("actionPerformed.name_missing_status"));
return;
}
if ((currentObject != null) && (string.equals(currentObject.getLabel())))
{
// This was set from the listbox, and hasn't been changed.
invid = (Invid)currentObject.getObject();
close(true);
return;
}
// We're looking up a new one. Deselect the selected node in
// the tree, since we're going to be working with a different
// object.
client.tree.unselectAllNodes(true);
client.tree.refresh();
currentObject = null;
if (list == null)
{
list = new JList();
list.setBorder(client.lineBorder);
list.setModel(new DefaultListModel());
list.addMouseListener(this);
}
else
{
((DefaultListModel)list.getModel()).clear();
}
if (pane == null)
{
pane = new JScrollPane(list);
// "Matching Objects"
pane.setBorder(new TitledBorder(ts.l("actionPerformed.matching_border")));
}
listHandle lh = (listHandle) type.getSelectedItem();
Short baseID = (Short) lh.getObject();
if (debug)
{
System.out.println("BaseID = " + baseID + ", string = " + string);
}
// "Searching for object named {0}."
client.setStatus(ts.l("actionPerformed.searching_status", string));
// First see if this exactly matches something, then do the STARTSWITH stuff
try
{
invid = client.session.findLabeledObject(string, baseID, false);
if (invid != null)
{
// "Found object named {0}."
client.setStatus(ts.l("actionPerformed.found_status", string));
close(true);
return;
}
}
catch (java.rmi.RemoteException ex)
{
close(false);
client.processExceptionRethrow(ex, "Remote Exception calling findLabeledObject()");
}
// no direct match, let's look for a prefix match
try
{
if (debug)
{
System.out.println("Looking for Startswith...");
}
// "Searching for objects whose names begin with {0}."
client.setStatus(ts.l("actionPerformed.searching_prefix_status", string));
QueryDataNode node = new QueryDataNode(QueryDataNode.NOCASEMATCHES, "^" + string);
QueryResult edit_query = client.session.query(new Query(baseID.shortValue(), node, editableOnly));
Vector<listHandle> edit_invids = edit_query.getListHandles();
// and add a direct match of a different type, if it exists
invid = client.session.findLabeledObject(string, baseID, true);
if (invid != null)
{
String matchLabel = client.session.viewObjectLabel(invid);
edit_invids.add(0, new listHandle("(" + client.getObjectType(invid) + ") " + string, invid));
}
if (edit_invids.size() == 1)
{
invid = (Invid) edit_invids.get(0).getObject();
close(true);
}
else if (edit_invids.size() == 0)
{
// "Error Finding Object"
// "No editable object starts with that string."
// "No viewable object starts with that string."
client.showErrorMessage(ts.l("actionPerformed.error_title"),
editableOnly ?
ts.l("actionPerformed.no_editable_text") :
ts.l("actionPerformed.no_viewable_text"));
return;
}
else
{
(new VecQuickSort(edit_invids,
new Comparator() {
public int compare(Object a, Object b)
{
listHandle aF, bF;
aF = (listHandle) a;
bF = (listHandle) b;
int comp = 0;
comp = aF.toString().compareToIgnoreCase(bF.toString());
if (comp < 0)
{
return -1;
}
else if (comp > 0)
{
return 1;
}
else
{
return 0;
}
}
})).sort();
DefaultListModel model = (DefaultListModel)list.getModel();
for (listHandle handle: edit_invids)
{
model.addElement(handle);
}
gbc.gridx = 0;
gbc.gridy = 3;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbl.setConstraints(pane, gbc);
middle.add(pane);
pack();
}
}
catch (java.rmi.RemoteException rx)
{
close(false);
client.processExceptionRethrow(rx, "Remote Exception opening object");
}
}
else if (e.getActionCommand().equals(CANCEL))
{
close(false);
}
}
public void mouseClicked(MouseEvent e)
{
currentObject = (listHandle) list.getSelectedValue();
if ((e.getWhen() - lastClick < 500) && (currentObject == lastObject))
{
invid = (Invid)((listHandle)currentObject).getObject();
close(true);
}
else
{
text.setText(currentObject.toString());
}
lastClick = e.getWhen();
lastObject = currentObject;
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}