001/*
002 *  $Source: /cvsroot2/open/projects/WebARTS/ca/bc/webarts/tools/X10Buttons.java,v $
003 *  $Name:  $
004 *  $Revision: 563 $
005 *  $Date: 2012-11-03 19:28:37 -0700 (Sat, 03 Nov 2012) $
006 *  $Locker:  $
007 */
008/*
009 *  X10Buttons -- A simple Panel control pad that lists the available X10
010 *  devices and house codes and calls the required X10 call.
011 *
012 *  Copyright (C) 2003 WebARTS Design, North Vancouver Canada
013 *  http://www.webarts.bc.ca
014 *
015 *  This program is free software; you can redistribute it and/or modify
016 *  it under the terms of Version 2 of the GNU General Public License as
017 *  published by the Free Software Foundation.
018 *
019 *  This program is distributed in the hope that it will be useful,
020 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
021 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
022 *  GNU General Public License for more details.
023 *
024 *  You should have received a copy of the GNU General Public License
025 *  along with this program; if not, write to the Free Software
026 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
027 */
028package ca.bc.webarts.tools;
029
030import ca.bc.webarts.widgets.ColouredLabel;
031import ca.bc.webarts.widgets.JToggleButton;
032import ca.bc.webarts.widgets.Util;
033
034//import com.jpeterson.x10.SendX10;
035import javax.comm.NoSuchPortException;
036
037import javax.comm.PortInUseException;
038
039import java.awt.BorderLayout;
040import java.awt.Color;
041import java.awt.Dimension;
042import java.awt.FlowLayout;
043import java.awt.Font;
044import java.awt.GridLayout;
045import java.awt.event.ActionEvent;
046import java.awt.event.ActionListener;
047import java.awt.event.MouseAdapter;
048import java.awt.event.MouseEvent;
049import java.awt.event.MouseListener;
050import java.awt.event.MouseMotionAdapter;
051import java.io.File;
052import javax.swing.BorderFactory;
053import javax.swing.ButtonGroup;
054import javax.swing.ImageIcon;
055import javax.swing.JButton;
056import javax.swing.JCheckBox;
057import javax.swing.JPopupMenu;
058import javax.swing.JRadioButton;
059import javax.swing.JSpinner;
060import javax.swing.JWindow;
061import javax.swing.SpinnerListModel;
062import javax.swing.border.BevelBorder;
063import javax.swing.border.EmptyBorder;
064
065import kiwi.ui.KButton;
066import kiwi.ui.KPanel;
067
068import x10.FireCracker;
069import x10.X10Command;
070
071
072/**
073 *  A simple window widget that holds a bunch of buttons that directly turn an
074 *  X10 device on or off. This app requires a few other libraries: webarts, and
075 *  kiwi java libraries as well as some x10 devices and a X10 java
076 *  implementation on your system.
077 *
078 * @author    tgutwin
079 */
080public class X10Buttons extends JWindow implements ActionListener
081{
082
083  // Colours
084  /**  Constant holding the users file seperator. ("/" or "\")  */
085  private final static String SYSTEM_FILE_SEPERATOR = File.separator;
086
087  /**  Description of the Field */
088  private final static String DEFAULT_TRANSMITTER =
089      "com.jpeterson.x10.module.CM11A";
090  /**  A Class holder for its name (used in Logging).  */
091  private static String className_ = "X10Buttons";
092
093  /**  The colour used for all panels except the display area.  */
094  static Color mainBackColour_ = new Color( 100, 180, 245 );
095  /**  The colour used to back the display area.  */
096  static Color displayBackColour_ = Color.black;
097  /**  The display area text colour.  */
098  static Color displayTextColour_ = mainBackColour_.brighter();
099
100  /**  The Main Popup menu  */
101  static JPopupMenu mainMenu = new JPopupMenu( className_ + " Main Menu" );
102
103  /**  Popup menu Mouse Listener.  */
104  static MouseListener popupListener_ =
105    new MouseAdapter()
106    {
107
108      public void mousePressed( MouseEvent e )
109      {
110        maybeShowPopup( e );
111      }
112
113
114      public void mouseReleased( MouseEvent e )
115      {
116        maybeShowPopup( e );
117      }
118
119
120      private void maybeShowPopup( MouseEvent e )
121      {
122        if ( e.isPopupTrigger() )
123        {
124          mainMenu.show( e.getComponent(), e.getX(), e.getY() );
125        }
126      }
127    };
128  /**  The wrapper panel holding all in this JWindow.  */
129  KPanel dragableMiniViewPanel = new KPanel();
130  /**  The Button area wrapper inside the dragableMiniViewPanel.  */
131  KPanel miniViewPanel = new KPanel();
132  /**  The Control area at the top of the window.  */
133  KPanel miniViewWindowControlPanel = new KPanel();
134  /**  The window header / draggable button.  */
135  KButton miniDragButton = new KButton( "" );
136  /**  The button to Min/Max this mini app window  */
137  KButton miniButtonView_ = new KButton( "" );
138  /**  The button to close this mini app window.  */
139  KButton miniButtonClose_ = new KButton( "" );
140  /**  The panel holding the X10 buttons  */
141  KPanel miniButtonPanel_ = new KPanel();
142  /**  The panel holding the on/off toggle button  */
143  KPanel onOffPanel_ = new KPanel();
144  /**  The object holding the min/max icon.  */
145  ImageIcon iconMiniView_ = new ImageIcon();
146  /**  The object holding the close icon.  */
147  ImageIcon iconMiniClose_ = new ImageIcon();
148  /**  The object holding the dim icon.  */
149  ImageIcon iconDim_ = new ImageIcon();
150  /**  The object holding the bright icon.  */
151  ImageIcon iconBright_ = new ImageIcon();
152  /**  The X amount the current window was just dragged.  */
153  private int XDifference_;
154  /**  The Y amount the current window was just dragged. * */
155  private int YDifference_;
156  /**  the x position of the mini window. * */
157  private int xPosition_ = 100;
158  /**  the y position of the mini window. * */
159  private int yPosition_ = 100;
160  /**  the x position of the app window. * */
161  private int appXpos = -1;
162  /**  the y position of the app window. * */
163  private int appYpos = -1;
164  /**  the number of rows of buttons to display in the app window. * */
165  private int displayRows_ = 9;
166  /**  the number of columns of buttons to display in the app window. * */
167  private int displayCols_ = 2;
168  /**  Class var holding the number of x10 buttons * */
169  private int numButtons_ = 16;
170  /**  Description of the Field */
171  private String portDescriptor_ = "/dev/ttyS0";
172
173  /**  Holds the Hose code values for the House Code Spinner * */
174  //private String [] houseCodes_ = {" F "," E "," D "," C "," B "," A "};
175  private String[] houseCodes_ = {" A ", " B ", " C ", " D ", " E ", " F ", " G ",
176      " H ", " I ", " J ", " K ", " L ", " M ", " N ",
177      " O ", " P "};
178
179  /**  The Spinner model used in the Hose Code Spinner * */
180  private SpinnerListModel spinnerModel_ = new SpinnerListModel( houseCodes_ );
181  /**  Description of the Field */
182  private JSpinner houseSpinner_ = new JSpinner( spinnerModel_ );
183
184
185  /**  The dir where the images are located.  */
186  String IMAGE_DIR = "." + SYSTEM_FILE_SEPERATOR +
187      "images" + SYSTEM_FILE_SEPERATOR;
188
189  /**  The Extension for the button images * */
190  String buttonImageExtension_ = ".gif";
191
192  /**  The Extension for the button images * */
193  String buttonImagepath_ = "/images/org/javalobby/icons/20x20/Circle_";
194
195  /**  This is this apps draggable - Title bar.  */
196  ColouredLabel miniDragLabel = new ColouredLabel(
197      displayBackColour_,
198      displayTextColour_,
199      new Font( "Arial", Font.PLAIN, 9 ),
200      "X10 Buttons" );
201
202  /**  An array of the x10 buttons.  */
203  KButton[] x10controlButton_ = new KButton[numButtons_];
204
205  /**  A dim button.  */
206  KButton x10DimButton_ = new KButton( "" );
207
208  /**  A dim button.  */
209  KButton x10BrightButton_ = new KButton( "" );
210
211  /**  The toggle controlling if the next X10 command will be on or Off.  */
212  JToggleButton onOffToggle_ = new JToggleButton();
213
214  /**
215   *  Listener for when the mouse is pressed on the fake window frame title bar
216   *  button.
217   */
218  MouseAdapter miniViewMouseListener =
219    new MouseAdapter()
220    {
221      /**
222       *  the impl for a mouse press.
223       *
224       * @param  e  Description of Parameter
225       * @since
226       */
227      public void mousePressed( MouseEvent e )
228      {
229        XDifference_ = e.getX();
230        YDifference_ = e.getY();
231      }
232    };
233
234  /**  Listener for changing the location of this window. *  */
235  MouseMotionAdapter dragMiniViewMotionListener =
236    new MouseMotionAdapter()
237    {
238      /**
239       *  Implementation of the mouse dragged event handler.
240       *
241       * @param  e  Description of Parameter
242       * @since
243       */
244      public void mouseDragged( MouseEvent e )
245      {
246        setLocation( xPosition_ + ( e.getX() - XDifference_ ),
247            yPosition_ + ( e.getY() - YDifference_ ) );
248        xPosition_ = xPosition_ + ( e.getX() - XDifference_ );
249        yPosition_ = yPosition_ + ( e.getY() - YDifference_ );
250      }
251    };
252
253
254  /**  Constructor * */
255  X10Buttons()
256  {
257    initWindowPanels();
258    pack();
259    setLocation( xPosition_, yPosition_ );
260    setVisible( true );
261    toFront();
262  }
263
264
265  /**  Constructor * */
266  X10Buttons(boolean invisible)
267  {
268    if (!invisible)
269    {
270      initWindowPanels();
271      pack();
272      setLocation( xPosition_, yPosition_ );
273      setVisible( true );
274      toFront();
275    }
276  }
277
278
279  /**
280   *  The main program for the X10Buttons class.
281   *
282   * @param  arg  The command line arguments
283   */
284  public static void main( String[] arg )
285  {
286    System.out.println( "Starting X10Buttons " );
287    X10Buttons instance = new X10Buttons();
288  }
289
290
291  /**
292   *  Handles all the Actions originating from the Control Buttons.
293   *
294   * @param  e  The action event to handle
295   */
296  public void actionPerformed( ActionEvent e )
297  {
298    final String methodName = className_ + ": actionPerformed()";
299
300    JButton pressedButton = (JButton)( e.getSource() );
301    ImageIcon buttonIcon = (ImageIcon)pressedButton.getIcon();
302    String command = "";
303    int commandButtonNumber = 0;
304    boolean dim = false;
305    boolean bright = false;
306    if ( buttonIcon != null )
307    {
308      command = buttonIcon.getDescription();
309      //System.out.println("Action From: "+command);
310      if ( command.trim().equals( "Close " + className_ ) )
311      {
312        //System.out.println("Close App");
313        //stop();
314        //log_.close();
315        System.exit( 0 );
316      }
317      else if ( command.trim().equals( "dim" ) )
318      {
319        System.out.println( "dim" );
320        dim = true;
321      }
322      else if ( command.trim().equals( "bright" ) )
323      {
324        System.out.println( "bright" );
325        bright = true;
326      }
327      else
328      {
329        commandButtonNumber =
330            Integer.parseInt( ( command.substring( command.length() - 2 ) ).trim() );
331        //System.out.println("Button ICON Pressed: "+commandButtonNumber);
332      }
333    }
334    else
335    {
336      command = pressedButton.getToolTipText();
337      commandButtonNumber =
338          Integer.parseInt( ( command.substring( command.length() - 2 ) ).trim() );
339      //System.out.println("Button Pressed: "+commandButtonNumber);
340    }
341    String x10HouseCode = ( (String)houseSpinner_.getValue() ).trim().toUpperCase();
342    String x10DeviceNumber = String.valueOf( commandButtonNumber );
343    String x10Command = ( onOffToggle_.getState() ? "on" : "off" );
344    if ( dim || bright )
345    {
346      x10Command = ( dim ? "dim" : "bright" );
347      x10DeviceNumber = "";
348    }
349    sendX10Command( x10Command, x10HouseCode, x10DeviceNumber );
350  }
351
352
353  /**
354   *  Abstracts the actual sending of the X10 Command.
355   *
356   * @param  x10Command       This is either 'on' or 'off'
357   * @param  x10HouseCode     send an uppercase house code
358   * @param  x10DeviceNumber  send the device nuymber as a string... ie. 'String.valueOf( 1 );'
359   */
360  public void sendX10Command( String x10Command,
361                              String x10HouseCode,
362                              String x10DeviceNumber )
363  {
364    // Now disable all buttons and send the X10 command
365    enableDeviceButtons( false );
366
367    FireCracker fc = new FireCracker();
368    try
369    {
370      System.out.println( "Connecting to FireCracker on port " + portDescriptor_ );
371
372      fc.openPort( portDescriptor_ );
373    }
374    catch ( PortInUseException piux )
375    {
376      System.out.println( "Specified port in use by application: " +
377          piux.currentOwner );
378      return;
379    }
380    catch ( NoSuchPortException nspx )
381    {
382      System.out.println( "Specified port not recognized: " + portDescriptor_ + "\n" );
383      //usage();
384    }
385
386    // Give the device time to power up?
387    // It's not very reliable without this delay.
388    Util.sleep( 400 );
389
390    X10Command xcmd = null;
391    //System.out.println("Preparing:"+ x10HouseCode.charAt(0)+Integer.parseInt(x10DeviceNumber)+" "+x10Command);
392    if ( x10Command.equals( "on" ) )
393    {
394      xcmd = X10Command.makeOnCommand( x10HouseCode.charAt( 0 ),
395          Integer.parseInt( x10DeviceNumber ) );
396    }
397    else if ( x10Command.equals( "off" ) )
398    {
399      xcmd = X10Command.makeOffCommand( x10HouseCode.charAt( 0 ),
400          Integer.parseInt( x10DeviceNumber ) );
401    }
402    else if ( x10Command.equals( "dim" ) )
403    {
404      xcmd = X10Command.makeDimCommand( x10HouseCode.charAt( 0 ) );
405    }
406    else if ( x10Command.equals( "bright" ) )
407    {
408      xcmd = X10Command.makeBrightCommand( x10HouseCode.charAt( 0 ) );
409    }
410    System.out.println( "Sending:" + x10HouseCode.charAt( 0 ) + x10DeviceNumber + " " + x10Command );
411    fc.sendCommand( xcmd );
412
413    System.out.println( "\nDisconnecting from FireCracker" );
414    fc.closePort();
415
416    //String [] x10Args = {x10Command, x10HouseCode, x10DeviceNumber};
417    //SendX10 sx = new SendX10("/dev/ttyS1", DEFAULT_TRANSMITTER );
418    //sx.transmit(0, x10Args);
419
420    //Util.sleep(2500);
421    enableDeviceButtons( true );
422  }
423
424
425  /**
426   *  Creates a button using a Icon with a preset imagename
427   *
428   * @param  controlNumber  Description of the Parameter
429   * @return                Description of the Return Value
430   */
431  private KButton createIconButton( int controlNumber )
432  {
433    KButton retVal = new KButton( String.valueOf( controlNumber ) );
434    ImageIcon tempIcon;
435    tempIcon =
436        new ImageIcon(
437        Util.loadImage( buttonImagepath_ + controlNumber + buttonImageExtension_ ),
438        "X10 Device " + controlNumber );
439
440    retVal.setIcon( tempIcon );
441    retVal.setPreferredSize(
442        new Dimension( tempIcon.getIconWidth() + 3, tempIcon.getIconHeight() + 3 ) );
443    retVal.setToolTipText( "X10 Device #" + controlNumber );
444    retVal.addActionListener( this );
445    retVal.setBorder( BorderFactory.createBevelBorder(
446        BevelBorder.RAISED ) );
447    return retVal;
448  }
449
450
451  /**
452   *  Creates a button using only text inside
453   *
454   * @param  controlNumber  Description of the Parameter
455   * @return                Description of the Return Value
456   */
457  private KButton createButton( int controlNumber )
458  {
459    KButton retVal = new KButton( String.valueOf( controlNumber ) );
460    // TO_DO: Add a custom tooltip naming the device on the end of this num
461    retVal.setToolTipText( "X10 Device # " + controlNumber );
462    retVal.addActionListener( this );
463    retVal.setBorder( BorderFactory.createBevelBorder(
464        BevelBorder.RAISED ) );
465    return retVal;
466  }
467
468
469  /**  Inits the gui widgets * */
470  private void initWindowPanels()
471  {
472    /*
473     *  Init Window dressing
474     */
475    String miniViewFilename = "/images/miniViewButtonImage.jpg";
476    String miniCloseFilename = "/images/miniCloseButtonImage.jpg";
477    String x10DimFilename = "/images/Down24.gif";
478    String x10BrightFilename = "/images/Up24.gif";
479
480    // the dragabler title bar button
481    miniDragButton.setMaximumSize( new Dimension( 100, 16 ) );
482    miniDragButton.setBorder( BorderFactory.createRaisedBevelBorder() );
483    miniDragButton.setBorderPainted( true );
484    miniDragButton.setDoubleBuffered( true );
485    miniDragButton.add( miniDragLabel );
486    miniDragButton.addMouseListener( miniViewMouseListener );
487    miniDragButton.addMouseMotionListener( dragMiniViewMotionListener );
488    miniDragButton.addMouseListener( popupListener_ );
489
490    // the mini close button
491    iconMiniClose_ =
492        new ImageIcon( Util.loadImage( miniCloseFilename ), "Close " + className_ );
493    miniButtonClose_.addActionListener( this );
494    miniButtonClose_.setIcon( iconMiniClose_ );
495    miniButtonClose_.setToolTipText( "Close " + className_ );
496    miniButtonClose_.setPreferredSize( new Dimension( 16, 16 ) );
497    miniButtonClose_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) );
498    miniButtonClose_.setBorderPainted( false );
499    miniButtonClose_.setDoubleBuffered( true );
500
501    // the mini Dim button
502    iconDim_ =
503        new ImageIcon( Util.loadImage( x10DimFilename ), "dim" );
504    x10DimButton_.addActionListener( this );
505    x10DimButton_.setIcon( iconDim_ );
506    x10DimButton_.setToolTipText( "dim" );
507    x10DimButton_.setPreferredSize( new Dimension( 16, 16 ) );
508    x10DimButton_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) );
509    x10DimButton_.setBorderPainted( false );
510    x10DimButton_.setDoubleBuffered( true );
511
512    // the mini Dim button
513    iconBright_ =
514        new ImageIcon( Util.loadImage( x10BrightFilename ), "bright" );
515    x10BrightButton_.addActionListener( this );
516    x10BrightButton_.setIcon( iconBright_ );
517    x10BrightButton_.setToolTipText( "bright" );
518    x10BrightButton_.setPreferredSize( new Dimension( 16, 16 ) );
519    x10BrightButton_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) );
520    x10BrightButton_.setBorderPainted( false );
521    x10BrightButton_.setDoubleBuffered( true );
522
523    // the Title Area Panel
524    miniViewWindowControlPanel.add( miniDragButton, BorderLayout.CENTER );
525    miniViewWindowControlPanel.add( miniButtonClose_, BorderLayout.EAST );
526    miniViewWindowControlPanel.setDoubleBuffered( true );
527    miniViewWindowControlPanel.addMouseListener( popupListener_ );
528
529    // the Button Panel
530    miniButtonPanel_.setLayout( new GridLayout( displayRows_, displayCols_, 1, 1 ) );
531    miniButtonPanel_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) );
532    miniButtonPanel_.addMouseListener( popupListener_ );
533    for ( int i = 0; i < numButtons_; i++ )
534    {
535      x10controlButton_[i] = createButton( i + 1 );
536      miniButtonPanel_.add( x10controlButton_[i] );
537    }
538    miniButtonPanel_.add( x10BrightButton_ );
539    miniButtonPanel_.add( x10DimButton_ );
540
541    onOffPanel_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) );
542    houseSpinner_.setValue( houseCodes_[0] );
543    onOffPanel_.add( houseSpinner_ );
544    onOffPanel_.add( onOffToggle_ );
545
546    // now stitch it all together
547    dragableMiniViewPanel.setDoubleBuffered( true );
548    dragableMiniViewPanel.setLayout( new BorderLayout( 0, 0 ) );
549    dragableMiniViewPanel.add( miniViewWindowControlPanel, BorderLayout.NORTH );
550    dragableMiniViewPanel.add( miniButtonPanel_, BorderLayout.CENTER );
551    dragableMiniViewPanel.add( onOffPanel_, BorderLayout.SOUTH );
552    getContentPane().add( dragableMiniViewPanel );
553  }
554
555
556  /**
557   *  Description of the Method
558   *
559   * @param  state  Description of the Parameter
560   */
561  private void enableDeviceButtons( boolean state )
562  {
563    for ( int i = 0; i < numButtons_; i++ )
564    {
565      x10controlButton_[i].setEnabled( state );
566    }
567  }
568}
569