View Javadoc

1   package org.wcb.autohome;
2   /***
3    * Copyright (C) 1999  Walter Bogaardt
4    *
5    * This library is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public
7    * License as published by the Free Software Foundation; either
8    * version 2 of the License, or (at your option) any later version.
9    *
10   * This library is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   * Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public
16   * License along with this library; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18   *
19   * Project: Alice X10 Home Automation
20   */
21  import javax.swing.JComboBox;
22  import javax.swing.JPanel;
23  import javax.swing.JScrollPane;
24  import javax.swing.JTextField;
25  import javax.swing.JButton;
26  import javax.swing.JOptionPane;
27  import javax.swing.BorderFactory;
28  import javax.swing.JLabel;
29  import javax.swing.event.ListSelectionEvent;
30  import javax.swing.event.ListSelectionListener;
31  import javax.swing.table.TableColumn;
32  
33  /* standard java stuff */
34  import java.awt.*;
35  import java.awt.event.ActionListener;
36  import java.awt.event.ActionEvent;
37  import java.util.Vector;
38  
39  /* special classes needed */
40  import org.wcb.autohome.implementations.Macro;
41  import org.wcb.autohome.implementations.MacroEvent;
42  import org.wcb.autohome.implementations.X10Module;
43  import org.wcb.autohome.interfaces.IMacro;
44  import org.wcb.autohome.interfaces.RefreshInterface;
45  import org.wcb.autohome.interfaces.X10DeviceConstants;
46  import org.wcb.autohome.interfaces.I18nConstants;
47  import org.wcb.autohome.interfaces.IMacroEvent;
48  import org.wcb.autohome.interfaces.IX10Module;
49  import org.wcb.autohome.util.Item;
50  import org.wcb.autohome.util.DeviceIDRenderer;
51  import org.wcb.autohome.util.ui.LightRender;
52  import org.wcb.util.TableSorter;
53  import org.wcb.util.SortButtonRenderer;
54  //import org.wcb.util.ExcelAdapter;
55  import org.wcb.util.TooltippedTable;
56  import org.wcb.autohome.model.MacroEventTableModel;
57  
58  /***
59   * Filename:    $Id: MacroSequencePanel.java,v 1.16 2004/02/28 00:21:46 wbogaardt Exp $
60   *
61   * Abstract: This panel handles a macro and the sequence of events its suppose
62   *to perform. These events being turning on or off a particular light or appliance.
63   * To create the trigger for starting the macro the user should enter the trigger information
64   *from the MacroTriggerPanel object.
65   *
66   * $Log: MacroSequencePanel.java,v $
67   * Revision 1.16  2004/02/28 00:21:46  wbogaardt
68   * fixed formating to be compliant with sun coding convention
69   *
70   * Revision 1.15  2004/02/06 20:06:15  wbogaardt
71   * replaced ampm drop boxes with time buttons which launch a time panel move menu items around on main panel
72   *
73   * Revision 1.14  2004/02/01 19:31:58  wbogaardt
74   * removed form layout references
75   *
76   * Revision 1.13  2004/01/18 00:48:31  wbogaardt
77   * refactored out unnecessary code and now have a functional initial design of monitoring panel
78   *
79   * Revision 1.12  2004/01/16 19:50:14  wbogaardt
80   * refactored, fixed long standing bug with updating macro panels, add error notification to user
81   * for improper device codes
82   *
83   * Revision 1.11  2004/01/16 00:53:34  wbogaardt
84   * Fixed a very obscure bug with the Macro Panel that it didn't added new
85   * x10 devices to the drop down of available x10 device for the macro. Modified Macro triggers to change
86   * the events to integer verses strings cleaner this way.
87   *
88   * Revision 1.10  2004/01/15 21:05:17  wbogaardt
89   * major revamp of Modules and interfaces changes overall structure of how information is stored
90   *
91   * Revision 1.9  2003/12/30 18:47:40  wbogaardt
92   * made labels so they are internationlized and fixed layout of trigger panel
93   *
94   * Revision 1.8  2003/12/30 00:56:45  wbogaardt
95   * added more internationalization to table column names.
96   *
97   * Revision 1.7  2003/12/20 20:13:01  wbogaardt
98   * modified formating and some names for labels
99   *
100  * Revision 1.6  2003/12/20 06:16:00  wbogaardt
101  * moved most buttons text to i18n internationalization.
102  *
103  * Revision 1.5  2003/12/12 23:17:33  wbogaardt
104  * javadoc comments refactored methods so they are more descriptive
105  *
106  * Revision 1.4  2003/10/10 22:50:43  wbogaardt
107  * removed error messages and cleaned up format
108  *
109  * Revision 1.3  2003/10/10 21:39:01  wbogaardt
110  * modified macro triggers to use calendar in stead of strings
111  *
112  *
113  *@author wbogaardt
114  *@version 1.0
115  */
116 public class MacroSequencePanel extends JPanel implements X10DeviceConstants, RefreshInterface {
117 
118     private JComboBox deviceIDCb, actionCb, macroCombo;
119     private String[] eventsString = {"Off", "On", "Brighten Lights", "Dim Lights"};
120     private JButton addEventButton, delEventButton, updateEventButton,
121     newButton, deleteMacroButton;
122     private JTextField waitTf, incrementsTf;
123     private MacroEventTableModel macroModel = null;
124     private TooltippedTable macroTable;
125     private TableSorter macroSorter;
126     private SortButtonRenderer macroSortButtonRenderer;
127     private ListSelectionListener macroListListener;
128     private JScrollPane macroScroll;
129    // private ExcelAdapter excelAdapter;
130     private JPanel tablePanel;
131     private RefreshInterface refreshInterface;
132     private static Vector MACRO_VECTOR = null;
133     private IMacro iCurrentMacro;
134 
135     /***
136      * The MacroSequencePanel allows setting up of CM11A macros. This sets the
137      * macro and the events associated with the macro.
138      * @param refresh The refresh interface so that the list of modules added to the system can be seen by this panel.
139      */
140     public MacroSequencePanel(RefreshInterface refresh) {
141         refreshInterface = refresh;
142         setupComponents();
143         setupListeners();
144     }
145 
146     private void setupComponents()
147     {
148         /* default data for table*/
149         Vector defaultData = new Vector();
150         defaultData.addElement(new MacroEvent());
151 
152         setLayout(new BorderLayout());
153         deviceIDCb = new JComboBox();
154         this.updateDeviceModules();
155         waitTf = new JTextField(2);
156 
157         addEventButton = new JButton(AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.ADD_BUTTON));
158         delEventButton = new JButton(AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.DELETE_BUTTON));
159         updateEventButton = new JButton(AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.UPDATE_BUTTON));
160         newButton = new JButton(AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.NEW_MACRO_BUTTON));
161         deleteMacroButton = new JButton(AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.DELETE_MACRO_BUTTON));
162         actionCb = new JComboBox(eventsString);
163         incrementsTf = new JTextField(4);
164         incrementsTf.setEnabled(false);
165         macroCombo = new JComboBox();
166         addSavedMacros(macroCombo);
167 
168         tablePanel = new JPanel();
169         macroModel = new MacroEventTableModel(defaultData);
170         macroSortButtonRenderer = new SortButtonRenderer();
171         if (macroModel != null)
172         {
173             /* sorting stuff for the table */
174             macroSorter = new TableSorter(macroModel);
175             macroTable = new TooltippedTable(macroSorter);
176             macroTable.setColHeaderRender(macroSortButtonRenderer);
177             macroSorter.addMouseListenerToHeaderInTable(macroTable, macroSortButtonRenderer);
178             macroSorter.sortByColumn(2, false);
179             TableColumn lampColumn = macroTable.getColumn(
180                     AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.DEVICE_COLUMN)
181             );
182             lampColumn.setCellRenderer(new LightRender());
183         }
184         macroScroll = new JScrollPane(macroTable);
185         macroScroll.setPreferredSize(new Dimension(625, 140));
186         tablePanel.add(macroScroll);
187 
188         add(this.createNorthPanel(), BorderLayout.NORTH);
189         add(this.createCenterPanel(), BorderLayout.CENTER);
190         add(tablePanel, BorderLayout.SOUTH);
191     }
192 
193     /***
194      * This creates the top panel that displays the list of macros
195      * and delays for those macros;
196      * @return The panel that should be palced in the north quadrant
197      */
198     private JPanel createNorthPanel() {
199         GridBagConstraints gridBagConstraints;
200         JPanel jNorthPanel = new javax.swing.JPanel();
201 
202         jNorthPanel.setLayout(new java.awt.GridBagLayout());
203 
204         jNorthPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black),
205                         AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.MACRO_TITLE_LABEL)));
206         jNorthPanel.setAlignmentX(0.0F);
207         jNorthPanel.setAlignmentY(0.0F);
208         jNorthPanel.add(newButton, new java.awt.GridBagConstraints());
209 
210         jNorthPanel.add(deleteMacroButton, new java.awt.GridBagConstraints());
211 
212         jNorthPanel.add(
213                 new JLabel(AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.CURRENT_MACRO_LABEL)),
214                 new java.awt.GridBagConstraints());
215 
216         jNorthPanel.add(macroCombo, new java.awt.GridBagConstraints());
217 
218         gridBagConstraints = new java.awt.GridBagConstraints();
219         gridBagConstraints.gridx = 0;
220         gridBagConstraints.gridy = 1;
221         gridBagConstraints.gridwidth = 3;
222         jNorthPanel.add(
223                 new JLabel(AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.TIME_DELAY_LABEL)),
224                 gridBagConstraints);
225 
226         gridBagConstraints = new java.awt.GridBagConstraints();
227         gridBagConstraints.gridx = 3;
228         gridBagConstraints.gridy = 1;
229         jNorthPanel.add(waitTf, gridBagConstraints);
230         return jNorthPanel;
231     }
232 
233     /***
234      * Sets up and creats the details of the macro and what events
235      * should take place for this macro.
236      * @return This is the details of the macro
237      */
238     private JPanel createCenterPanel() {
239         JPanel centerPanel = new JPanel();
240         centerPanel.setLayout(new java.awt.GridBagLayout());
241 
242         centerPanel.setBorder(BorderFactory.
243                 createTitledBorder(BorderFactory.createLineBorder
244                 (Color.black),
245                         AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.MACRO_DETAIL_LABEL)));
246         centerPanel.add(
247                 new JLabel(AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.INSTALLED_MODULES_LABEL)),
248                 new java.awt.GridBagConstraints());
249 
250         GridBagConstraints gridBagConstraints;
251         gridBagConstraints = new java.awt.GridBagConstraints();
252         gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
253         centerPanel.add(deviceIDCb, gridBagConstraints);
254 
255         centerPanel.add(
256                 new JLabel(AutoHomeAdminSession.getInstance().getI18n().getString(I18nConstants.COMMAND_LABEL)),
257                 new java.awt.GridBagConstraints());
258 
259         centerPanel.add(actionCb, new java.awt.GridBagConstraints());
260 
261         gridBagConstraints = new java.awt.GridBagConstraints();
262         gridBagConstraints.gridx = 0;
263         gridBagConstraints.gridy = 1;
264         gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
265         centerPanel.add(addEventButton, gridBagConstraints);
266 
267         gridBagConstraints = new java.awt.GridBagConstraints();
268         gridBagConstraints.gridx = 1;
269         gridBagConstraints.gridy = 1;
270         centerPanel.add(updateEventButton, gridBagConstraints);
271 
272         gridBagConstraints = new java.awt.GridBagConstraints();
273         gridBagConstraints.gridx = 2;
274         gridBagConstraints.gridy = 1;
275         gridBagConstraints.gridwidth = 2;
276         gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
277         centerPanel.add(delEventButton, gridBagConstraints);
278         return centerPanel;
279     }
280 
281     private void setupListeners()
282     {
283         macroListListener = new ListSelectionListener() {
284             public void valueChanged(ListSelectionEvent e) {
285                 if (!e.getValueIsAdjusting())
286                 {
287                     setDetails();
288                 }
289             }
290         };
291         if (macroModel != null)
292         {
293             macroTable.getSelectionModel().addListSelectionListener(macroListListener);
294         }
295         ActionListener al = new ActionListener()
296         {
297             public void actionPerformed(ActionEvent evt) {
298                 Object src = evt.getSource();
299                 if (src == addEventButton)
300                 {
301                     addMacroEvent();
302                 }
303                 if (src == updateEventButton)
304                 {
305                     updateMacroRow();
306                 }
307                 if (src == delEventButton)
308                 {
309                     deleteMacroRow();
310                 }
311                 if (src == newButton)
312                 {
313                     addNewMacro();
314                 }
315                 if (src == macroCombo)
316                 {
317                     loadMacro();
318                 }
319                 if (src == deleteMacroButton)
320                 {
321                     deleteCurrentMacro();
322                 }
323             }
324         };
325         addEventButton.addActionListener(al);
326         updateEventButton.addActionListener(al);
327         delEventButton.addActionListener(al);
328         newButton.addActionListener(al);
329         macroCombo.addActionListener(al);
330         deleteMacroButton.addActionListener(al);
331     }
332 
333     /***
334      * takes a table vector and puts it into
335      * the table model format then refreshes the UI
336      * to display the new table information.
337      * @param tableData Vector of data to add to this panels table model
338      */
339     public void setModel(Vector tableData)
340     {
341         if (tableData != null)
342         {
343             macroModel.setList(tableData);
344         }
345         updateUI();
346     }
347 
348     /***
349      * This returns an instance of the MessageInterface
350      * that is used in this class to control the various
351      * messages.
352      * @return this panels refresh interface.
353      */
354     public RefreshInterface getInterface()
355     {
356         return this;
357     }
358 
359     /***
360      *This allows outside objects to update the panel when there is a
361      *refresh that needs to be done.
362      */
363     public void refresh()
364     {
365         this.updateDeviceModules();
366         this.addSavedMacros(macroCombo);
367         this.loadMacro();
368         refreshInterface.refresh(); //also refresh the Trigger Panel
369     }
370 
371     /***
372      * allows creates icons of the individual devices that
373      * were created from the Module panel
374      */
375     private void updateDeviceModules()
376     {
377         deviceIDCb = AutoHomeAdminSession.getInstance().setRenderedModules(deviceIDCb);
378         deviceIDCb.setRenderer(new DeviceIDRenderer());
379     }
380 
381     /***
382      * adds to the combo box all the macros that have been saved
383      * to the properties file.
384      */
385     private void addSavedMacros(JComboBox comboBox)
386     {
387         comboBox = AutoHomeAdminSession.getInstance().getAvailableMacroEvents(comboBox);
388     }
389 
390     private void setDetails()
391     {
392         int rownum = macroTable.getSelectedRow();
393         try
394         {
395             rownum = macroSorter.getMappingToRow(rownum);
396         }
397         catch (Exception e)
398         {
399         }
400         showInMacroDetailView((IMacroEvent) macroModel.getItemAt(rownum));
401     }
402 
403     /***
404      *This displays the new vector of information
405      *in a table detail view.
406      *@param ime- table row to display in the detail view.
407      */
408     private void showInMacroDetailView(IMacroEvent ime)
409     {
410         /* display the Module ID */
411         IX10Module iX10Device = ime.getX10Module();
412         for (int i = 0; i < deviceIDCb.getItemCount(); i++)
413         {
414             if ((deviceIDCb.getItemAt(i)).toString().startsWith(iX10Device.getFullDeviceCode()))
415             {
416                 deviceIDCb.setSelectedIndex(i);
417             }
418         }
419         actionCb.setSelectedIndex(ime.getAction());
420     }
421 
422     /***
423      * loads the macros and their asociated events
424      * all in one Vector which has a data structure of each Macro
425      * in the call of getEvents() you will get a Vector of MacroEvents
426      *
427      */
428     private void loadMacro()
429     {
430         String mac = (String) macroCombo.getSelectedItem();
431         MACRO_VECTOR = AutoHomeAdminSession.getInstance().loadAllCM11AMacros();
432         int size = MACRO_VECTOR.size();
433         for (int i = 0; i < size; i++)
434         {
435             IMacro currMacro = (IMacro) MACRO_VECTOR.elementAt(i);
436             if (mac.equalsIgnoreCase(currMacro.getMacroName()))
437             {
438                 iCurrentMacro = currMacro;
439                 waitTf.setText(iCurrentMacro.getDelay() + "");
440                 setModel(iCurrentMacro.getEvents());
441             }
442         }
443     }
444 
445     /***
446      * add a new macro event to the macro table
447      */
448     public void addMacroEvent()
449     {
450         macroModel.addRow(getDetailItem());
451         saveAllMacroEvent();
452     }
453 
454     /***
455      * builds a A macro event which is used to display
456      * in the Macro table view as a row. The return
457      * parameter is just the interface the the MacroEvent
458      * object. This information is from the Macro Events Detail section on
459      * this panel.
460      *
461      *@return IMacroEvent - macro event interface
462      */
463     private IMacroEvent getDetailItem()
464     {
465         Item type = (Item) deviceIDCb.getSelectedItem();
466         String housecode = type.toString();
467         int zonecode = Integer.parseInt(housecode.substring(1));
468         return new MacroEvent("Name",
469                 new X10Module(type.toString().charAt(0), zonecode, "Device Name", "Macro Sequence", type.getType()),
470                 this.getAction(actionCb.getSelectedItem().toString()));
471     }
472 
473     /***
474      * Takes in a string of the action and returns
475      * it to a integer value equivalent.
476      * @param sAction the String is of the following; Off, On, Dim Lights, Brighten Lights
477      * @return a X10DeviceConstants of OFF_ACTION, ON_ACTION, DIM_ACTION, BRIGHT_ACTION
478      */
479     private int getAction(String sAction) {
480         if (sAction.equalsIgnoreCase("Off"))
481         {
482             return OFF_ACTION;
483         }
484         if (sAction.equalsIgnoreCase("On"))
485         {
486             return ON_ACTION;
487         }
488         if (sAction.equalsIgnoreCase("Dim Lights"))
489         {
490             return DIM_ACTION;
491         }
492         if (sAction.equalsIgnoreCase("Brighten Lights"))
493         {
494             return BRIGHT_ACTION;
495         }
496         return ON_ACTION;
497     }
498 
499     /***
500      * This deletes the selected row from the table model
501      * Currently only 25 events for one macro is allowed
502      */
503     public void deleteMacroRow()
504     {
505         int rownum = macroTable.getSelectedRow();
506         try
507         {
508             rownum = macroSorter.getMappingToRow(rownum);
509         }
510         catch (Exception e)
511         {
512         }
513         if (rownum > -1)
514         {
515             macroModel.removeRow(rownum);
516             saveAllMacroEvent();
517         }
518     }
519 
520     /***
521      * Updates the currently selected row
522      * from the details panel information. Using IMacroEvent
523      * Object to keep the data altogether so it now easier.
524      */
525     public void updateMacroRow()
526     {
527         int rownum = macroTable.getSelectedRow();
528         IMacroEvent rowData = getDetailItem();
529         try
530         {
531             rownum = macroSorter.getMappingToRow(rownum);
532         }
533         catch (Exception e)
534         {
535         }
536         if (rownum > -1)
537         {
538             macroModel.setValueAt(rowData, rownum);
539             saveAllMacroEvent();
540         }
541     }
542 
543     /***
544      * adds a new macro assignable sequence
545      */
546     public void addNewMacro()
547     {
548         String s = JOptionPane.showInputDialog("Enter a unique macro name (No spaces):");
549 
550         Vector defaultData = new Vector();
551         if (s != null)
552         {
553             int time = 0;
554             try
555             {
556                 time = Integer.parseInt(JOptionPane.showInputDialog("Time offset in minutes"));
557             }
558             catch (NumberFormatException err)
559             {
560                 time = 0;
561             }
562             macroCombo.addItem(s); //add Macro name to combo box
563             macroCombo.setSelectedIndex(macroCombo.getItemCount() - 1);
564             waitTf.setText(time + "");
565             defaultData.addElement(new MacroEvent(s, new X10Module(), ON_ACTION));
566         }
567         setModel(defaultData);
568         saveAllMacroEvent();
569         refreshInterface.refresh(); // refresh macro panel combo boxes
570     }
571 
572     /***
573      * Deletes the currently selected macro item
574      * and removes it from the file properties.
575      * Currently only allow for 25 events to one macro
576      */
577     public void deleteCurrentMacro()
578     {
579         String name = (String) macroCombo.getSelectedItem();
580         AutoHomeAdminSession.getInstance().deleteMacro(iCurrentMacro);
581         macroCombo.removeItem(name);
582         refreshInterface.refresh();
583     }
584 
585     /***
586      * Save the entire table model into a properties
587      * The format for the key is Macroname.event(modelRowNumber)=LM,A1,On
588      *This format is and will be changing soon.
589      */
590     public void saveAllMacroEvent()
591     {
592         int rowCount = macroTable.getRowCount();
593         String name = (String) macroCombo.getSelectedItem();
594         Vector macroEvents = new Vector();
595 
596         for (int cnt = 0; cnt < rowCount; cnt++)
597         {
598             macroEvents.addElement(macroModel.getItemAt(cnt));
599         }
600 
601         Macro macro = new Macro(name, "No Description", Integer.parseInt(waitTf.getText()), macroEvents);
602         AutoHomeAdminSession.getInstance().saveMacro(macro);
603     }
604 
605 }