1:/*
   2: *  Copyright (c) 2000-2002, Shayne R Flint
   3: *  All rights reserved.
   4: *
   5: *  Redistribution and use in source and binary forms, with or without
   6: *  modification, are permitted provided that the following conditions
   7: *  are met:
   8: *
   9: *  1. Redistributions of source code must retain the above copyright
  10: *  notice, this list of conditions and the following disclaimer.
  11: *
  12: *  2. Redistributions in binary form must reproduce the above copyright
  13: *  notice, this list of conditions and the following disclaimer in the
  14: *  documentation and/or other materials provided with the distribution.
  15: *
  16: *  3. The name of the author may not be used to endorse or promote products
  17: *  derived from this software without specific prior written permission.
  18: *
  19: *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  20: *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21: *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22: *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23: *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24: *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25: *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26: *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27: *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28: *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29: */
  30: 
  31:package armidale.test;
  32:
  33:import armidale.api.Application;
  34:import armidale.api.ClassInformation;
  35:import armidale.api.ProductInfo;
  36:import armidale.api.context.*;
  37:import armidale.api.context.clientserver.*;
  38:import armidale.api.context.platform.*;
  39:
  40:import armidale.api.gui.*;
  41:import armidale.api.gui.constants.*;
  42:import armidale.api.io.Debug;
  43:import armidale.api.io.File;
  44:
  45:import java.io.IOException;
  46:
  47:// This is a simple armidale application which will open a small frame
  48:// with an image and button on it. A callback is defined to display
  49:// a message on the server when the button is clicked.
  50://
  51:// Because this is an armidale application, it can be run stand-alone or over
  52:// a network using the armidale launcher.
  53://
  54:  
  55:
  56:// All armidale applications must extend armidale.api.Application or an extension of it.
  57://
  58:public class SimpleApp extends Application {  
  59:
  60:
  61:  public void init() {
  62:
  63:    // This is where the main work is done. The init() method is declared in armidale.api.Application
  64:    // and is called as part of the application execution (see the armidale.api.Application.run()
  65:    // method).
  66:    //
  67:    
  68:    // We start by creating a frame using the armidale.api.gui.FrameFactory. This factory creates
  69:    // implementations of the armidale.api.gui.Frame interface based on the specified context (usually
  70:    // server or local swing). The context parameter used below is declared in armidale.api.Application
  71:    // (our parent class) and is set by the environment starting the application. In the standalone
  72:    // case this is set in a main method like the one defined later in this class. In the case of a 
  73:    // server environment, it is set by the armidale server in response to a connection
  74:    // request from a client.
  75:    //
  76:    // The main point here is that the application developer doesn't have to worry about what
  77:    // context is set to. He just passes it as a parameter the the various factories and other
  78:    // API methods.
  79:    //
  80:    Frame frame = FrameFactory.create(context);
  81:
  82:    
  83:    // Armidale handles events using a callback mechanism. When an event is generated by a widget
  84:    // (eg. a user clicks a button) a specific method of each associated callback object is called. 
  85:    // For example, when a Frame is closed, a frame close event is generated. This
  86:    // event results in a call to the windowClosing() method of each associate WindowCallback object.
  87:    //
  88:    // In the following statement we add a callback to the frame to handle window close events
  89:    // (ie. when the user clicks the close icon at the top of the window). As a convenience, armidale
  90:    // includes a simple class (armidale.api.gui.WindowCloseCallback) that implements various
  91:    // options regarding the closing of frames. Here we have chosen to stop the application when
  92:    // the user closes the frame.
  93:    //    
  94:    frame.addWindowCallback(new WindowCloseCallback(context, WindowCloseCallback.STOP_APPLICATION_ON_CLOSE));
  95:    
  96:    
  97:    // Complete the initialization of the frame by setting its title, size etc.
  98:    //
  99:    frame.setTitle("Simple Application");
 100:    frame.setSize(new Size(420, 200));
 101:    frame.setAlignment(Frame.CENTER);
 102:    frame.setResizable(false);
 103:
 104:    
 105:    // The image and button will be displayed on a BorderPanel. Create the main panel
 106:    // and set its background color. Note that the Color class here is an armidale.api.gui.Color,
 107:    // not a java.awt.Color
 108:    //
 109:    BorderPanel  mainPanel    = BorderPanelFactory.create(context);
 110:    mainPanel.setBackgroundColor(Color.WHITE);
 111:
 112:    
 113:    // Create the image and set the image data to the contents of a specified file.
 114:    //
 115:    // By using the setFile() method to set the image data, this application, when run on a server,
 116:    // will ask the client to try and load the image from the client filesystem. If the image
 117:    // is not available on the client, it will downloaded from the server.
 118:    //
 119:    Image        image        = ImageFactory.create(context);
 120:    image.setFile(new File("images/armidaledemo.png"));
 121:
 122:    
 123:    // Create a label, based on the above image and set its alignment
 124:    //
 125:    Label        label        = LabelFactory.create(context);
 126:    label.setImage(image);
 127:    label.setAlignment(Label.CENTER);
 128:
 129:    
 130:    // Add the label created above to the main panel. To add a widget to a border panel, it needs to 
 131:    // be wrapped up in a BorderPanelWidget along with its position (constraints) on the border panel
 132:    // (ie. north, south, east, west or center). Note that this pattern is used for many of the armidale
 133:    // panels (eg. GridPanel and GridPanelWidget).
 134:    //
 135:    mainPanel.addWidget(BorderPanelWidgetFactory.create(context, label, BorderPanelWidget.CENTER));
 136:
 137:    
 138:    // Following the same pattern of widget creation, we now create a button and set some its
 139:    // properties
 140:    //
 141:    PushButton   testButton   = PushButtonFactory.create(context);
 142:    testButton.setText("Test Events");
 143:    testButton.setPreferredSize(new Size(150, 25));
 144:
 145:    
 146:    // For convenience, armidale provides a Debug implementation of all callback classes.
 147:    // These Debug classes print details of events generated by associated widgets.
 148:    //
 149:    // In the following code we add to the button a pre-built ActionCallbackDebug object which displays
 150:    // a debug message when the button is pressed.
 151:    //
 152:    testButton.addActionCallback(new ActionCallbackDebug(context));
 153:
 154:    
 155:    // We are now going to create a FlowPanel on which to place the Button. This panel will, in turn,
 156:    // be placed on the main border panel created above.
 157:    //
 158:    FlowPanel    buttonPanel  = FlowPanelFactory.create(context);
 159:    buttonPanel.setBackgroundColor(Color.WHITE);
 160:    buttonPanel.setHorizontalGap(6);
 161:    buttonPanel.setVerticalGap(6);
 162:    
 163:    
 164:    // Now add the button to the FlowPanel. There are no constraints applicable to widgets placed on a 
 165:    // flow panel, so we don't use a special wrapper class like the BorderPanelWidget used above.
 166:    //
 167:    buttonPanel.addWidget(testButton);
 168:
 169:    
 170:    // Now add the button panel to the south of the main border panel.
 171:    //
 172:    mainPanel.addWidget(BorderPanelWidgetFactory.create(context, buttonPanel, BorderPanelWidget.SOUTH));
 173:    
 174:    
 175:    // Next, we need to add the main panel (with its image and flow panel containing the button) to the
 176:    // frame. Frames have a tool bar, status bar and content area, each of which contain a single
 177:    // widget. Here we use setContent() to set the content of the frame to the main panel we
 178:    // created above.
 179:    //
 180:    frame.setContent(mainPanel);
 181:    
 182:    // And finaly, we make the frame visible.
 183:    //
 184:    frame.show();
 185:  }
 186:
 187:  
 188:  
 189:  // A main method is required if you want to be able to run an application
 190:  // stand-alone. The pattern of this main is fairly common in Java applications, 
 191:  // in that it creates an instance of the enclosing class. In the case of armidale,
 192:  // it must also set the context in which to run the application. To run the application
 193:  // locally, we need to use the SwingContext which will cause the various widget factories
 194:  // to create objects that are implemented using swing. These object will therefore be
 195:  // displayed on the local computer.
 196:  //
 197:  public static void main(String[] args) {
 198:    
 199:    // create an instance of SimpleApp
 200:    //
 201:    SimpleApp  app  = new SimpleApp();
 202:    
 203:    // set the apps context to an instance of SwingContext. 
 204:    //
 205:    app.setContext(new SwingContext());
 206:    
 207:    // the application is now ready to go. So start it.
 208:    //
 209:    app.start();
 210:  }
 211:
 212:}
 213: