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
34 import java.awt.*;
35 import java.awt.event.ActionListener;
36 import java.awt.event.ActionEvent;
37 import java.util.Vector;
38
39
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
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
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
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
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();
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
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);
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();
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 }