001/**
002 * Copyright (c) 2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2010-06-03 16:45:10 -0700 (Thu, 03 Jun 2010) $' 
007 * '$Revision: 24730 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029package org.kepler.workflowscheduler.gui;
030
031import java.awt.BorderLayout;
032import java.awt.Dimension;
033import java.awt.Point;
034import java.awt.event.MouseAdapter;
035import java.awt.event.MouseEvent;
036
037import javax.swing.BorderFactory;
038import javax.swing.JMenuItem;
039import javax.swing.JPanel;
040import javax.swing.JPopupMenu;
041import javax.swing.JScrollPane;
042import javax.swing.JTable;
043import javax.swing.border.TitledBorder;
044
045import ptolemy.actor.gui.TableauFrame;
046
047
048/**
049 *  A tab pane to display existing schedule. 
050 * @author tao
051 *
052 */
053public class ExistingSchedulePanel extends JPanel implements ScheduleChangeListenerInterface
054{
055  private static final String TITLE = "Existing Schedules";
056  private Schedule[] scheduleList = null;
057  private ScheduleTableModel scheduleTableModel = null;
058  private JTable scheduleTable = null;
059  private TableauFrame parent = null;
060  private ScheduleChangeController scheduleChangeController = null;
061  private WorkflowSchedulerParentPanel schedulerParentPanel = null;
062  
063  /**
064   * Constructor
065   */
066  public ExistingSchedulePanel(Schedule[] scheduleList, TableauFrame parent, 
067              WorkflowSchedulerParentPanel schedulerParentPanel, ScheduleChangeController scheduleChangeController)
068  {
069    this.scheduleList = scheduleList;
070    this.parent = parent;
071    this.schedulerParentPanel = schedulerParentPanel;
072    this.scheduleChangeController = scheduleChangeController;
073    initialize(); 
074  }
075  
076  /*
077   * Initialize the panel
078   */
079  private void initialize()
080  {
081    //create a titled border for parameter panel
082    TitledBorder title = BorderFactory.createTitledBorder(TITLE);
083    setBorder(title);
084    this.setLayout(new BorderLayout());
085    //JTableHeader header = scheduleTable.getTableHeader();
086    //header.setBackground(Color.LIGHT_GRAY);
087    scheduleTableModel = new ScheduleTableModel(scheduleList);   
088    scheduleTable = new JTable(scheduleTableModel);
089    scheduleTable.setAutoCreateColumnsFromModel(false);
090    PopupListener popupListener = new PopupListener();
091    scheduleTable.addMouseListener(popupListener);
092    JScrollPane scrollPane = new JScrollPane(scheduleTable);
093    scrollPane.setPreferredSize(new Dimension(800, 180));
094    add(scrollPane, BorderLayout.CENTER);
095    
096  }
097  
098  /**
099   * Handle the event that a new schedule is added
100   * Note: this method will handle the table which displays existing schedules. 
101   *          It doesn't do anything to the server.
102   * @param schedule  the new schedule
103   * @throws Exception
104   */
105  public void addSchedule(Schedule schedule) throws Exception
106  {
107    if(schedule != null && schedule.isValid())
108    {
109      if(scheduleList == null )
110      {
111        scheduleList = new Schedule[1];
112        scheduleList[0] = schedule;
113      }
114      else 
115      {
116        
117        Schedule[] oldArray = scheduleList;
118        int size = scheduleList.length;
119        int newSize = size+1;
120        scheduleList = new Schedule[newSize];
121        scheduleList[0]= schedule;
122        for(int i=0; i<size; i++)
123        {
124          scheduleList[i+1] = oldArray[i];
125        }
126     }
127     updateTable();
128   }
129   else
130   {
131      throw new Exception("The added schedule is not valid schedule and we couldn't add it");
132   }
133    
134  }
135  
136  /**
137   * Handle the event that a schedule is removed.
138   * Note: this method will handle the table which displays existing schedules. 
139   *          It doesn't do anything to the server.
140   * @param schedule the schedule will be removed
141   * @throws Exception
142   */
143  public void removeSchedule(Schedule schedule) throws Exception
144  {
145    if(schedule != null)
146    {
147      if(scheduleList == null || scheduleList.length == 0)
148      {
149        throw new Exception("Current schedule list is empty and we couldn't remove any schedule from it");
150      }
151      else 
152      {
153        boolean foundIt = false;
154        Schedule[] oldArray = scheduleList;
155        int size = scheduleList.length;
156        int newSize = size-1;
157        Schedule[] newArray = null;
158        if(newSize > 0)
159        {
160          //Note: only newSize is greater than zero, we initialize the array.
161          newArray = new Schedule[newSize];
162        }
163        //compare size -1 elements in old array
164        for(int i=0; i<newSize; i++)
165        {
166          Schedule existSchedule = oldArray[i];
167          if(existSchedule != null && existSchedule.getWorkflowJobName() != null  &&
168              existSchedule.getWorkflowJobName().equals(schedule.getWorkflowJobName()))
169          {
170            foundIt = true;
171            newArray[i] = oldArray[i+1];//skip the the element having index=i in old array.
172          }
173          else
174          {
175            if(!foundIt)
176            {
177              newArray[i]=oldArray[i];
178            }
179            else
180            {
181              newArray[i] = oldArray[i+1];
182            }
183          }
184        }
185        
186       if(!foundIt)
187       {
188         //If we didn't find matched schedule above for loop,
189         //We must compare the last element in the original list
190         Schedule existSchedule = oldArray[size-1];
191         if(existSchedule != null && existSchedule.getWorkflowJobName() != null  &&
192             existSchedule.getWorkflowJobName().equals(schedule.getWorkflowJobName()))
193         {
194           // the last element is the schedule we will remove. So 
195           //scheduleList will be the newArray
196           scheduleList = newArray;
197           updateTable();
198         }
199         else
200         {
201           throw new Exception("We couldn't find the deleted schedule "+schedule.getWorkflowJobName() +" in the existing schedule list. So remove action couldn't be peformed");
202         }
203       }
204       else
205       {
206         scheduleList = newArray;
207         updateTable();
208       }
209        
210       
211     }  
212   }
213   else
214   {
215      throw new Exception("The removed schedule is not valid schedule and we couldn't remove it");
216   }
217  }
218  
219  /**
220   * Handle the event that a schedule will be enabled
221   * Note: this method will handle the table which displays existing schedules. 
222   *          It doesn't do anything to the server.
223   * @param schedule the schedule will be enabled
224   * @throws Exception
225   */
226  public void enableSchedule(Schedule schedule) throws Exception
227  {
228    setScheduleStatus(true, schedule);
229  }
230  
231  /**
232   * Handle the event that a schedule will be disabled
233   * Note: this method will handle the table which displays existing schedules. 
234   *          It doesn't do anything to the server.
235   * @param schedule the schedule will be disabled
236   * @throws Exception
237   */
238  public void disableSchedule(Schedule schedule) throws Exception
239  {
240    setScheduleStatus(false, schedule);
241  }
242  
243  /*
244   * Set a schedule to be enabled or disalbed
245   */
246  private void setScheduleStatus(boolean enabled, Schedule schedule)
247  {
248    if(schedule != null && scheduleList != null && scheduleList.length >0)
249    {
250      String workflowJobName = schedule.getWorkflowJobName();
251      if(workflowJobName != null)
252      {
253        for(int i=0; i<scheduleList.length; i++)
254        {
255          Schedule existingSchedule = scheduleList[i];
256          if(existingSchedule != null && workflowJobName.equals(existingSchedule.getWorkflowJobName()))
257          {
258            existingSchedule.setEnabled(enabled);
259            updateTable();
260          }
261        }
262      }
263    }
264  }
265  
266  /**
267   * Handle the event that new schedules will replace the old ones
268   * @param newSchedule new schedules
269   * @throws Exception
270   */
271  public void update(Schedule[] newSchedules) throws Exception
272  {
273    scheduleList = newSchedules;
274    updateTable();
275    this.repaint();
276    this.validate();
277  }
278  
279  /*
280   * Update the table after the table data model was changed
281   */
282  private void updateTable()
283  {
284    scheduleTableModel = new ScheduleTableModel(scheduleList);
285    scheduleTable.setModel(scheduleTableModel);
286    //scheduleTableModel.fireTableDataChanged();
287    scheduleTable.repaint();
288    scheduleTable.validate();
289    //System.out.println("After repaint table");
290  }
291  
292  /*
293   * Class to handle right-click menu
294   */
295  private class PopupListener extends MouseAdapter {
296    
297    // on the Mac, popups are triggered on mouse pressed, while mouseReleased triggers them
298    // on the PC; use the trigger flag to record a trigger in mac, but do not show popup until the
299    // mouse released event 
300
301    boolean trigger = false;
302    private JPopupMenu popup = null;
303    private Schedule selectedSchedule = null;
304
305    /**
306     * Handle mouse pressed event
307     */
308    public void mousePressed(MouseEvent e)
309    {
310     
311        //select the clicked row first
312        scheduleTable.clearSelection();
313        int selrow = scheduleTable.rowAtPoint(new Point(e.getX(), e.getY()));
314        //System.out.println("the selection row number is============= "+selrow);
315        scheduleTable.setRowSelectionInterval(selrow, selrow);
316        selectedSchedule = scheduleList[selrow];
317        // for mac
318        if (e.isPopupTrigger()) 
319        {
320          trigger = true;
321        }
322      
323    }
324
325    /**
326     * Handle mouse released event
327     */
328    public void mouseReleased(MouseEvent e)
329    {
330      maybeShowPopup(e);     
331    }
332
333    /*
334     *Show right popup menu
335     */
336    private void maybeShowPopup(MouseEvent e)
337    {
338      //trigger = true is for mac. e.isPopupTrigger()  is for pc
339      if(e.isPopupTrigger() || trigger)
340      {
341        if(selectedSchedule != null)
342        {
343          popup = new JPopupMenu();
344          RemoveScheduleAction deleteAction = new RemoveScheduleAction(parent, schedulerParentPanel, scheduleChangeController);
345          deleteAction.setSchedule(selectedSchedule);
346          JMenuItem delete = new JMenuItem("Delete");
347          delete.addActionListener(deleteAction);
348          popup.add(delete);
349          EnableScheduleAction enableAction = null;
350          DisableScheduleAction disableAction = null;
351          boolean isEnabled = selectedSchedule.isEnabled();
352          if(isEnabled)
353          {
354            disableAction = new DisableScheduleAction(parent,  schedulerParentPanel, scheduleChangeController);
355            disableAction.setSchedule(selectedSchedule);
356            JMenuItem disable = new JMenuItem("Disable");
357            disable.addActionListener(disableAction);
358            popup.add(disable);
359          }
360          else
361          {
362            enableAction = new EnableScheduleAction(parent, schedulerParentPanel,scheduleChangeController);
363            enableAction.setSchedule(selectedSchedule);
364            JMenuItem enable = new JMenuItem("Enable");
365            enable.addActionListener(enableAction);
366            popup.add(enable);
367          }
368          trigger = false;
369          popup.show(e.getComponent(), e.getX(), e.getY());
370        }
371        
372      }
373    }
374
375  }
376  
377}