//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// J2ME-Lib source file
// Copyright (c) 2006 Elmar Sonnenschein / esoco GmbH
// Last Change: 19.10.2006 by eso
//
// J2ME-Lib is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 2.1 of the License, or (at your option)
// any later version.
//
// J2ME-Lib 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 Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with J2ME-Lib; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or use the contact
// information from the GNU website http://www.gnu.org
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
package de.esoco.j2me.ui;
import de.esoco.j2me.model.MutableHierarchyNode;
import de.esoco.j2me.model.HierarchyNode;
import de.esoco.j2me.util.Executable;
import de.esoco.j2me.util.ProcessingQueue;
import de.esoco.j2me.util.UserNotificationException;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.List;
/********************************************************************
* A package-internal class that handles the commands for a HierarchyView
* instance.
*
* @author eso
* @see de.esoco.j2me.ui.HierarchyView
*/
class HierarchyViewController implements CommandListener
{
//~ Instance fields --------------------------------------------------------
/** Commands that are always available */
public Command[] aGeneralCommands;
/** Commands available in the leaf (node) editor */
public Command[] aNodeEditorCommands;
/** Commands available in node child lists */
public Command[] aNodeListCommands;
/** Commands available in child lists of editable nodes */
public Command[] aNodeListEditCommands;
/** Commands available in the leaf (node) viewer */
public Command[] aNodeViewerCommands;
/** Commands available in the leaf viewer for editable nodes */
public Command[] aNodeViewerEditCommands;
/** command to navigate backwards */
Command aBackCommand;
/** Navigates forward in the node hierarchy */
NodeCommand aForwardCommand;
/**
* Paste will be enabled and disabled depending on the clipboard contents
*/
Command aPasteCommand;
/** The view this controller operates on */
HierarchyView rView;
/** The application specific controller for nodes */
private NodeController rNodeController;
//~ Constructors -----------------------------------------------------------
/***************************************
* Constructor that initializes the commands for a particular view.
*
* @param rView The view this controller operates on
* @param rNodeController The node controller to be used for node specific
* operations
* @param rGeneralCommands General commands that are always available
*/
protected HierarchyViewController(HierarchyView rView,
NodeController rNodeController,
Command[] rGeneralCommands)
{
this.rView = rView;
this.rNodeController = rNodeController;
initCommands(rGeneralCommands);
}
//~ Methods ----------------------------------------------------------------
/***************************************
* To process commands issued by user interaction with the current list.
*
* @see CommandListener#commandAction(Command, Displayable)
*/
public void commandAction(Command rCmd, Displayable d)
{
// this should normally not happen but if the list screen became active
// while processing the previous command simply ignore this command
if (ProcessingQueue.isProcessing())
{
return;
}
if (rCmd == List.SELECT_COMMAND)
{
ProcessingQueue.schedule(getForwardCommand(),
rView.getSelectedNode());
}
else if (rCmd instanceof ExecutableCommand)
{
ProcessingQueue.schedule((ExecutableCommand) rCmd);
}
else if (rCmd instanceof NodeCommand)
{
HierarchyNode rNode = rView.getSelectedNode();
if (rNode != null)
{
ProcessingQueue.schedule((NodeCommand) rCmd, rNode);
}
else
{
// NULL means "<New item>" was selected, therefore show hint
// that NodeCommands are not available there
MessageScreen.showAlert(rView.getString("JL_MtInfo"),
rView.getString("JL_MsNoCmd"),
AlertType.INFO);
}
}
}
/***************************************
* Creates a NodeCommand that will either go forward one level in the
* hierarchical data by displaying the children of the currently selected
* node or that will invoke the <code>queryNewNode()</code> method of the
* view if the <New Item> at the end of a list has been selected.
*
* @return The command to navigate forward in the node hierarchy
*/
protected NodeCommand getForwardCommand()
{
if (aForwardCommand == null)
{
aForwardCommand = new NodeCommand("", NodeCommand.SCREEN, 1, false,
rNodeController)
{
protected void processNode(HierarchyNode rNode)
{
if (rNode != null)
{
if (rNode.isGroup())
{
rView.setNextView(rView.newNodeDisplay(rNode,
true));
}
else
{
rView.setNextView(getLeafViewer(rNode));
}
}
else
{
// Node will be null if the <New Item> entry at the
// end of a list has been selected
rView.queryNewNode((MutableHierarchyNode) rView
.getCurrentNode());
}
}
};
}
return aForwardCommand;
}
/***************************************
* Creates and initializes the leaf (node) editor and returns it.
*
* @param rNode The node for which the leaf editor is requested
*
* @return The leaf editor displayable
*/
protected Displayable getLeafEditor(MutableHierarchyNode rNode)
{
Displayable aEditor = rNodeController.createLeafEditor(rNode);
aEditor.setCommandListener(this);
setCommands(aEditor, aNodeEditorCommands);
return aEditor;
}
/***************************************
* Creates and initializes the leaf (node) viewer and returns it.
*
* @param rNode The node for which the leaf viewer is requested
*
* @return The leaf viewer displayable
*/
protected Displayable getLeafViewer(HierarchyNode rNode)
{
Displayable aViewer = rNodeController.createLeafViewer(rNode);
aViewer.setCommandListener(this);
setCommands(aViewer, aGeneralCommands);
setCommands(aViewer, aNodeViewerCommands);
if (rNode instanceof MutableHierarchyNode)
{
setCommands(aViewer, aNodeViewerEditCommands);
}
return aViewer;
}
/***************************************
* Returns the node controller that is used for node specific operations.
*
* @return The node controller object
*/
protected NodeController getNodeController()
{
return rNodeController;
}
/***************************************
* Returns the Paste command.
*
* @return A command instance for the Paste command
*/
protected Command getPasteCommand()
{
return aPasteCommand;
}
/***************************************
* Internal method to initialize the Commands that can be executed on the
* displayed data. These have to be either ExecutableCommand or NodeCommand
* instances which can be directly executed.
*
* @param rGeneralCommands General commands that are always available
*/
protected void initCommands(Command[] rGeneralCommands)
{
initGlobalCommands();
Command aRenameCmd = new NodeCommand(rView.getString("Rename") + "...",
Command.ITEM, 10, true,
rNodeController)
{
protected void processNode(HierarchyNode rNode)
{
rView.queryRenameNode((MutableHierarchyNode) rNode);
}
};
Command aCopyCmd = new NodeCommand(rView.getString("Copy"),
Command.ITEM, 22, false,
rNodeController)
{
protected void processNode(HierarchyNode rNode)
{
rView.copyNode(rNode);
}
};
Command aNewCmd = new ExecutableCommand(rView.getString("New") + "...",
Command.ITEM, 12)
{
public void execute(Object rArg)
{
rView.queryNewNode((MutableHierarchyNode) rView
.getCurrentNode());
}
};
Command aDeleteCmd = new NodeCommand(rView.getString("Delete"),
Command.ITEM, 13, false,
rNodeController)
{
protected void processNode(final HierarchyNode rNode)
{
rNodeController.checkNodeDelete(rNode, new Executable()
{
public void execute(Object rArg)
throws UserNotificationException
{
rView.deleteNode(rNode);
}
});
}
};
Command aCutCmd = new NodeCommand(rView.getString("Cut"), Command.ITEM,
21, false, rNodeController)
{
protected void processNode(HierarchyNode rNode)
throws UserNotificationException
{
rView.cutNode(rNode);
}
};
Command aEditCmd = new NodeCommand(rView.getString("Edit") + "...",
Command.SCREEN, 1, true,
rNodeController)
{
protected void processNode(HierarchyNode rNode)
{
rView.setNextView(getLeafEditor((MutableHierarchyNode) rNode));
}
};
Command aOkCmd = new NodeCommand(rView.getString("Ok"), Command.OK, 1,
true, null)
{
protected void processNode(HierarchyNode rNode)
throws UserNotificationException
{
rView.endLeafEditor((MutableHierarchyNode) rNode);
}
};
Command aCancelCmd = new ExecutableCommand(rView.getString("Cancel"),
Command.CANCEL, 2)
{
public void execute(Object rArg)
{
rView.back();
}
};
aGeneralCommands = new Command[rGeneralCommands.length];
System.arraycopy(rGeneralCommands, 0, aGeneralCommands, 0,
aGeneralCommands.length);
aNodeListCommands = new Command[] { aCopyCmd };
aNodeListEditCommands = new Command[]
{
aRenameCmd, aNewCmd, aDeleteCmd, aCutCmd,
};
aNodeViewerCommands = new Command[] { aBackCommand, };
aNodeViewerEditCommands = new Command[] { aRenameCmd, aEditCmd, };
aNodeEditorCommands = new Command[] { aOkCmd, aCancelCmd, };
}
/***************************************
* Initializes the globally available command instances.
*/
protected void initGlobalCommands()
{
aBackCommand = new ExecutableCommand(rView.getString("Back"),
Command.BACK, 1)
{
public void execute(Object rArg)
{
rView.back();
}
};
aPasteCommand = new ExecutableCommand(rView.getString("Paste"),
Command.ITEM, 20)
{
public void execute(Object rArg)
throws UserNotificationException
{
rView.pasteNode();
}
};
}
/***************************************
* Internal method to join two arrays of Command objects.
*
* @param rCmds1 The first array to join or null
* @param rCmds2 The second array to join or null
*
* @return Either one of the argument arrays if the other is null, a new
* Command array containing the objects from both arrays, or null if
* both arrays are null
*/
protected Command[] joinCommands(Command[] rCmds1, Command[] rCmds2)
{
if (rCmds1 == null)
{
return rCmds2;
}
if (rCmds2 == null)
{
return rCmds1;
}
Command[] rCommands = new Command[rCmds1.length + rCmds2.length];
System.arraycopy(rCmds1, 0, rCommands, 0, rCmds1.length);
System.arraycopy(rCmds2, 0, rCommands, rCmds1.length, rCmds2.length);
return rCommands;
}
/***************************************
* To set a vector of Command instances on a Displayable object.
*
* @param rView The Displayable object to set the commands on
* @param rCommands The Command objects
*/
protected void setCommands(Displayable rView, Command[] rCommands)
{
if (rCommands != null)
{
for (int i = 0; i < rCommands.length; i++)
{
rView.addCommand(rCommands[i]);
}
}
}
/***************************************
* Initializes the commands for a node list in the HierarchyView.
*
* @param rDisplay The List instance to initialize
* @param rParent The parent node of the listed child nodes
* @param bEditable TRUE, if the displayed node is editable
* @param bClipboard TRUE, if clipboard data is available
* @param bWithBackCommand TRUE if the list shall have a "Back" command
*/
protected void setListCommands(Displayable rDisplay,
HierarchyNode rParent,
boolean bEditable,
boolean bClipboard,
boolean bWithBackCommand)
{
rDisplay.setCommandListener(this);
if (bWithBackCommand)
{
rDisplay.addCommand(aBackCommand);
}
setCommands(rDisplay, aGeneralCommands);
setCommands(rDisplay, aNodeListCommands);
if (bEditable)
{
setCommands(rDisplay,
joinCommands(aNodeListEditCommands,
rNodeController.getNodeListEditCommands(rParent)));
if (bClipboard)
{
rDisplay.addCommand(aPasteCommand);
}
}
}
}