import java.applet.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.lang.Math; import java.util.*; import javax.swing.*; import com.genlogic.*; ////////////////////////////////////////////////////////////////////////// // A diagramming editor: example of using Extended API. // // This demo uses Glg as a bean and may be used in a browser or // stand-alone. // // The CustomHandler class provides callbacks for interfacing with // application-specific functionality. ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// public class GlgDiagram extends GlgJBean { // Constants // Selection sensitivity in pixels static final int SELECTION_RESOLUTION = 5; static final int POINT_SELECTION_RESOLUTION = 2; // Skip 6 buttons (select and link): already there. static final int PALETTE_START_INDEX = 6; // Scale factor when displayed as icons. static final double ICON_SCALE = 10.; // Scale factor when placed in the drawing static final double IconScale = 1.; // Editing Modes static final int SELECT_OBJECT = 0; static final int ADD_NODE = 4; static final int ADD_LINK1 = 5; static final int ADD_LINK2 = 6; static final int DRAGGING = 7; // Object types static final int NO_OBJ = 0; static final int NODE = 1; static final int LINK = 2; boolean StandAlone; GlgObject Viewport; GlgObject MainArea; GlgObject SelectedObject = null; GlgObject SelectedMarker = null; boolean PointFeedbackShown = false; int SelectedObjectType; int NodeType; int LinkType; GlgObject DragLink; int EdgeType; GlgObject Point1; GlgObject StoredColor; GlgObject CutBuffer; int CutBufferType; int Mode; int NumLinkPoints; boolean MiddlePointAdded = false; String LastButton; GlgObject Handler; GlgDiagramData CurrentDiagram = new GlgDiagramData(); GlgDiagramData SavedDiagram; GlgNodeData StartNodeData; GlgObject IconArray; GlgObject LinkArray; GlgObject PaletteTemplate; GlgObject ButtonTemplate; int NumRows; int NumColumns; GlgPoint cursor_pos = new GlgPoint(); GlgPoint world_coord = new GlgPoint(); GlgPoint screen_coord = new GlgPoint(); GlgPoint start_point = new GlgPoint(); GlgPoint end_point = new GlgPoint(); GlgCube select_rect = new GlgCube(); GlgObject last_color; // Stores color during selection. ////////////////////////////////////////////////////////////////////////// // Utility class used to return several values. ////////////////////////////////////////////////////////////////////////// class ObjectInfo { GlgObject object; int type; // Constructors ObjectInfo() {} ObjectInfo( GlgObject object_p, int type_p ) { object = object_p; type = type_p; } } ////////////////////////////////////////////////////////////////////////// public GlgDiagram() { super(); SetDResource( "$config/GlgSwingUsage", 1. ); SelectedObjectType = NO_OBJ; CutBufferType = NO_OBJ; Mode = SELECT_OBJECT; LastButton = null; // The bean is a default listener for bean events except the trace // events (which are disabled by default), but add all listeners // explicitely as an example. AddListener( GlgObject.H_CB, this ); AddListener( GlgObject.V_CB, this ); AddListener( GlgObject.READY_CB, this ); AddListener( GlgObject.INPUT_CB, this ); AddListener( GlgObject.TRACE_CB, this ); } ////////////////////////////////////////////////////////////////////////// // For using as a stand-alone java demo ////////////////////////////////////////////////////////////////////////// public static void main( final String arg[] ) { SwingUtilities. invokeLater( new Runnable(){ public void run() { Main( arg ); } } ); } ////////////////////////////////////////////////////////////////////////// public static void Main( final String arg[] ) { class DemoQuit extends WindowAdapter { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } JFrame frame = new JFrame(); frame.setResizable( true ); frame.setSize( 900, 700 ); frame.setLocation( 20, 20 ); GlgDiagram diagram = new GlgDiagram(); diagram.StandAlone = true; // Loading the drawing triggers the H, V and Ready callbacks. // When used as an applet, the DrawingName parameter is set in HTML. // diagram.SetDrawingName( "diagram.g" ); frame.getContentPane().add( diagram ); frame.addWindowListener( new DemoQuit() ); frame.show(); } ////////////////////////////////////////////////////////////////////////// // Invoked after the drawing has been loaded but before it's set up. ////////////////////////////////////////////////////////////////////////// public void HCallback( GlgObject viewport ) { // Fill out the palette and change the dialog type before the // hierarchy setup Viewport = GetViewport(); MainArea = Viewport.GetResourceObject( "MainArea" ); if( MainArea == null ) { PrintToJavaConsole( "Can't find MainArea viewport.\n" ); return; } FillObjectPalette( "PaletteTemplate", "Icon", "Node", "ObjectPalette", "IconButton", PALETTE_START_INDEX, true ); } ////////////////////////////////////////////////////////////////////////// // Invoked after the drawing has been loaded and set up, but before it's // displayed. ////////////////////////////////////////////////////////////////////////// public void VCallback( GlgObject viewport ) { // Do some initialization here before displaying the drawing. SetPrompt( "" ); // Create a color object to store original node color during node // selection. StoredColor = Viewport.GetResourceObject( "FillColor" ).CopyObject(); // Make exit button visible for stand-alone. if( StandAlone ) Viewport.SetDResource( "Exit/Visibility", 1. ); else Viewport.SetDResource( "Exit/Visibility", 0. ); // Set grid color (configuration parameter) to grey. Viewport.SetGResource( "$config/GlgGridPolygon/EdgeColor", 0.632441, 0.632441, 0.632441 ); // Change the shell type of the Properties dialog to make it a separate // top-level window, and make it invisible on start-up. // You can replace the dialog with any custom Java-based dialog. Viewport.SetDResource( "Dialog/ShellType", (double) GlgObject.DIALOG_SHELL ); Viewport.SetDResource( "Dialog/Visibility", 0. ); // Set the Properties dialog's title. Viewport.SetSResource( "Dialog/ScreenName", "Object Properties" ); // Create a separate group to hold objects. GlgObject group = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); group.SetSResource( "Name", "ObjectGroup" ); MainArea.AddObjectToBottom( group ); // Read palettes and extract icon and link objects. IconArray = GetPaletteIcons( "IconButton", "Icon", "Node" ); LinkArray = GetPaletteIcons( "IconButton", "Icon", "Link" ); Mode = SELECT_OBJECT; SetRadioBox( "IconButton0" ); // Highlight Select button CurrentDiagram = new GlgDiagramData(); // Position nodes with multiple attachment points that don't use // reference object. SetupObjectPalette( "IconButton", PALETTE_START_INDEX ); } ////////////////////////////////////////////////////////////////////////// // Invoked after the drawing has been drawn for the first time. ////////////////////////////////////////////////////////////////////////// public void ReadyCallback( GlgObject viewport ) { // May be used to start data updates, not used here. } //////////////////////////////////////////////////////////////////////// // The trace callback receives all low-level events and is used for // handling mouse interaction, such as creating and dragging nodes // and links. // // The TraceCB requires handling native events as the price of the extended // functionality it provides. However, the native code is limited to just // a few code lines to extract the platform-specific event information. //////////////////////////////////////////////////////////////////////// public void TraceCallback( GlgObject viewport, GlgTraceData trace_info ) { int event_type, x, y; // Use the MainArea's events only. if( !IsReady() || trace_info.viewport != MainArea ) return; event_type = trace_info.event.getID(); switch( event_type ) { case MouseEvent.MOUSE_PRESSED: case MouseEvent.MOUSE_MOVED: case MouseEvent.MOUSE_DRAGGED: case MouseEvent.MOUSE_RELEASED: if( GetButton( trace_info.event ) != 1 ) return; // Use the left button clicks only. cursor_pos.x = (double) ((MouseEvent)trace_info.event).getX(); cursor_pos.y = (double) ((MouseEvent)trace_info.event).getY(); cursor_pos.z = 0.; break; default: return; } if( MainArea.GetDResource( "ZoomToMode" ).intValue() != 0 ) return; // Don't handle mouse selection in ZoomTo mode. switch( Mode ) { default: Bell(); ResetModes(); Update(); return; case ADD_NODE: AddNodeHandler( event_type, cursor_pos ); return; case ADD_LINK1: case ADD_LINK2: AddLinkHandler( event_type, cursor_pos, viewport, trace_info ); return; case DRAGGING: DraggingHandler( event_type, cursor_pos ); return; case SELECT_OBJECT: ObjectHandler( event_type, cursor_pos, viewport, trace_info ); return; } } //////////////////////////////////////////////////////////////////////// public void AddNodeHandler( int event_type, GlgPoint cursor_pos ) { if( event_type != MouseEvent.MOUSE_PRESSED ) return; // Use screen coords of the cursor to add graphics GlgObject new_node = AddNodeAt( NodeType, null, cursor_pos, GlgObject.SCREEN_COORD ); CustomHandler.AddObjectCB( this, new_node, GetData( new_node ), true ); SelectGlgObject( new_node, NODE ); Update(); } //////////////////////////////////////////////////////////////////////// public void AddLinkHandler( int event_type, GlgPoint cursor_pos, GlgObject viewport, GlgTraceData trace_info ) { GlgObject point, sel_object = null; int num_selected; if( event_type != MouseEvent.MOUSE_PRESSED && event_type != MouseEvent.MOUSE_MOVED ) return; // Drag the link if( event_type == MouseEvent.MOUSE_MOVED && Mode == ADD_LINK2 ) { if( DragLink == null ) // Create a link to drag if wasn't yet created { DragLink = AddLink( LinkType, null ); NumLinkPoints = 1; // First point ConstrainLinkPoint( DragLink, Point1, false ); AttachFramePoints( DragLink ); SetEdgeDirection( DragLink, start_point, cursor_pos ); } SetLastPoint( DragLink, cursor_pos, false ); if( !MiddlePointAdded ) SetArcMiddlePoint( DragLink ); Update(); } GlgObject selection = GetObjectsAtCursor( /** top viewport **/ viewport, /** event viewport **/ trace_info.viewport, cursor_pos ); if( selection != null && ( num_selected = selection.GetSize() ) != 0 ) { // Some objects were selected, process the selection to find the // point to connect to. point = null; for( int i=0; i < num_selected; ++i ) { sel_object = (GlgObject) selection.GetElement( i ); // Find if the object itself is a link or a node, // of if it's a part of a node. If it's a part of a node, // get the node object ID. // ObjectInfo selection_info = GetSelectedObject( sel_object ); sel_object = selection_info.object; int selection_type = selection_info.type; if( selection_type == NODE ) { int type = sel_object.GetDResource( "Type" ).intValue(); if( type == GlgObject.REFERENCE ) { // Use ref's point as a connector. point = sel_object.GetResourceObject( "Point" ); } else { // Node has multiple connectors. Get connection point point = GetSelectedPoint( sel_object, cursor_pos, "CP" ); } if( point != null ) break; // Found a point to connect to: stop search and use it. } // No point to connect to: continue searching all selected objects. } if( point != null ) // Use point if found. { switch( event_type ) { // Show feedback at the connector's position. case MouseEvent.MOUSE_MOVED: if( SelectedMarker == null ) { // First time: create, set marker type and color. SelectedMarker = new GlgMarker(); SelectedMarker.SetDResource( "MarkerType", (double) ( GlgObject.CIRCLE | GlgObject.FILLED_CIRCLE ) ); SelectedMarker.SetGResource( "FillColor", 0., 0., 1. ); } // Get screen coords of the connector point, not the cursor // position: may be a few pixels off. GlgPoint screen_point = point.GetGResource( "XfValue" ); MainArea.ScreenToWorld( true, screen_point, world_coord ); // Position the feedback marker over the connector SelectedMarker.SetGResource( "Point", world_coord ); if( !PointFeedbackShown ) { MainArea.AddObjectToBottom( SelectedMarker ); PointFeedbackShown = true; } Update(); break; case MouseEvent.MOUSE_PRESSED: // Connect switch( Mode ) { case ADD_LINK1: Point1 = point; StartNodeData = (GlgNodeData) GetData( sel_object ); Mode = ADD_LINK2; SetPrompt( "Select the second node." ); DragLink = null; // Store cursor position for setting direction based on the // first mouse move. start_point.CopyFrom( cursor_pos ); Update(); break; case ADD_LINK2: if( point == Point1 || DragLink == null /* No mouse move */ ) { SetError( "The two nodes are the same, " + "chose a different second node." ); break; } ++NumLinkPoints; // Last point ConstrainLinkPoint( DragLink, point, true ); AttachFramePoints( DragLink ); if( !MiddlePointAdded ) SetArcMiddlePoint( DragLink ); GlgObject arrow_type = DragLink.GetResourceObject( "ArrowType" ); if( arrow_type != null ) arrow_type.SetDResource( null, (double) GlgObject.MIDDLE_FILL_ARROW ); // Wire up the start and end nodes GlgLinkData link_data = (GlgLinkData) GetData( DragLink ); link_data.setStartNode( StartNodeData ); link_data.setEndNode( (GlgNodeData) GetData( sel_object ) ); // Store color link_data.link_color = new GlgDiagramPoint( DragLink.GetGResource( "EdgeColor" )); // Store points StorePointData( link_data, DragLink ); // Add link data to the link list Vector link_list = CurrentDiagram.getLinkList(); link_list.addElement( link_data ); // After storing color: changes color to select SelectGlgObject( DragLink, LINK ); CustomHandler.AddObjectCB( this, DragLink, GetData( DragLink ), false ); // Start over to create more links Mode = ADD_LINK1; SetPrompt( "Select the first node." ); DragLink = null; MiddlePointAdded = false; Update(); break; } } /* switch( event_type ) */ return; // We are done with the point. } /* if( point != null ) */ } // No point or no selection: handle point feedback and link middle // points. if( PointFeedbackShown ) { MainArea.DeleteObject( SelectedMarker ); PointFeedbackShown = false; Update(); } if( event_type == MouseEvent.MOUSE_PRESSED ) // Add midlle link point { if( Mode == ADD_LINK1 ) return; // No first point yet ++NumLinkPoints; // Add middle link point. AddLinkPoints( DragLink, 1 ); MiddlePointAdded = true; SetLastPoint( DragLink, cursor_pos, EdgeType == GlgObject.ARC ); AttachFramePoints( DragLink ); if( EdgeType == GlgObject.ARC ) { // Offset the last point after setting the middle one. cursor_pos.x += 10; cursor_pos.y += 10; SetLastPoint( DragLink, cursor_pos, false ); } Update(); } } //////////////////////////////////////////////////////////////////////// // Stores point coordinates in the link data structure as a vector. //////////////////////////////////////////////////////////////////////// void StorePointData( GlgLinkData link_data, GlgObject link ) { ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; int num_points = point_container.GetSize(); // Always create a new vector and discard the old one for simplicity // (not much to gain any way). link_data.point_array = new Vector( num_points ); for( int i=0; i 2 ) { ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; // Skip the first and last point: constrained to nodes. // Set only the middle points. for( int i=1; i < num_points - 1; ++i ) { GlgObject point = (GlgObject) point_container.GetElement( i ); GlgDiagramPoint xyz = (GlgDiagramPoint) link_data.point_array.elementAt( i ); point.SetGResource( null, xyz ); } } } //////////////////////////////////////////////////////////////////////// // Handles object selection and dragging start. //////////////////////////////////////////////////////////////////////// public void ObjectHandler( int event_type, GlgPoint cursor_pos, GlgObject viewport, GlgTraceData trace_info ) { int num_selected; if( event_type != MouseEvent.MOUSE_PRESSED ) return; GlgObject selection = GetObjectsAtCursor( /** top viewport **/ viewport, /** event viewport **/ trace_info.viewport, cursor_pos ); if( selection != null && ( num_selected = selection.GetSize() ) != 0 ) { // Some objects were selected, process the selection. for( int i=0; i < num_selected; ++i ) { GlgObject sel_object = (GlgObject) selection.GetElement( i ); // Find if the object itself is a link or a node, // of if it's a part of a node. If it's a part of a node, // get the node object ID. // ObjectInfo selection_info = GetSelectedObject( sel_object ); sel_object = selection_info.object; int selection_type = selection_info.type; if( selection_type != 0 ) { SelectGlgObject( sel_object, selection_type ); Update(); CustomHandler.SelectObjectCB( this, sel_object, GetData( sel_object ), selection_type == NODE ); // Prepare for dragging Mode = DRAGGING; // Store the start point start_point.CopyFrom( cursor_pos ); return; } } } // No link or node was selected. SelectGlgObject( null, 0 ); // Unselect. Update(); } //////////////////////////////////////////////////////////////////////// public void DraggingHandler( int event_type, GlgPoint cursor_pos ) { switch( event_type ) { case MouseEvent.MOUSE_RELEASED: ResetModes(); return; case MouseEvent.MOUSE_DRAGGED: if( SelectedObjectType == NODE ) SelectedObject.MoveObject( GlgObject.SCREEN_COORD, start_point, cursor_pos ); else MoveLink( SelectedObject, start_point, cursor_pos ); Update(); Object data = GetData( SelectedObject ); if( data != null ) if( data instanceof GlgNodeData ) { // Update the X and Y in the product's data struct. UpdateNodePosition( SelectedObject, (GlgNodeData) data ); // Don't need to update the attached links' points, since // the stored positions of the first and last points are // not used: they are constrained to nodes and positioned // by them. } else // LinkData { GlgLinkData link_data = (GlgLinkData) data; UpdateNodePosition( link_data.getStartNode().graphics, null ); UpdateNodePosition( link_data.getEndNode().graphics, null ); // Update stored point values StorePointData( link_data, SelectedObject ); } // Update the start point for the next move start_point.CopyFrom( cursor_pos ); break; } } //////////////////////////////////////////////////////////////////////// // If the link is attached to nodes that use reference objects, moving the // link moves the nodes, with no extra actions required. However, the link // can be connected to a node with multiple attachment points which doesn't // use reference object. Moving such a link would move just the attachment // points, but not the nodes. To avoid this, unsconstrain the end points // of the link not to spoil the attachment points' geometry, move the link, // move the nodes, then constrain the link points back. //////////////////////////////////////////////////////////////////////// void MoveLink( GlgObject link, GlgPoint start_point, GlgPoint end_point ) { GlgLinkData link_data = (GlgLinkData) GetData( link ); GlgObject start_node = link_data.start_node.graphics; GlgObject end_node = link_data.end_node.graphics; int type1 = start_node.GetDResource( "Type" ).intValue(); int type2 = end_node.GetDResource( "Type" ).intValue(); if( type1 == GlgObject.REFERENCE && type2 == GlgObject.REFERENCE ) { // Nodes are reference objects, moving the link moves nodes. link.MoveObject( GlgObject.SCREEN_COORD, start_point, end_point ); } else // Nodes with multiple attachment points. { // Unconstrain link points GlgObject point1 = UnConstrainLinkPoint( link, false ); GlgObject point2 = UnConstrainLinkPoint( link, true ); DetachFramePoints( link ); // Move the link link.MoveObject( GlgObject.SCREEN_COORD, start_point, end_point ); // Move nodes start_node.MoveObject( GlgObject.SCREEN_COORD, start_point, end_point ); end_node.MoveObject( GlgObject.SCREEN_COORD, start_point, end_point ); // Re-attach the link ConstrainLinkPoint( link, point1, false ); ConstrainLinkPoint( link, point2, true ); AttachFramePoints( link ); } } //////////////////////////////////////////////////////////////////////// void UpdateNodePosition( GlgObject node, GlgNodeData node_data ) { if( node_data == null ) node_data = (GlgNodeData) GetData( node ); GetPosition( node, world_coord ); node_data.position.x = world_coord.x; node_data.position.y = world_coord.y; } //////////////////////////////////////////////////////////////////////// public GlgObject GetObjectsAtCursor( GlgObject viewport, GlgObject event_vp, GlgPoint cursor_pos ) { // Select all objects in the vicinity of the +-SELECTION_RESOLUTION // pixels from the actual mouse click position. select_rect.p1.x = cursor_pos.x - SELECTION_RESOLUTION; select_rect.p1.y = cursor_pos.y - SELECTION_RESOLUTION; select_rect.p2.x = cursor_pos.x + SELECTION_RESOLUTION; select_rect.p2.y = cursor_pos.y + SELECTION_RESOLUTION; return GlgObject.CreateSelection( /** top viewport **/ viewport, select_rect, /** event viewport **/ event_vp ); } //////////////////////////////////////////////////////////////////////// public void InputCallback( GlgObject viewport, GlgObject message_obj ) { if( !IsReady() ) return; String format = message_obj.GetSResource( "Format" ); String origin = message_obj.GetSResource( "Origin" ); String full_origin = message_obj.GetSResource( "FullOrigin" ); String action = message_obj.GetSResource( "Action" ); String subaction = message_obj.GetSResource( "SubAction" ); // Handle Dialog window closing. if( format.equals( "Window" ) && action.equals( "DeleteWindow" ) && origin.equals( "Dialog" ) ) { // Close the dialog window. Viewport.SetDResource( "Dialog/Visibility", 0. ); Update(); } else if( format.equals( "Button" ) ) { if( !action.equals( "Activate" ) && !action.equals( "ValueChanged" ) ) return; ResetModes(); if( origin.equals( "Save" ) ) Save( CurrentDiagram ); else if( origin.equals( "Insert" ) ) Load(); else if( origin.equals( "Print" ) ) Print(); else if( origin.equals( "Cut" ) ) Cut(); else if( origin.equals( "Paste" ) ) Paste(); else if( origin.equals( "Exit" ) ) System.exit( 0 ); else if( origin.equals( "ZoomIn" ) ) { ResetModes(); MainArea.SetZoom( null, 'i', 0. ); } else if( origin.equals( "ZoomOut" ) ) { ResetModes(); MainArea.SetZoom( null, 'o', 0. ); } else if( origin.equals( "ZoomTo" ) ) { ResetModes(); MainArea.SetZoom( null, 't', 0. ); } else if( origin.equals( "ZoomReset" ) ) { ResetModes(); MainArea.SetZoom( null, 'n', 0. ); } else if( origin.startsWith( "IconButton" ) ) { GlgObject button = viewport.GetResourceObject( full_origin ); GlgObject icon = button.GetResourceObject( "Icon" ); if( icon == null ) { SetError( "Can't find icon." ); return; } String icon_type = icon.GetSResource( "IconType" ); if( icon_type == null ) { SetError( "Can't find icon type." ); return; } if( icon_type.equals( "Select" ) ) ResetModes(); else if( icon_type.equals( "Link" ) ) AddLink( full_origin, icon ); else if( icon_type.equals( "Node" ) ) AddNode( full_origin, icon ); } else if( origin.equals( "DialogApply" ) ) ApplyData(); else if( origin.equals( "DialogClose" ) ) { if( ApplyData() ) // Close the dialog if successfully applied. Viewport.SetDResource( "Dialog/Visibility", 0. ); } else if( origin.equals( "DialogCancel" ) ) { // Close the dialog without applying the data. Viewport.SetDResource( "Dialog/Visibility", 0. ); } else if( origin.equals( "Properties" ) ) { // You can use a custom Java-based dialog to display properties // of the selected mode or link. FillData(); Viewport.SetDResource( "Dialog/Visibility", 1. ); } Update(); } } //////////////////////////////////////////////////////////////////////// void SelectGlgObject( GlgObject object, int selected_type ) { String name; if( object == SelectedObject ) return; // No change if( last_color != null ) // Restore the color of previously selected node { last_color.SetResourceFromObject( null, StoredColor ); last_color = null; } SelectedObject = object; SelectedObjectType = selected_type; // Change color to highlight selected node. if( object != null ) { if( selected_type == NODE ) { last_color = object.GetResourceObject( "Template/SelectColor" ); if( last_color == null ) // Not a reference object last_color = object.GetResourceObject( "SelectColor" ); } else // Link last_color = object.GetResourceObject( "EdgeColor" ); // Store original color StoredColor.SetResourceFromObject( null, last_color ); // Set color to red to highlight selection. last_color.SetGResource( null, 1., 0., 0. ); name = GetObjectLabel( SelectedObject ); } else name = "NONE"; // Display selected object name at the bottom. Viewport.SetSResource( "SelectedObject", name ); FillData(); } //////////////////////////////////////////////////////////////////////// void AddNode( String button_name, GlgObject node ) { GlgObject palette_button = Viewport.GetResourceObject( button_name ); Mode = ADD_NODE; SetPrompt( "Position the node." ); SetRadioBox( button_name ); // Store Node type NodeType = node.GetDResource( "Index" ).intValue(); } //////////////////////////////////////////////////////////////////////// void AddLink( String button_name, GlgObject link ) { Mode = ADD_LINK1; SetPrompt( "Select the first node." ); SetRadioBox( button_name ); // Store Link type LinkType = link.GetDResource( "Index" ).intValue(); ObjectInfo link_info = GetCPContainer( link ); EdgeType = link_info.type; } //////////////////////////////////////////////////////////////////////// void Cut() { if( NoSelection() ) return; // Disallow deleting a node without deleting the link first. if( SelectedObjectType == NODE && NodeConnected( SelectedObject ) ) { SetError( "Remove links connected to the node before removing the node!" ); return; } GlgObject group = MainArea.GetResourceObject( "ObjectGroup" ); if( group.ContainsObject( SelectedObject ) ) { // Store the node or link in the cut buffer. CutBuffer = SelectedObject; CutBufferType = SelectedObjectType; // Delete the node group.DeleteObject( SelectedObject ); // Delete the data Object data = GetData( SelectedObject ); Vector list = null; CustomHandler.CutObjectCB( this, SelectedObject, data, SelectedObjectType == NODE ); if( SelectedObjectType == NODE ) list = (Vector) CurrentDiagram.getNodeList(); else // Link list = (Vector) CurrentDiagram.getLinkList(); if( !list.removeElement( data ) ) System.out.println( "Deleting data failed!" ); SelectGlgObject( null, 0 ); } else SetError( "Cut failed." ); } //////////////////////////////////////////////////////////////////////// void Paste() { if( CutBuffer == null ) { SetError( "Empty cut buffer, cut some object first." ); return; } GlgObject group = MainArea.GetResourceObject( "ObjectGroup" ); Object data = GetData( CutBuffer ); Vector list = null; CustomHandler.PasteObjectCB( this, CutBuffer, data, CutBufferType == NODE ); if( CutBufferType == NODE ) { group.AddObjectToBottom( CutBuffer ); // In front list = CurrentDiagram.getNodeList(); } else // LINK { group.AddObjectToTop( CutBuffer ); // Behind list = CurrentDiagram.getLinkList(); } list.addElement( data ); SelectGlgObject( CutBuffer, CutBufferType ); // Allow pasting just once to avoid handling the data copy CutBuffer = null; } //////////////////////////////////////////////////////////////////////// void Save( GlgDiagramData diagram ) { // Print all nodes and edges as a test Vector node_list = diagram.getNodeList(); Vector link_list = diagram.getLinkList(); int i; for( i=0; i 2 ) AddLinkPoints( new_link, num_points - 2 ); AddCustomData( new_link, link_data ); return new_link; } ///////////////////////////////////////////////////////////////////////// // Connects the first or last point of the link. ///////////////////////////////////////////////////////////////////////// void ConstrainLinkPoint( GlgObject link, GlgObject point, boolean last_point ) { ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; int edge_type = link_info.type; GlgObject link_point = (GlgObject) point_container.GetElement( ( last_point ? point_container.GetSize() - 1 : 0 ) ); GlgObject suspend_info = link.SuspendObject(); link_point.ConstrainObject( point ); link.ReleaseObject( suspend_info ); // Store the point name for save/load String point_name = point.GetSResource( "Name" ); if( point_name == null || point_name.length() == 0 ) point_name = "Point"; GlgLinkData link_data = (GlgLinkData) GetData( link ); if( last_point ) link_data.end_point_name = point_name; else link_data.start_point_name = point_name; } ///////////////////////////////////////////////////////////////////////// // Positions the arc's middle point if it's not explicitly defined. ///////////////////////////////////////////////////////////////////////// void SetArcMiddlePoint( GlgObject link ) { double x1, y1, x2, y2, z; ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; int edge_type = link_info.type; if( edge_type != GlgObject.ARC ) return; // Offset the arc's middle point if wasn't set. GlgObject start_point = (GlgObject) point_container.GetElement( 0 ); GlgObject middle_point = (GlgObject) point_container.GetElement( 1 ); GlgObject end_point = (GlgObject) point_container.GetElement( 2 ); GlgPoint pt1 = start_point.GetGResource( null ); GlgPoint pt2 = end_point.GetGResource( null ); // Offset the middle point. middle_point.SetGResource( null, ( pt1.x + pt2.x ) / 2. + ( pt1.y - pt2.y != 0. ? 50. : 0. ), ( pt1.y + pt2.y ) / 2. + ( pt1.y - pt2.y != 0. ? 0. : 50. ), ( pt1.z + pt2.z ) / 2. ); } ///////////////////////////////////////////////////////////////////////// // Handles links with labels: constrains frame's points to the link's // points. ///////////////////////////////////////////////////////////////////////// void AttachFramePoints( GlgObject link ) { GlgObject frame, link_point_container, frame_point_container, link_start_point, link_end_point, frame_start_point, frame_end_point, suspend_info; frame = link.GetResourceObject( "Frame" ); if( frame == null ) // Link without label and frame return; ObjectInfo link_info = GetCPContainer( link ); link_point_container = link_info.object; // Always use the first segment of the link to attach the frame. link_start_point = (GlgObject) link_point_container.GetElement( 0 ); link_end_point = (GlgObject) link_point_container.GetElement( 1 ); frame_point_container = frame.GetResourceObject( "CPArray" ); int size = frame_point_container.GetSize(); frame_start_point =(GlgObject) frame_point_container.GetElement( 0 ); frame_end_point = (GlgObject) frame_point_container.GetElement( size - 1 ); suspend_info = link.SuspendObject(); frame_start_point.ConstrainObject( link_start_point ); frame_end_point.ConstrainObject( link_end_point ); link.ReleaseObject( suspend_info ); } ///////////////////////////////////////////////////////////////////////// // Disconnects the first or last point of the link. Returns the object // the link is connected to. ///////////////////////////////////////////////////////////////////////// GlgObject UnConstrainLinkPoint( GlgObject link, boolean last_point ) { ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; int edge_type = link_info.type; GlgObject link_point = (GlgObject) point_container.GetElement( ( last_point ? point_container.GetSize() - 1 : 0 ) ); GlgObject attachment_point = link_point.GetResourceObject( "Data" ); GlgObject suspend_info = link.SuspendObject(); link_point.UnconstrainObject(); link.ReleaseObject( suspend_info ); return attachment_point; } ///////////////////////////////////////////////////////////////////////// // Detaches the first and last points of the frame. ///////////////////////////////////////////////////////////////////////// void DetachFramePoints( GlgObject link ) { GlgObject frame, frame_point_container, frame_start_point, frame_end_point, suspend_info; frame = link.GetResourceObject( "Frame" ); if( frame == null ) // Link without label and frame return; frame_point_container = frame.GetResourceObject( "CPArray" ); int size = frame_point_container.GetSize(); frame_start_point = (GlgObject) frame_point_container.GetElement( 0 ); frame_end_point = (GlgObject) frame_point_container.GetElement( size - 1 ); suspend_info = link.SuspendObject(); frame_start_point.UnconstrainObject(); frame_end_point.UnconstrainObject(); link.ReleaseObject( suspend_info ); } ///////////////////////////////////////////////////////////////////////// // Set last point of the link (dragging). ///////////////////////////////////////////////////////////////////////// void SetLastPoint( GlgObject link, GlgPoint cursor_pos, boolean arc_middle_point ) { GlgObject point; ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; int edge_type = link_info.type; if( arc_middle_point ) // Setting the middle point of an arc. point = (GlgObject) point_container.GetElement( 1 ); else // Setting the last point. point = (GlgObject) point_container.GetElement( point_container.GetSize() - 1 ); MainArea.ScreenToWorld( true, cursor_pos, world_coord ); point.SetGResource( null, world_coord ); } ///////////////////////////////////////////////////////////////////////// void AddLinkPoints( GlgObject link, int num_points ) { ObjectInfo link_info = GetCPContainer( link ); if( link_info.type == GlgObject.ARC ) return; // Arc connectors have fixed number of points: don't add. GlgObject point_container = link_info.object; int edge_type = link_info.type; GlgObject point = (GlgObject) point_container.GetElement( 0 ); GlgObject suspend_info = link.SuspendObject(); for( int i=0; i Math.abs( start_pos.y - end_pos.y ) ) direction = GlgObject.HORIZONTAL; else direction = GlgObject.VERTICAL; link.SetDResource( "EdgeDirection", (double) direction ); GlgLinkData link_data = (GlgLinkData) GetData( link ); link_data.link_direction = direction; } //////////////////////////////////////////////////////////////////////// GlgObject AddLink( int link_type, GlgLinkData link_data ) { GlgObject link; if( link_data == null ) // Creating a new link interactively { link_data = new GlgLinkData(); link_data.link_type = link_type; link = CreateLink( link_data ); // Store color link_data.link_color = new GlgDiagramPoint( link.GetGResource( "EdgeColor" ) ); // Don't add link data to the link list or store points: // will be done when finished creating the link. } else // Creating a link from data on load. { link = CreateLink( link_data ); // Set color link.SetGResource( "EdgeColor", link_data.link_color ); // Enable arrow type if defined GlgObject arrow_type = link.GetResourceObject( "ArrowType" ); if( arrow_type != null ) arrow_type.SetDResource( null, (double) GlgObject.MIDDLE_FILL_ARROW ); // Restore connector direction if recta-linear GlgObject direction = link.GetResourceObject( "EdgeDirection" ); if( direction != null ) direction.SetDResource( null, (double) link_data.link_direction ); // Constrain end points to start and end nodes GlgObject node1 = (GlgObject) link_data.getStartNode().graphics; GlgObject node2 = (GlgObject) link_data.getEndNode().graphics; GlgObject point1 = node1.GetResourceObject( link_data.start_point_name ); GlgObject point2 = node2.GetResourceObject( link_data.end_point_name ); ConstrainLinkPoint( link, point1, false ); // First point ConstrainLinkPoint( link, point2, true ); // Last point AttachFramePoints( link ); RestorePointData( link_data, link ); } // Display the label if it's a link with a label. if( link.GetResourceObject( "Label" ) != null ) link.SetSResource( "Label/String", link_data.object_label ); link_data.graphics = link; // Pointer from data struct to graphics // Add to the top of the draw list to be behind other objects. GlgObject group = MainArea.GetResourceObject( "ObjectGroup" ); group.AddObjectToTop( link ); return link; } //////////////////////////////////////////////////////////////////////// // Set the object size and position. //////////////////////////////////////////////////////////////////////// void PlaceObject( GlgObject node, GlgPoint pos, int coord_type, GlgPoint world_coord ) { int type; // World coordinates of the node are returned to be stored in the node's // data structure. if( coord_type == GlgObject.SCREEN_COORD ) MainArea.ScreenToWorld( true, pos, world_coord ); else world_coord.CopyFrom( pos ); type = node.GetDResource( "Type" ).intValue(); if( type == GlgObject.REFERENCE ) { // Reference: can use its point to position it. node.SetGResource( "Point", world_coord ); if( IconScale != 1. ) // Change node size if required. // Scale object around the origin, which is now located at pos. node.ScaleObject( coord_type, pos, IconScale, IconScale, 1. ); } else { // Arbitrary object: move its box's center to the cursor position. node.PositionObject( coord_type, GlgObject.HCENTER | GlgObject.VCENTER, pos.x, pos.y, pos.z ); if( IconScale != 1. ) // Change node size if required. // Scale object around the center of it's bounding box. node.ScaleObject( coord_type, null, IconScale, IconScale, 1. ); } } //////////////////////////////////////////////////////////////////////// // Get the link's control points container based on the link type. //////////////////////////////////////////////////////////////////////// ObjectInfo GetCPContainer( GlgObject link ) { ObjectInfo rval; int link_type, edge_type; link_type = link.GetDResource( "Type" ).intValue(); switch( link_type ) { case GlgObject.POLYGON: rval = new ObjectInfo(); rval.object = link; rval.type = 0; break; case GlgObject.GROUP: // Group containing a polygon with a label return GetCPContainer( link.GetResourceObject( "Link" ) ); case GlgObject.CONNECTOR: rval = new ObjectInfo(); rval.object = link; rval.type = link.GetDResource( "EdgeType" ).intValue(); break; default: SetError( "Invalid link type." ); return null; } return rval; } //////////////////////////////////////////////////////////////////////// // Determines what node or link the object belongs to and returns it. // Also returns type of the object: NODE or LINK. //////////////////////////////////////////////////////////////////////// ObjectInfo GetSelectedObject( GlgObject object ) { while( object != null ) { // Name prefix is used to identify icon type. A custom property // (named IconType, for example) may be attached to icons as an // alternative. GlgObject type_obj = object.GetResourceObject( "IconType" ); if( type_obj != null ) { String type_string = type_obj.GetSResource( null ); if( type_string.equals( "Link" ) ) return new ObjectInfo( object, LINK ); else if( type_string.equals( "Node" ) ) return new ObjectInfo( object, NODE ); } object = object.GetParent(); } // No node/link parent found - no selection. return new ObjectInfo( null, NO_OBJ ); } //////////////////////////////////////////////////////////////////////// // Returns the first point at the cursor whose name starts with the // name_prefix. //////////////////////////////////////////////////////////////////////// GlgObject GetSelectedPoint( GlgObject sel_object, GlgPoint cursor_pos, String name_prefix ) { int size; GlgObject pt_array = sel_object.CreatePointArray( 0 ); if( pt_array == null || ( size = pt_array.GetSize() ) == 0 ) return null; pt_array.SetStart(); for( int i=0; i staring // with the start_index. The palette buttons are created by copying an empty // template button. // Parameters: // template_name Name of the template containing palette icons. // icon_name Icon's name prefix in the template. // type Type of the icons to look for. // palette_name Name of the palette object to add buttons to. // button_name Name of the buttons in the palette object. // start_index Number of buttons to skip (select and link // buttons already in the palette). // finish Is set to true on the last invocation of the // method to do clean up. ////////////////////////////////////////////////////////////////////////// int FillObjectPalette( String template_name, String icon_name, String type, String palette_name, String button_name, int start_index, boolean finish ) { int i; GlgObject palette = Viewport.GetResourceObject( palette_name ); if( PaletteTemplate == null ) { PaletteTemplate = Viewport.GetResourceObject( template_name ); if( PaletteTemplate == null ) { SetError( "Can't find palette template!" ); return 0; } Viewport.DeleteObject( PaletteTemplate ); } // Find and store an empty palette button used as a template. if( ButtonTemplate == null ) { // Search the button at the top viewport level, since palette's // HasResources=NO. ButtonTemplate = Viewport.GetResourceObject( button_name + start_index ); if( ButtonTemplate == null ) { SetError( "Can't find palette button to copy!" ); return 0; } // Delete the template button from the palette but keep it around. palette.DeleteObject( ButtonTemplate ); // Store NumRows and NumColumns info. NumRows = ButtonTemplate.GetDResource( "NumRows" ).intValue(); NumColumns = ButtonTemplate.GetDResource( "NumColumns" ).intValue(); } // Find icons in the palette template and add them to the palette, // using a copy of the template button. for( i=0; ; ++i ) { GlgObject icon = PaletteTemplate.GetResourceObject( icon_name + i ); if( icon == null ) break; // Done: no more icons. // Set node index, position and uniform name (Icon). icon.SetDResource( "Index", (double)i ); icon.SetSResource( "Name", "Icon" ); int obj_type = icon.GetDResource( "Type" ).intValue(); // Set empty label and position the node. if( obj_type == GlgObject.REFERENCE ) { icon.SetSResource( "Template/Label/String", "" ); icon.SetGResource( "Point", 0., 0., 0. ); // Center position } else { icon.SetSResource( "Label/String", "" ); // The nodes which don't use reference object will be positioned // using GlgPositionObject after the drawing has been setup. } // Create a button to hold the icon. GlgObject button = ButtonTemplate.CloneObject( GlgObject.STRONG_CLONE ); // Set button name adding an indexed suffix (IconButtonN). button.SetSResource( "Name", button_name + ( start_index + i ) ); // Set tooltip string. GlgObject tooltip = icon.GetResourceObject( "TooltipString" ); if( tooltip != null ) // Use custom data from icon if defined. button.SetResourceFromObject( "TooltipString", tooltip ); else // Use "Node" as a default. button.SetSResource( "TooltipString", "Node" ); // Position the button by setting row and column indices. button.SetDResource( "RowIndex", (double) ( ( start_index + i ) / (int) NumColumns ) ); button.SetDResource( "ColumnIndex", (double) ( ( start_index + i ) % (int) NumColumns ) ); button.SetDResource( "Zoom", ICON_SCALE ); button.AddObjectToBottom( icon ); palette.AddObjectToBottom( button ); } if( i == 0 ) SetError( "Can't find any icons." ); if( finish ) { ButtonTemplate = null; PaletteTemplate = null; } return i; // Return number of icons added. } ////////////////////////////////////////////////////////////////////////// // Invoked after the drawing has been setup. Positions nodes with multiple // attachment points (they don't use reference object). // Parameters: // button_name Name of the buttons in the palette object. // start_index Number of buttons to skip (select and link // buttons already in the palette). ////////////////////////////////////////////////////////////////////////// void SetupObjectPalette( String button_name, int start_index ) { // Find icons in the palette template and add them to the palette, // using a copy of the template button. for( int i = start_index; ; ++i ) { GlgObject button = Viewport.GetResourceObject( button_name + i ); if( button == null ) return; // No more buttons GlgObject icon = button.GetResourceObject( "Icon" ); int type = icon.GetDResource( "Type" ).intValue(); if( type != GlgObject.REFERENCE ) icon.PositionObject( GlgObject.OBJECT_COORD, GlgObject.HCENTER | GlgObject.VCENTER, 0., 0., 0. ); // Center position } } ////////////////////////////////////////////////////////////////////////// // Queries items in the palette and returns array of node or link icons. ////////////////////////////////////////////////////////////////////////// GlgObject GetPaletteIcons( String button_name, String icon_name, String type ) { GlgObject type_obj; int i; GlgObject icon_array = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); for( i=0; ; ++i ) { // Get icon[i] GlgObject button = Viewport.GetResourceObject( button_name + i ); if( button == null ) break; GlgObject icon = button.GetResourceObject( icon_name ); if( icon == null || ( type_obj = icon.GetResourceObject( "IconType" ) ) == null ) continue; String type_string = type_obj.GetSResource( null ); if( type_string.equals( type ) ) { // Found an icon of requested type, add it to the array. icon_array.AddObjectToBottom( icon ); // Check the icon index to match the array index. int icon_index = icon.GetDResource( "Index" ).intValue(); if( icon_array.GetSize() - 1 != icon_index ) SetError( "Invalid icon index." ); } } int size = icon_array.GetSize(); if( i == 0 ) // First icon=null: can't find any icons! SetError( "Can't find palette buttons" ); else if( size == 0 ) SetError( "Can't find any icons of this type." ); if( size == 0 ) return null; // Done reading icons. System.out.println( "Scanned " + size + " " + type + " icons" ); return icon_array; } //////////////////////////////////////////////////////////////////////// // Adds custom data to the graphical object //////////////////////////////////////////////////////////////////////// void AddCustomData( GlgObject object, Object data ) { // Add back-pointer from graphics to the link's data struct, // keeping the data already attached (if any). // GlgObject custom_data = object.GetResourceObject( "CustomData" ); if( custom_data == null ) { // No custom data attached: create an extra group and attach it // to object as custom data. custom_data = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); object.SetResourceObject( "CustomData", custom_data ); } // To allow using non-glg objects, use a group with element type // JAVA_OBJECT as a holder. The first element of the group will keep // the custom data pointer (pointer to the Link or Node structure). GlgObject holder_group = new GlgDynArray( GlgObject.JAVA_OBJECT, 0, 0 ); holder_group.SetSResource( "Name", "PtrHolder" ); holder_group.AddObjectToBottom( data ); // Add it to custom data. custom_data.AddObjectToBottom( holder_group ); } //////////////////////////////////////////////////////////////////////// // Get custom data attached to the graphical object //////////////////////////////////////////////////////////////////////// Object GetData( GlgObject object ) { GlgObject holder_group = object.GetResourceObject( "PtrHolder" ); return holder_group.GetElement( 0 ); } //////////////////////////////////////////////////////////////////////// void SetRadioBox( String button_name ) { // Always highlight the new button: the toggle would unhighlight if // clicked on twice. GlgObject button = Viewport.GetResourceObject( button_name ); if( button != null ) button.SetDResource( "OnState", 1. ); // Unhighlight the previous button. if( LastButton != null && !LastButton.equals( button_name ) ) { button = Viewport.GetResourceObject( LastButton ); if( button != null ) button.SetDResource( "OnState", 0. ); } LastButton = button_name; // Store the last button. } //////////////////////////////////////////////////////////////////////// void GetPosition( GlgObject object, GlgPoint coord ) { int type = object.GetDResource( "Type" ).intValue(); if( type == GlgObject.REFERENCE ) { // Reference: can use its point to position it. coord.CopyFrom( object.GetGResource( "Point" ) ); } else { // Arbitrary object: convert the box's center to the world coords. // Get object center in screen coords. GlgCube box = object.GetBoxPtr(); GlgPoint center = new GlgPoint( ( box.p1.x + box.p2.x ) / 2., ( box.p1.y + box.p2.y ) / 2., ( box.p1.z + box.p2.z ) / 2. ); MainArea.ScreenToWorld( true, center, coord ); } } //////////////////////////////////////////////////////////////////////// // Fills Properties dialog with the selected object data //////////////////////////////////////////////////////////////////////// void FillData() { String label, object_data; switch( SelectedObjectType ) { default: label = "NO_OBJECT"; object_data = ""; break; case NODE: case LINK: label = GetObjectLabel( SelectedObject ); object_data = GetObjectData( SelectedObject ); break; } Viewport.SetSResource( "Dialog/DialogName/TextString", label ); Viewport.SetSResource( "Dialog/DialogData/TextString", object_data ); } //////////////////////////////////////////////////////////////////////// boolean ApplyData() { String label, object_data; label = Viewport.GetSResource( "Dialog/DialogName/TextString" ); object_data = Viewport.GetSResource( "Dialog/DialogData/TextString" ); switch( SelectedObjectType ) { case NODE: case LINK: break; default: return true; } // Store data SetObjectLabel( SelectedObject, label ); SetObjectData( SelectedObject, object_data ); Update(); return true; } //////////////////////////////////////////////////////////////////////// String GetObjectLabel( GlgObject object ) { Object data = GetData( object ); if( data instanceof GlgNodeData ) return ((GlgNodeData)data).object_label; else return ((GlgLinkData)data).object_label; } //////////////////////////////////////////////////////////////////////// void SetObjectLabel( GlgObject object, String label ) { Object data = GetData( object ); if( data instanceof GlgNodeData ) { // Display the label in the object if( object.GetResourceObject( "Template" ) != null ) object.SetSResource( "Template/Label/String", label ); else object.SetSResource( "Label/String", label ); ((GlgNodeData)data).object_label = label; } else if( data instanceof GlgLinkData ) { // Display the label if it's a link with a label. if( object.GetResourceObject( "Label" ) != null ) object.SetSResource( "Label/String", label ); ((GlgLinkData)data).object_label = label; } } //////////////////////////////////////////////////////////////////////// String GetObjectData( GlgObject object ) { Object data = GetData( object ); if( data instanceof GlgNodeData ) return ((GlgNodeData)data).object_data; else return ((GlgLinkData)data).object_data; } //////////////////////////////////////////////////////////////////////// void SetObjectData( GlgObject object, String object_data ) { Object data = GetData( object ); if( data instanceof GlgNodeData ) ((GlgNodeData)data).object_data = object_data; else ((GlgLinkData)data).object_data = object_data; } //////////////////////////////////////////////////////////////////////// boolean NodeConnected( GlgObject node ) { for( int i=0; i< CurrentDiagram.getLinkList().size(); ++ i ) { GlgLinkData link_data = (GlgLinkData) CurrentDiagram.getLinkList().elementAt( i ); if( link_data.getStartNode().graphics == node || link_data.getEndNode().graphics == node ) return true; } return false; } //////////////////////////////////////////////////////////////////////// int GetButton( AWTEvent event ) { if( ! ( event instanceof InputEvent ) ) return 0; InputEvent input_event = (InputEvent) event; int modifiers = input_event.getModifiers(); if( ( modifiers & InputEvent.BUTTON3_MASK ) != 0 ) return 3; else if( ( modifiers & InputEvent.BUTTON2_MASK ) != 0 ) return 2; else return 1; } } class GlgNodeData { int node_type; GlgDiagramPoint position; String object_label; String object_data; transient GlgObject graphics; GlgNodeData() { object_label = ""; object_data = ""; position = new GlgDiagramPoint(); } } class GlgLinkData { int link_type; int link_direction; GlgDiagramPoint link_color; transient GlgObject graphics; GlgNodeData start_node; GlgNodeData end_node; String start_point_name; String end_point_name; String object_label; String object_data; Vector point_array; GlgLinkData() { object_label = "A1"; object_data = ""; point_array = new Vector(); } GlgNodeData getStartNode() { return start_node; } GlgNodeData getEndNode() { return end_node; } void setStartNode( GlgNodeData node ) { start_node = node; } void setEndNode( GlgNodeData node ) { end_node = node; } } class GlgDiagramData { Vector node_list; Vector link_list; GlgDiagramData() { node_list = new Vector(); link_list = new Vector(); } Vector getNodeList() { return node_list; } Vector getLinkList() { return link_list; } } class GlgDiagramPoint extends GlgPoint { // Allowes for custom serialization extensions for saving and loading GlgDiagramPoint() { } GlgDiagramPoint( GlgPoint point ) { if( point != null ) { x = point.x; y = point.y; z = point.z; } } } // Custom handler, place application-specific code into these callbacks. class CustomHandler { static void AddObjectCB( GlgDiagram diagram, GlgObject icon, Object data, boolean is_node ) { } static void SelectObjectCB( GlgDiagram diagram, GlgObject icon, Object data, boolean is_node ) { } static void CutObjectCB( GlgDiagram diagram, GlgObject icon, Object data, boolean is_node ) { } static void PasteObjectCB( GlgDiagram diagram, GlgObject icon, Object data, boolean is_node ) { } }