001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2009-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2016 ForgeRock AS.
016 */
017package org.opends.guitools.controlpanel.ui;
018
019import static org.forgerock.util.Utils.*;
020import static org.opends.messages.AdminToolMessages.*;
021import static org.opends.server.util.CollectionUtils.*;
022import static org.opends.server.util.LDIFReader.*;
023
024import java.awt.Component;
025import java.awt.GridBagConstraints;
026import java.awt.GridBagLayout;
027import java.awt.event.ActionEvent;
028import java.awt.event.ActionListener;
029import java.awt.event.KeyEvent;
030import java.util.ArrayList;
031import java.util.HashMap;
032import java.util.HashSet;
033import java.util.LinkedHashSet;
034import java.util.List;
035import java.util.Map;
036import java.util.Random;
037import java.util.Set;
038
039import javax.swing.Box;
040import javax.swing.JButton;
041import javax.swing.JLabel;
042import javax.swing.JMenu;
043import javax.swing.JMenuBar;
044import javax.swing.JMenuItem;
045import javax.swing.JPanel;
046import javax.swing.JScrollPane;
047import javax.swing.JTable;
048import javax.swing.JTextArea;
049import javax.swing.ListSelectionModel;
050import javax.swing.SwingUtilities;
051import javax.swing.event.ListSelectionEvent;
052import javax.swing.event.ListSelectionListener;
053
054import org.forgerock.i18n.LocalizableMessage;
055import org.forgerock.i18n.slf4j.LocalizedLogger;
056import org.forgerock.opendj.ldap.AttributeDescription;
057import org.forgerock.opendj.ldap.ByteString;
058import org.forgerock.opendj.ldap.DN;
059import org.forgerock.opendj.ldap.schema.AttributeType;
060import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
061import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
062import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
063import org.opends.guitools.controlpanel.datamodel.TaskTableModel;
064import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
065import org.opends.guitools.controlpanel.task.CancelTaskTask;
066import org.opends.guitools.controlpanel.task.Task;
067import org.opends.guitools.controlpanel.ui.renderer.TaskCellRenderer;
068import org.opends.guitools.controlpanel.util.ConfigFromFile;
069import org.opends.guitools.controlpanel.util.Utilities;
070import org.opends.server.core.DirectoryServer;
071import org.opends.server.tools.tasks.TaskEntry;
072import org.opends.server.types.Attribute;
073import org.opends.server.types.AttributeBuilder;
074import org.opends.server.types.Entry;
075import org.forgerock.opendj.ldap.schema.ObjectClass;
076import org.opends.server.types.OpenDsException;
077
078/** The panel displaying the list of scheduled tasks. */
079public class ManageTasksPanel extends StatusGenericPanel
080{
081  private static final long serialVersionUID = -8034784684412532193L;
082
083  private JLabel lNoTasksFound;
084
085  /** Remove task button. */
086  private JButton cancelTask;
087  /** The scroll that contains the list of tasks (actually is a table). */
088  private JScrollPane tableScroll;
089  /** The table of tasks. */
090  private JTable taskTable;
091
092  /** The model of the table. */
093  private TaskTableModel tableModel;
094
095  private ManageTasksMenuBar menuBar;
096
097  private MonitoringAttributesViewPanel<LocalizableMessage> operationViewPanel;
098  private GenericDialog operationViewDlg;
099
100  private JPanel detailsPanel;
101  private JLabel noDetailsLabel;
102  /** The panel containing all the labels and values of the details. */
103  private JPanel detailsSubpanel;
104  private JLabel logsLabel;
105  private JScrollPane logsScroll;
106  private JTextArea logs;
107  private JLabel noLogsLabel;
108
109  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
110
111  /** Default constructor. */
112  public ManageTasksPanel()
113  {
114    super();
115    createLayout();
116  }
117
118  @Override
119  public LocalizableMessage getTitle()
120  {
121    return INFO_CTRL_PANEL_TASK_TO_SCHEDULE_LIST_TITLE.get();
122  }
123
124  @Override
125  public boolean requiresScroll()
126  {
127    return false;
128  }
129
130  @Override
131  public GenericDialog.ButtonType getButtonType()
132  {
133    return GenericDialog.ButtonType.CLOSE;
134  }
135
136  @Override
137  public void okClicked()
138  {
139    // Nothing to do, it only contains a close button.
140  }
141
142  @Override
143  public JMenuBar getMenuBar()
144  {
145    if (menuBar == null)
146    {
147      menuBar = new ManageTasksMenuBar(getInfo());
148    }
149    return menuBar;
150  }
151
152  @Override
153  public Component getPreferredFocusComponent()
154  {
155    return taskTable;
156  }
157
158  /**
159   * Returns the selected cancelable tasks in the list.
160   * @param onlyCancelable add only the cancelable tasks.
161   * @return the selected cancelable tasks in the list.
162   */
163  private List<TaskEntry> getSelectedTasks(boolean onlyCancelable)
164  {
165    ArrayList<TaskEntry> tasks = new ArrayList<>();
166    int[] rows = taskTable.getSelectedRows();
167    for (int row : rows)
168    {
169      if (row != -1)
170      {
171        TaskEntry task = tableModel.get(row);
172        if (!onlyCancelable || task.isCancelable())
173        {
174          tasks.add(task);
175        }
176      }
177    }
178    return tasks;
179  }
180
181  /**
182   * Creates the components and lays them in the panel.
183   * @param gbc the grid bag constraints to be used.
184   */
185  private void createLayout()
186  {
187    GridBagConstraints gbc = new GridBagConstraints();
188    gbc.anchor = GridBagConstraints.WEST;
189    gbc.gridx = 0;
190    gbc.gridy = 0;
191    gbc.gridwidth = 2;
192    addErrorPane(gbc);
193
194    gbc.weightx = 0.0;
195    gbc.gridy ++;
196    gbc.anchor = GridBagConstraints.WEST;
197    gbc.weightx = 0.0;
198    gbc.fill = GridBagConstraints.NONE;
199    gbc.gridwidth = 2;
200    gbc.insets.left = 0;
201    gbc.gridx = 0;
202    gbc.gridy = 0;
203    lNoTasksFound = Utilities.createDefaultLabel(
204        INFO_CTRL_PANEL_NO_TASKS_FOUND.get());
205    gbc.gridy ++;
206    gbc.anchor = GridBagConstraints.CENTER;
207    gbc.gridheight = 2;
208    add(lNoTasksFound, gbc);
209    lNoTasksFound.setVisible(false);
210
211    gbc.gridwidth = 1;
212    gbc.weightx = 1.0;
213    gbc.weighty = 1.0;
214    gbc.fill = GridBagConstraints.BOTH;
215    gbc.insets.top = 10;
216    gbc.anchor = GridBagConstraints.NORTHWEST;
217    // Done to provide a good size to the table.
218    tableModel = new TaskTableModel()
219    {
220      private static final long serialVersionUID = 55555512319230987L;
221
222      /**
223       * Updates the table model contents and sorts its contents depending on
224       * the sort options set by the user.
225       */
226      @Override
227      public void forceResort()
228      {
229        Set<String> selectedIds = getSelectedIds();
230        super.forceResort();
231        setSelectedIds(selectedIds);
232      }
233    };
234    tableModel.setData(createDummyTaskList());
235    taskTable =
236      Utilities.createSortableTable(tableModel, new TaskCellRenderer());
237    taskTable.getSelectionModel().setSelectionMode(
238        ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
239    tableScroll = Utilities.createScrollPane(taskTable);
240    add(tableScroll, gbc);
241    updateTableSizes();
242    int height = taskTable.getPreferredScrollableViewportSize().height;
243    add(Box.createVerticalStrut(height), gbc);
244
245    gbc.gridx = 1;
246    gbc.gridheight = 1;
247    gbc.anchor = GridBagConstraints.EAST;
248    gbc.fill = GridBagConstraints.NONE;
249    gbc.weightx = 0.0;
250    gbc.weighty = 0.0;
251    cancelTask = Utilities.createButton(
252        INFO_CTRL_PANEL_CANCEL_TASK_BUTTON_LABEL.get());
253    cancelTask.setOpaque(false);
254    gbc.insets.left = 10;
255    add(cancelTask, gbc);
256
257    gbc.gridy ++;
258    gbc.weighty = 1.0;
259    gbc.fill = GridBagConstraints.VERTICAL;
260    add(Box.createVerticalGlue(), gbc);
261    cancelTask.addActionListener(new ActionListener()
262    {
263      @Override
264      public void actionPerformed(ActionEvent ev)
265      {
266        cancelTaskClicked();
267      }
268    });
269
270    gbc.gridy ++;
271    gbc.gridx = 0;
272    gbc.gridwidth = 2;
273    gbc.weightx = 0.0;
274    gbc.weighty = 0.0;
275    gbc.fill = GridBagConstraints.HORIZONTAL;
276    gbc.anchor = GridBagConstraints.NORTHWEST;
277    gbc.insets.top = 15;
278    gbc.insets.left = 0;
279    logsLabel = Utilities.createDefaultLabel(
280        INFO_CTRL_PANEL_TASK_LOG_LABEL.get());
281    logsLabel.setFont(ColorAndFontConstants.titleFont);
282    add(logsLabel, gbc);
283
284    logs = Utilities.createNonEditableTextArea(LocalizableMessage.EMPTY, 5, 50);
285    logs.setFont(ColorAndFontConstants.defaultFont);
286    gbc.fill = GridBagConstraints.BOTH;
287    gbc.weightx = 1.0;
288    gbc.weighty = 0.7;
289    gbc.gridy ++;
290    gbc.insets.top = 5;
291    logsScroll = Utilities.createScrollPane(logs);
292    add(logsScroll, gbc);
293    height = logs.getPreferredSize().height;
294    add(Box.createVerticalStrut(height), gbc);
295    logsScroll.setVisible(false);
296
297    gbc.anchor = GridBagConstraints.CENTER;
298    gbc.fill = GridBagConstraints.NONE;
299    gbc.weightx = 1.0;
300    gbc.weighty = 1.0;
301    noLogsLabel =
302      Utilities.createDefaultLabel(INFO_CTRL_PANEL_NO_TASK_SELECTED.get());
303    add(noLogsLabel, gbc);
304
305    gbc.fill = GridBagConstraints.BOTH;
306    gbc.weightx = 1.0;
307    gbc.weighty = 0.8;
308    gbc.gridy ++;
309    gbc.insets.left = 0;
310    gbc.insets.top = 15;
311    createDetailsPanel();
312    add(detailsPanel, gbc);
313
314    ListSelectionListener listener = new ListSelectionListener()
315    {
316      @Override
317      public void valueChanged(ListSelectionEvent ev)
318      {
319        tableSelected();
320      }
321    };
322    taskTable.getSelectionModel().addListSelectionListener(listener);
323    listener.valueChanged(null);
324  }
325
326  /** Creates the details panel. */
327  private void createDetailsPanel()
328  {
329    detailsPanel = new JPanel(new GridBagLayout());
330    detailsPanel.setOpaque(false);
331
332    GridBagConstraints gbc = new GridBagConstraints();
333    gbc.gridx = 1;
334    gbc.gridy = 1;
335    gbc.anchor = GridBagConstraints.NORTHWEST;
336    JLabel label = Utilities.createDefaultLabel(
337        INFO_CTRL_PANEL_TASK_SPECIFIC_DETAILS.get());
338    label.setFont(ColorAndFontConstants.titleFont);
339    detailsPanel.add(label, gbc);
340    gbc.gridy ++;
341    gbc.anchor = GridBagConstraints.CENTER;
342    gbc.fill = GridBagConstraints.NONE;
343    gbc.weightx = 1.0;
344    gbc.weighty = 1.0;
345    noDetailsLabel =
346      Utilities.createDefaultLabel(INFO_CTRL_PANEL_NO_TASK_SELECTED.get());
347    gbc.gridwidth = 2;
348    detailsPanel.add(noDetailsLabel, gbc);
349
350    detailsSubpanel = new JPanel(new GridBagLayout());
351    detailsSubpanel.setOpaque(false);
352    gbc.anchor = GridBagConstraints.NORTHWEST;
353    gbc.fill = GridBagConstraints.BOTH;
354    detailsPanel.add(Utilities.createBorderLessScrollBar(detailsSubpanel), gbc);
355
356    detailsPanel.add(
357        Box.createVerticalStrut(logs.getPreferredSize().height), gbc);
358  }
359
360  /** Method called when the table is selected. */
361  private void tableSelected()
362  {
363    List<TaskEntry> tasks = getSelectedTasks(true);
364    cancelTask.setEnabled(!tasks.isEmpty());
365
366    detailsSubpanel.removeAll();
367
368    tasks = getSelectedTasks(false);
369
370    boolean displayContents = false;
371    if (tasks.isEmpty())
372    {
373      noDetailsLabel.setText(INFO_CTRL_PANEL_NO_TASK_SELECTED.get().toString());
374      logsScroll.setVisible(false);
375      noLogsLabel.setText(INFO_CTRL_PANEL_NO_TASK_SELECTED.get().toString());
376      noLogsLabel.setVisible(true);
377    }
378    else if (tasks.size() > 1)
379    {
380      noDetailsLabel.setText(
381          INFO_CTRL_PANEL_MULTIPLE_TASKS_SELECTED.get().toString());
382      logsScroll.setVisible(false);
383      noLogsLabel.setText(
384          INFO_CTRL_PANEL_MULTIPLE_TASKS_SELECTED.get().toString());
385      noLogsLabel.setVisible(true);
386    }
387    else
388    {
389      TaskEntry taskEntry = tasks.iterator().next();
390      Map<LocalizableMessage,List<String>> taskSpecificAttrs =
391        taskEntry.getTaskSpecificAttributeValuePairs();
392      List<LocalizableMessage> lastLogMessages = taskEntry.getLogMessages();
393      if (!lastLogMessages.isEmpty())
394      {
395        StringBuilder sb = new StringBuilder();
396        for (LocalizableMessage msg : lastLogMessages)
397        {
398          if (sb.length() != 0)
399          {
400            sb.append("\n");
401          }
402          sb.append(msg);
403        }
404        logs.setText(sb.toString());
405      }
406      else
407      {
408        logs.setText("");
409      }
410      logsScroll.setVisible(true);
411      noLogsLabel.setVisible(false);
412
413      if (taskSpecificAttrs.isEmpty())
414      {
415        noDetailsLabel.setText(
416            INFO_CTRL_PANEL_NO_TASK_SPECIFIC_DETAILS.get().toString());
417      }
418      else
419      {
420        displayContents = true;
421        GridBagConstraints gbc = new GridBagConstraints();
422        gbc.gridy = 0;
423        gbc.fill = GridBagConstraints.NONE;
424        gbc.anchor = GridBagConstraints.NORTHWEST;
425        gbc.insets.top = 10;
426        for (LocalizableMessage label : taskSpecificAttrs.keySet())
427        {
428          List<String> values = taskSpecificAttrs.get(label);
429          gbc.gridx = 0;
430          gbc.insets.left = 10;
431          gbc.insets.right = 0;
432          detailsSubpanel.add(Utilities.createPrimaryLabel(
433              INFO_CTRL_PANEL_OPERATION_NAME_AS_LABEL.get(label)),
434              gbc);
435
436          gbc.gridx = 1;
437          gbc.insets.right = 10;
438
439          String s = joinAsString("\n", values);
440          detailsSubpanel.add(
441              Utilities.makeHtmlPane(s, ColorAndFontConstants.defaultFont),
442              gbc);
443
444          gbc.gridy ++;
445        }
446        gbc.gridx = 0;
447        gbc.gridwidth = 2;
448        gbc.weightx = 1.0;
449        gbc.weighty = 1.0;
450        gbc.fill = GridBagConstraints.BOTH;
451        detailsSubpanel.add(Box.createGlue(), gbc);
452      }
453    }
454    noDetailsLabel.setVisible(!displayContents);
455    revalidate();
456    repaint();
457  }
458
459  /**
460   * Creates a list with task descriptors.  This is done simply to have a good
461   * initial size for the table.
462   * @return a list with bogus task descriptors.
463   */
464  private Set<TaskEntry> createRandomTasksList()
465  {
466    Set<TaskEntry> list = new HashSet<>();
467    Random r = new Random();
468    int numberTasks = r.nextInt(10);
469    for (int i= 0; i<numberTasks; i++)
470    {
471      CustomSearchResult csr =
472        new CustomSearchResult("cn=mytask"+i+",cn=tasks");
473      String p = "ds-task-";
474      String[] attrNames =
475      {
476          p + "id",
477          p + "class-name",
478          p + "state",
479          p + "scheduled-start-time",
480          p + "actual-start-time",
481          p + "completion-time",
482          p + "dependency-id",
483          p + "failed-dependency-action",
484          p + "log-message",
485          p + "notify-on-error",
486          p + "notify-on-completion",
487          p + "ds-recurring-task-schedule"
488      };
489      String[] values =
490      {
491          "ID",
492          "TheClassName",
493          "TheState",
494          "Schedule Start Time",
495          "Actual Start Time",
496          "Completion Time",
497          "Dependency ID",
498          "Failed Dependency Action",
499          "Log LocalizableMessage.                              Should be pretty long"+
500          "Log LocalizableMessage.                              Should be pretty long"+
501          "Log LocalizableMessage.                              Should be pretty long"+
502          "Log LocalizableMessage.                              Should be pretty long"+
503          "Log LocalizableMessage.                              Should be pretty long",
504          "Notify On Error",
505          "Notify On Completion",
506          "Recurring Task Schedule"
507      };
508      for (int j=0; j < attrNames.length; j++)
509      {
510        Object o = values[j] + r.nextInt();
511        csr.set(attrNames[j], newArrayList(o));
512      }
513      try
514      {
515        Entry entry = getEntry(csr);
516        TaskEntry task = new TaskEntry(entry);
517        list.add(task);
518      }
519      catch (Throwable t)
520      {
521        logger.error(LocalizableMessage.raw("Error getting entry '"+csr.getDN()+"': "+t, t));
522      }
523    }
524    return list;
525  }
526
527  /**
528   * Creates a list with task descriptors.  This is done simply to have a good
529   * initial size for the table.
530   * @return a list with bogus task descriptors.
531   */
532  private Set<TaskEntry> createDummyTaskList()
533  {
534    Set<TaskEntry> list = new HashSet<>();
535    for (int i= 0; i<10; i++)
536    {
537      CustomSearchResult csr =
538        new CustomSearchResult("cn=mytask"+i+",cn=tasks");
539      String p = "ds-task-";
540      String[] attrNames =
541      {
542          p + "id",
543          p + "class-name",
544          p + "state",
545          p + "scheduled-start-time",
546          p + "actual-start-time",
547          p + "completion-time",
548          p + "dependency-id",
549          p + "failed-dependency-action",
550          p + "log-message",
551          p + "notify-on-error",
552          p + "notify-on-completion",
553          p + "ds-recurring-task-schedule"
554      };
555      String[] values =
556      {
557          "A very 29-backup - Sun Mar 29 00:00:00 MET 2009",
558          "A long task type",
559          "A very long task status",
560          "Schedule Start Time",
561          "Actual Start Time",
562          "Completion Time",
563          "Dependency ID",
564          "Failed Dependency Action",
565          "Log LocalizableMessage.                              Should be pretty long\n"+
566          "Log LocalizableMessage.                              Should be pretty long\n"+
567          "Log LocalizableMessage.                              Should be pretty long\n"+
568          "Log LocalizableMessage.                              Should be pretty long\n"+
569          "Log LocalizableMessage.                              Should be pretty long\n",
570          "Notify On Error",
571          "Notify On Completion",
572          "Recurring Task Schedule"
573      };
574      for (int j=0; j < attrNames.length; j++)
575      {
576        Object o = values[j];
577        csr.set(attrNames[j], newArrayList(o));
578      }
579      try
580      {
581        Entry entry = getEntry(csr);
582        TaskEntry task = new TaskEntry(entry);
583        list.add(task);
584      }
585      catch (Throwable t)
586      {
587        logger.error(LocalizableMessage.raw("Error getting entry '"+csr.getDN()+"': "+t, t));
588      }
589    }
590    return list;
591  }
592
593  private void cancelTaskClicked()
594  {
595    ArrayList<LocalizableMessage> errors = new ArrayList<>();
596    ProgressDialog dlg = new ProgressDialog(
597        Utilities.createFrame(),
598        Utilities.getParentDialog(this),
599        INFO_CTRL_PANEL_CANCEL_TASK_TITLE.get(), getInfo());
600    List<TaskEntry> tasks = getSelectedTasks(true);
601    CancelTaskTask newTask = new CancelTaskTask(getInfo(), dlg, tasks);
602    for (Task task : getInfo().getTasks())
603    {
604      task.canLaunch(newTask, errors);
605    }
606    if (errors.isEmpty())
607    {
608      boolean confirmed = displayConfirmationDialog(
609          INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
610          INFO_CTRL_PANEL_CANCEL_TASK_MSG.get());
611      if (confirmed)
612      {
613        launchOperation(newTask,
614            INFO_CTRL_PANEL_CANCELING_TASK_SUMMARY.get(),
615            INFO_CTRL_PANEL_CANCELING_TASK_COMPLETE.get(),
616            INFO_CTRL_PANEL_CANCELING_TASK_SUCCESSFUL.get(),
617            ERR_CTRL_PANEL_CANCELING_TASK_ERROR_SUMMARY.get(),
618            ERR_CTRL_PANEL_CANCELING_TASK_ERROR_DETAILS.get(),
619            null,
620            dlg);
621        dlg.setVisible(true);
622      }
623    }
624  }
625
626  /**
627   * Gets the Entry object equivalent to the provided CustomSearchResult.
628   * The method assumes that the schema in DirectoryServer has been initialized.
629   * @param csr the search result.
630   * @return the Entry object equivalent to the provided CustomSearchResult.
631   * @throws OpenDsException if there is an error parsing the DN or retrieving
632   * the attributes definition and objectclasses in the schema of the server.
633   * TODO: move somewhere better.
634   */
635  private static Entry getEntry(CustomSearchResult csr) throws OpenDsException
636  {
637    DN dn = DN.valueOf(csr.getDN());
638    Map<ObjectClass,String> objectClasses = new HashMap<>();
639    Map<AttributeType,List<Attribute>> userAttributes = new HashMap<>();
640    Map<AttributeType,List<Attribute>> operationalAttributes = new HashMap<>();
641
642    for (String wholeName : csr.getAttributeNames())
643    {
644      final AttributeDescription attrDesc = parseAttrDescription(wholeName);
645      final AttributeType attrType = attrDesc.getAttributeType();
646
647      // See if this is an objectclass or an attribute.  Then get the
648      // corresponding definition and add the value to the appropriate hash.
649      if (attrType.isObjectClass())
650      {
651        for (Object value : csr.getAttributeValues(attrType.getNameOrOID()))
652        {
653          String ocName = value.toString().trim();
654          objectClasses.put(DirectoryServer.getSchema().getObjectClass(ocName), ocName);
655        }
656      }
657      else
658      {
659        AttributeBuilder builder = new AttributeBuilder(attrDesc);
660        for (Object value : csr.getAttributeValues(attrType.getNameOrOID()))
661        {
662          ByteString bs;
663          if (value instanceof byte[])
664          {
665            bs = ByteString.wrap((byte[])value);
666          }
667          else
668          {
669            bs = ByteString.valueOfUtf8(value.toString());
670          }
671          builder.add(bs);
672        }
673
674        List<Attribute> attrList = builder.toAttributeList();
675        if (attrType.isOperational())
676        {
677          operationalAttributes.put(attrType, attrList);
678        }
679        else
680        {
681          userAttributes.put(attrType, attrList);
682        }
683      }
684    }
685
686    return new Entry(dn, objectClasses, userAttributes, operationalAttributes);
687  }
688
689  /**
690   * The main method to test this panel.
691   * @param args the arguments.
692   */
693  public static void main(String[] args)
694  {
695    // This is a hack to initialize configuration
696    new ConfigFromFile();
697    final ManageTasksPanel p = new ManageTasksPanel();
698    Thread t = new Thread(new Runnable()
699    {
700      @Override
701      public void run()
702      {
703        try
704        {
705          // To let the dialog to be displayed
706          Thread.sleep(5000);
707        }
708        catch (Throwable t)
709        {
710          t.printStackTrace();
711        }
712        while (p.isVisible())
713        {
714          try
715          {
716            SwingUtilities.invokeLater(new Runnable(){
717              @Override
718              public void run()
719              {
720                Set<TaskEntry> tasks = p.createRandomTasksList();
721                p.tableModel.setData(tasks);
722                boolean visible = p.tableModel.getRowCount() > 0;
723                if (visible)
724                {
725                  p.updateTableSizes();
726                }
727                p.tableModel.fireTableDataChanged();
728                p.lNoTasksFound.setVisible(!visible);
729                p.tableScroll.setVisible(visible);
730                p.cancelTask.setVisible(visible);
731              }
732            });
733            Thread.sleep(5000);
734          }
735          catch (Exception ex)
736          {
737            ex.printStackTrace();
738          }
739        }
740      }
741    });
742    t.start();
743
744    SwingUtilities.invokeLater(new Runnable(){
745      @Override
746      public void run()
747      {
748        GenericDialog dlg = new GenericDialog(Utilities.createFrame(), p);
749        dlg.setModal(true);
750        dlg.pack();
751        dlg.setVisible(true);
752      }
753    });
754    t = null;
755  }
756
757  /** Displays a dialog allowing the user to select which operations to display. */
758  private void operationViewClicked()
759  {
760    if (operationViewDlg == null)
761    {
762      operationViewPanel = MonitoringAttributesViewPanel.createMessageInstance(
763          tableModel.getAllAttributes());
764      operationViewDlg = new GenericDialog(Utilities.getFrame(this),
765          operationViewPanel);
766      Utilities.centerGoldenMean(operationViewDlg,
767          Utilities.getParentDialog(this));
768      operationViewDlg.setModal(true);
769    }
770    operationViewPanel.setSelectedAttributes(
771        tableModel.getDisplayedAttributes());
772    operationViewDlg.setVisible(true);
773    if (!operationViewPanel.isCanceled())
774    {
775      LinkedHashSet<LocalizableMessage> displayedAttributes =
776        operationViewPanel.getAttributes();
777      setAttributesToDisplay(displayedAttributes);
778      updateTableSizes();
779    }
780  }
781
782  @Override
783  public void configurationChanged(ConfigurationChangeEvent ev)
784  {
785    updateErrorPaneIfServerRunningAndAuthRequired(ev.getNewDescriptor(),
786        INFO_CTRL_PANEL_SCHEDULED_TASK_LIST_REQUIRES_SERVER_RUNNING.get(),
787        INFO_CTRL_PANEL_SCHEDULED_TASK_LIST_AUTHENTICATION.get());
788    ServerDescriptor server = ev.getNewDescriptor();
789    final Set<TaskEntry> tasks = server.getTaskEntries();
790    if (haveChanged(tasks))
791    {
792      SwingUtilities.invokeLater(new Runnable()
793      {
794        @Override
795        public void run()
796        {
797          Set<String> selectedIds = getSelectedIds();
798          tableModel.setData(tasks);
799          boolean visible = tableModel.getRowCount() > 0;
800          if (visible)
801          {
802            updateTableSizes();
803            setSelectedIds(selectedIds);
804          }
805          else
806          {
807            logsLabel.setVisible(false);
808            logsScroll.setVisible(false);
809          }
810          tableModel.fireTableDataChanged();
811          lNoTasksFound.setVisible(!visible &&
812              !errorPane.isVisible());
813          tableScroll.setVisible(visible);
814          cancelTask.setVisible(visible);
815          detailsPanel.setVisible(visible);
816        }
817      });
818    }
819  }
820
821  private boolean haveChanged(final Set<TaskEntry> tasks)
822  {
823    if (tableModel.getRowCount() != tasks.size())
824    {
825      return true;
826    }
827    for (int i=0; i<tableModel.getRowCount(); i++)
828    {
829      if (!tasks.contains(tableModel.get(i)))
830      {
831        return true;
832      }
833    }
834    return false;
835  }
836
837  private void updateTableSizes()
838  {
839    Utilities.updateTableSizes(taskTable, 5);
840    Utilities.updateScrollMode(tableScroll, taskTable);
841  }
842
843  private void setAttributesToDisplay(LinkedHashSet<LocalizableMessage> attributes)
844  {
845    Set<String> selectedIds = getSelectedIds();
846    tableModel.setAttributes(attributes);
847    tableModel.forceDataStructureChange();
848    setSelectedIds(selectedIds);
849  }
850
851  /** The specific menu bar of this panel. */
852  private class ManageTasksMenuBar extends MainMenuBar
853  {
854    private static final long serialVersionUID = 5051878116443370L;
855
856    /**
857     * Constructor.
858     * @param info the control panel info.
859     */
860    private ManageTasksMenuBar(ControlPanelInfo info)
861    {
862      super(info);
863    }
864
865    @Override
866    protected void addMenus()
867    {
868      add(createViewMenuBar());
869      add(createHelpMenuBar());
870    }
871
872    /**
873     * Creates the view menu bar.
874     * @return the view menu bar.
875     */
876    @Override
877    protected JMenu createViewMenuBar()
878    {
879      JMenu menu = Utilities.createMenu(
880          INFO_CTRL_PANEL_CONNECTION_HANDLER_VIEW_MENU.get(),
881          INFO_CTRL_PANEL_CONNECTION_HANDLER_VIEW_MENU_DESCRIPTION.get());
882      menu.setMnemonic(KeyEvent.VK_V);
883      final JMenuItem viewOperations = Utilities.createMenuItem(
884          INFO_CTRL_PANEL_TASK_ATTRIBUTES_VIEW.get());
885      menu.add(viewOperations);
886      viewOperations.addActionListener(new ActionListener()
887      {
888        @Override
889        public void actionPerformed(ActionEvent ev)
890        {
891          operationViewClicked();
892        }
893      });
894      return menu;
895    }
896  }
897
898  private Set<String> getSelectedIds()
899  {
900    Set<String> selectedIds = new HashSet<>();
901    int[] indexes = taskTable.getSelectedRows();
902    if (indexes != null)
903    {
904      for (int index : indexes)
905      {
906        TaskEntry taskEntry = tableModel.get(index);
907        selectedIds.add(taskEntry.getId());
908      }
909    }
910    return selectedIds;
911  }
912
913  private void setSelectedIds(Set<String> ids)
914  {
915    taskTable.getSelectionModel().clearSelection();
916    for (int i=0; i<tableModel.getRowCount(); i++)
917    {
918      TaskEntry taskEntry = tableModel.get(i);
919      if (ids.contains(taskEntry.getId()))
920      {
921        taskTable.getSelectionModel().addSelectionInterval(i, i);
922      }
923    }
924  }
925}