/*
ownershipPanel.java
The ownershipPanel is used in the Ganymede client to display
objects owned when the user opens a Ganymede Owner Group window.
Created: 9 September 1997
Module By: Michael Mulvaney
-----------------------------------------------------------------------
Ganymede Directory Management System
Copyright (C) 1996-2014
The University of Texas at Austin
Ganymede is a registered trademark of The University of Texas at Austin
Contact information
Web site: http://www.arlut.utexas.edu/gash2
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.CardLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.rmi.RemoteException;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import arlut.csd.JDataComponent.JAddValueObject;
import arlut.csd.JDataComponent.JAddVectorValueObject;
import arlut.csd.JDataComponent.JDeleteValueObject;
import arlut.csd.JDataComponent.JDeleteVectorValueObject;
import arlut.csd.JDataComponent.JParameterValueObject;
import arlut.csd.JDataComponent.JValueObject;
import arlut.csd.JDataComponent.JsetValueCallback;
import arlut.csd.JDataComponent.StringSelector;
import arlut.csd.JDataComponent.TimedKeySelectionManager;
import arlut.csd.Util.TranslationService;
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.common.ReturnVal;
import arlut.csd.ganymede.common.SchemaConstants;
import arlut.csd.ganymede.rmi.Base;
import arlut.csd.ganymede.rmi.db_field;
import arlut.csd.ganymede.rmi.db_object;
import arlut.csd.ganymede.rmi.invid_field;
import arlut.csd.ganymede.rmi.Session;
/*------------------------------------------------------------------------------
class
ownershipPanel
------------------------------------------------------------------------------*/
/**
* The ownershipPanel is used in the Ganymede client to display objects owned
* when the user opens a Ganymede Owner Group window.
*/
public class ownershipPanel extends JPanel implements ItemListener {
/**
* TranslationService object for handling string localization in the
* Ganymede client.
*/
static final TranslationService ts = TranslationService.getTranslationService("arlut.csd.ganymede.client.ownershipPanel");
boolean
editable;
framePanel
parent;
gclient
gc;
JPanel
center;
JComboBox
bases;
Hashtable<Short, Base> objects_owned = null; // (Short)Base type -> (Vector)list of objects [all objects]
Hashtable<String, objectPane> paneHash = null; // (String) base name -> objectPane holding base objects
CardLayout
cards;
JPanel
holder;
QueryDataNode
node;
/* -- */
public ownershipPanel(boolean editable, framePanel parent)
{
this.editable = editable;
this.parent = parent;
gc = parent.wp.gc;
setLayout(new BorderLayout());
holder = new JPanel();
// "Loading ownershipPanel."
holder.add(new JLabel(ts.l("init.loading_label")));
add("Center", holder);
cards = new CardLayout();
center = new JPanel(false);
center.setLayout(cards);
// Build the combo box from the baseList
JPanel bp = new JPanel(false);
bases = new JComboBox();
bases.setKeySelectionManager(new TimedKeySelectionManager());
// "Object type:"
bp.add(new JLabel(ts.l("init.type_label")));
bp.add(bases);
Vector<Base> baseList = gc.getBaseList();
Hashtable<Base, String> baseNames = gc.getBaseNames();
Hashtable<Base, Short> baseToShort = gc.getBaseToShort();
paneHash = new Hashtable<String, objectPane>();
try
{
for (Base b: baseList)
{
if (!b.isEmbedded())
{
String name = baseNames.get(b);
bases.addItem(name);
objectPane p = new objectPane(editable,
this,
baseToShort.get(b).shortValue());
paneHash.put(name, p);
center.add(name, p);
}
}
}
catch (RemoteException rx)
{
throw new RuntimeException("could not load the combobox: " + rx);
}
bases.addItemListener(this);
remove(holder);
add("North", bp);
add("Center", center);
invalidate();
parent.validate();
JPanel emptyP = new JPanel();
center.add("empty", emptyP);
cards.show(center, "empty");
}
public void itemStateChanged(ItemEvent event)
{
if (event.getStateChange() == ItemEvent.SELECTED)
{
String item = (String)event.getItem();
objectPane op = paneHash.get(item);
if (!op.isStarted())
{
Thread thread = new Thread(op);
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
cards.show(center, item);
}
}
public void dispose()
{
parent = null;
gc = null;
removeAll();
if (center != null)
{
center.removeAll();
center = null;
}
bases = null;
if (objects_owned != null)
{
objects_owned.clear();
objects_owned = null;
}
if (paneHash != null)
{
paneHash.clear();
paneHash = null;
}
cards = null;
if (holder != null)
{
holder.removeAll();
holder = null;
}
node = null;
}
}
/*------------------------------------------------------------------------------
class
objectPane
------------------------------------------------------------------------------*/
/**
* The objectPane class is a JPanel subclass used in the Ganymede client
* to display a list of objects of a given type contained in a Ganymede Owner
* Group.
*/
class objectPane extends JPanel implements JsetValueCallback, Runnable {
/**
* TranslationService object for handling string localization in the
* Ganymede client.
*/
static final TranslationService ts = TranslationService.getTranslationService("arlut.csd.ganymede.client.objectPane");
// ---
private
boolean stringSelector_loaded = false;
private
StringSelector ss;
private
boolean editable;
private
Vector owned, possible;
private
short type;
private
QueryResult result;
private
ownershipPanel parent;
private
JPanel filler;
private
boolean isStarted = false;
private
gclient gc;
/* -- */
// Most of the work is in the create() method, only called after this panel is shown
public objectPane(boolean editable, ownershipPanel parent, short type)
{
this.editable = editable;
this.type = type;
this.parent = parent;
gc = parent.gc;
setLayout(new BorderLayout());
filler = new JPanel();
// "Creating panel, please wait."
filler.add(new JLabel(ts.l("init.loading_label")));
add("Center", filler);
}
public boolean isStarted()
{
return isStarted;
}
public void run()
{
objectList
list = null;
/* -- */
isStarted = true;
// Get the list of selected choices
try
{
QueryResult qResult;
// go back to the framePanel to get the invid for this owner
// group
QueryDataNode node = new QueryDataNode(SchemaConstants.OwnerListField,
QueryDataNode.EQUALS,
QueryDataNode.CONTAINS,
parent.parent.getObjectInvid());
qResult = gc.getSession().query(new Query(type, node, false)); // no filtering, allow non-editables
owned = new objectList(qResult).getListHandles(false, true); // include non-editables
}
catch (RemoteException rx)
{
throw new RuntimeException("Could not get Query: " + rx);
}
// Get the list of possible objects
Short key = Short.valueOf(type);
try
{
if (gc.cachedLists.containsList(key))
{
list = gc.cachedLists.getList(key);
possible = list.getListHandles(false);
}
else
{
// "Downloading list of owned objects."
gc.setStatus(ts.l("run.downloading_status"));
result = gc.getSession().query(new Query(type)); // no filtering
list = new objectList(result);
possible = list.getListHandles(false);
gc.cachedLists.putList(key, list);
}
}
catch (RemoteException rx)
{
throw new RuntimeException("Could not get QueryResult for all objects: " + rx);
}
ss = new StringSelector(this, editable, true, true);
ss.update(possible, true, null, owned, true, null);
ss.setCellWidth((possible != null && editable) ? 150 : 300);
// "Selected"
// "Available"
ss.setTitles(ts.l("run.column1"), ts.l("run.column2"));
// we need to create two separate pop up menus so the
// StringSelector can attach them to its two
// arlut.csd.JDataComponent.JstringListBox components without
// having each listen to the other's events. Also, each menu item
// is limited to belonging to a single menu, so we have to create
// redundant menuitems with identical action commands set.
JPopupMenu invidTablePopup = new JPopupMenu();
// "View object"
JMenuItem viewObj = new JMenuItem(ts.l("run.view_popup"));
viewObj.setActionCommand("View object");
// "Edit object"
JMenuItem editObj = new JMenuItem(ts.l("run.edit_popup"));
editObj.setActionCommand("Edit object");
invidTablePopup.add(viewObj);
invidTablePopup.add(editObj);
JPopupMenu invidTablePopup2 = new JPopupMenu();
// "View object"
JMenuItem viewObj2 = new JMenuItem(ts.l("run.view_popup"));
viewObj2.setActionCommand("View object");
// "Edit object"
JMenuItem editObj2 = new JMenuItem(ts.l("run.edit_popup"));
editObj2.setActionCommand("Edit object");
invidTablePopup2.add(viewObj2);
invidTablePopup2.add(editObj2);
ss.setPopups(invidTablePopup, invidTablePopup2);
ss.setCallback(this);
remove(filler);
add("Center", ss);
invalidate();
parent.validate();
stringSelector_loaded = true;
// "Done downloading list of ownerd objects."
gc.setStatus(ts.l("run.done_status"));
}
public boolean isCreated()
{
return stringSelector_loaded;
}
/**
*
* Callback for our stringSelector
*
*/
public boolean setValuePerformed(JValueObject e)
{
ReturnVal retVal;
boolean succeeded = false;
/* -- */
// First, are we being given a menu operation from StringSelector?
if (e instanceof JParameterValueObject)
{
String command = (String) e.getParameter();
if (command.equals("Edit object"))
{
Invid invid = (Invid) e.getValue();
gc.editObject(invid);
return true;
}
else if (command.equals("View object"))
{
Invid invid = (Invid) e.getValue();
gc.viewObject(invid);
return true;
}
}
else if (e instanceof JAddValueObject)
{
try
{
retVal = addToOwnerGroup((Invid) e.getValue());
if (retVal != null)
{
gc.handleReturnVal(retVal);
}
succeeded = (retVal == null) ? true : retVal.didSucceed();
}
catch (RemoteException rx)
{
throw new RuntimeException("Could not add value to list: " + rx);
}
}
else if (e instanceof JAddVectorValueObject)
{
try
{
retVal = addToOwnerGroup((Vector<Invid>) e.getValue());
if (retVal != null)
{
gc.handleReturnVal(retVal);
}
succeeded = (retVal == null) ? true : retVal.didSucceed();
}
catch (RemoteException rx)
{
throw new RuntimeException("Could not add values to list: " + rx);
}
}
else if (e instanceof JDeleteValueObject)
{
try
{
retVal = removeFromOwnerGroup((Invid) e.getValue());
if (retVal != null)
{
gc.handleReturnVal(retVal);
}
succeeded = (retVal == null) ? true : retVal.didSucceed();
}
catch (RemoteException rx)
{
throw new RuntimeException("Could not delete value from list: " + rx);
}
}
else if (e instanceof JDeleteVectorValueObject)
{
try
{
retVal = removeFromOwnerGroup((Vector<Invid>) e.getValue());
if (retVal != null)
{
gc.handleReturnVal(retVal);
}
succeeded = (retVal == null) ? true : retVal.didSucceed();
}
catch (RemoteException rx)
{
throw new RuntimeException("Could not remove values from list: " + rx);
}
}
if (succeeded)
{
gc.somethingChanged();
}
return succeeded;
}
/**
* This private helper method attempts to edit the object whose
* Invid is provided. If successful, it will add the Invid for the
* owner group we are attached to to the Owner List Field.
*/
private ReturnVal addToOwnerGroup(Invid objectToAdd) throws RemoteException
{
ReturnVal retVal = null;
Session session = gc.getSession();
retVal = session.edit_db_object(objectToAdd);
if (!retVal.didSucceed())
{
return retVal;
}
db_object my_object = retVal.getObject();
db_field my_field = my_object.getField(SchemaConstants.OwnerListField);
retVal = my_field.addElement(parent.parent.getObjectInvid());
return retVal;
}
/**
* <p>This private helper method attempts to edit the objects whose
* Invid are provided in the Vector parameter. If successful, it
* will add the Invid for the owner group we are attached to to the
* Owner List Field for these objects.</p>
*
* <p>If a failure is encountered while we are looping over the
* vector of objects to add, we will return an error message and
* revert the objects we've already added.</p>
*/
private ReturnVal addToOwnerGroup(Vector<Invid> objectsToAdd) throws RemoteException
{
ReturnVal retVal = null;
Session session = gc.getSession();
boolean success = true;
int i;
// XXX we need to do manual loops here
for (i = 0; success && i < objectsToAdd.size(); i++)
{
Invid objectToAdd = objectsToAdd.get(i);
retVal = session.edit_db_object(objectToAdd);
if (!retVal.didSucceed())
{
success = false;
break;
}
db_object my_object = retVal.getObject();
db_field my_field = my_object.getField(SchemaConstants.OwnerListField);
// "Adding object {0} to owner group."
gc.setStatus(ts.l("addToOwnerGroup.adding_status", my_object.getLabel()));
retVal = my_field.addElement(parent.parent.getObjectInvid());
if (retVal != null && !retVal.didSucceed())
{
success = false;
}
}
if (!success)
{
// "Error encountered adding objects to owner group. Reverting."
gc.setStatus(ts.l("addToOwnerGroup.failure_status"), 0);
// we couldn't add all of these objects to the owner group.
// Go ahead and revert all the ones we successfully added.
for (int j = 0; j < i; j++)
{
Invid objectToAdd = objectsToAdd.get(j);
ReturnVal retVal2 = session.edit_db_object(objectToAdd);
if (!retVal2.didSucceed())
{
// weird! go ahead and try to undo the rest
continue;
}
db_object my_object = retVal2.getObject();
db_field my_field = my_object.getField(SchemaConstants.OwnerListField);
// we won't bother checking for success, if we fail here,
// we've got big problems.
my_field.deleteElement(parent.parent.getObjectInvid());
}
// clear the status display
gc.setStatus("");
// and return our original error message
return retVal;
}
return null; // success
}
/**
* <p>This private helper method attempts to edit the object whose
* Invid is provided. If successful, it will remove the Invid for
* the owner group we are attached to from the Owner List Field.</p>
*/
private ReturnVal removeFromOwnerGroup(Invid objectToRemove) throws RemoteException
{
ReturnVal retVal = null;
Session session = gc.getSession();
retVal = session.edit_db_object(objectToRemove);
if (!retVal.didSucceed())
{
return retVal;
}
db_object my_object = retVal.getObject();
db_field my_field = my_object.getField(SchemaConstants.OwnerListField);
retVal = my_field.deleteElement(parent.parent.getObjectInvid());
return retVal;
}
/**
* <p>This private helper method attempts to edit the objects whose
* Invid are provided in the Vector parameter. If successful, it
* will remove the Invid for the owner group we are attached to from
* the Owner List Field for these objects.</p>
*
* <p>If a failure is encountered while we are looping over the
* vector of objects to add, we will return an error message and
* revert the objects we've already removed.</p>
*/
private ReturnVal removeFromOwnerGroup(Vector<Invid> objectsToRemove) throws RemoteException
{
ReturnVal retVal = null;
Session session = gc.getSession();
int i;
boolean success = true;
// XXX we need to do manual loops here
for (i = 0; success && i < objectsToRemove.size(); i++)
{
Invid objectToRemove = objectsToRemove.get(i);
retVal = session.edit_db_object(objectToRemove);
if (!retVal.didSucceed())
{
success = false;
break;
}
db_object my_object = retVal.getObject();
db_field my_field = my_object.getField(SchemaConstants.OwnerListField);
// "Removing object {0} from owner group."
gc.setStatus(ts.l("removeFromOwnerGroup.removing_status", my_object.getLabel()));
retVal = my_field.deleteElement(parent.parent.getObjectInvid());
if (retVal != null && !retVal.didSucceed())
{
success = false;
}
}
if (!success)
{
// we couldn't remove all of these objects to the owner group.
// Go ahead and try to revert all the ones we successfully
// removed.
// "Error encountered removing objects from owner group. Reverting."
gc.setStatus(ts.l("removeFromOwnerGroup.failure_status"), 0);
for (int j = 0; j < i; j++)
{
Invid objectToRemove = objectsToRemove.get(j);
ReturnVal retVal2 = session.edit_db_object(objectToRemove);
if (!retVal2.didSucceed())
{
// weird! go ahead and try to undo the rest
continue;
}
db_object my_object = retVal2.getObject();
db_field my_field = my_object.getField(SchemaConstants.OwnerListField);
// we won't bother checking for success, if we fail here,
// we've got big problems.
my_field.addElement(parent.parent.getObjectInvid());
}
gc.setStatus("");
// and return our original error message
return retVal;
}
return null; // success
}
}