001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2008-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027
028package org.opends.guitools.controlpanel.ui;
029
030import static org.opends.messages.AdminToolMessages.*;
031
032import java.awt.Component;
033import java.awt.Dimension;
034import java.awt.GridBagConstraints;
035import java.awt.Insets;
036import java.awt.Point;
037import java.awt.Window;
038import java.awt.event.ActionEvent;
039import java.awt.event.ActionListener;
040import java.awt.event.ItemEvent;
041import java.awt.event.ItemListener;
042import java.util.ArrayList;
043import java.util.HashMap;
044
045import javax.swing.Box;
046import javax.swing.DefaultComboBoxModel;
047import javax.swing.ImageIcon;
048import javax.swing.JButton;
049import javax.swing.JComboBox;
050import javax.swing.JLabel;
051import javax.swing.JMenuItem;
052import javax.swing.JPopupMenu;
053import javax.swing.JScrollPane;
054import javax.swing.JSeparator;
055import javax.swing.JSplitPane;
056import javax.swing.JTree;
057import javax.swing.SwingUtilities;
058import javax.swing.border.EmptyBorder;
059import javax.swing.event.TreeSelectionEvent;
060import javax.swing.event.TreeSelectionListener;
061import javax.swing.tree.DefaultMutableTreeNode;
062import javax.swing.tree.DefaultTreeModel;
063import javax.swing.tree.TreeNode;
064import javax.swing.tree.TreePath;
065
066import org.opends.guitools.controlpanel.browser.IconPool;
067import org.opends.guitools.controlpanel.datamodel.AbstractIndexDescriptor;
068import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
069import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
070import org.opends.guitools.controlpanel.datamodel.IndexDescriptor;
071import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
072import org.opends.guitools.controlpanel.datamodel.VLVIndexDescriptor;
073import org.opends.guitools.controlpanel.event.*;
074import org.opends.guitools.controlpanel.task.DeleteIndexTask;
075import org.opends.guitools.controlpanel.task.Task;
076import org.opends.guitools.controlpanel.ui.components.CustomTree;
077import org.opends.guitools.controlpanel.ui.components.TreePanel;
078import org.opends.guitools.controlpanel.ui.nodes.AbstractIndexTreeNode;
079import org.opends.guitools.controlpanel.ui.nodes.CategoryTreeNode;
080import org.opends.guitools.controlpanel.ui.nodes.IndexTreeNode;
081import org.opends.guitools.controlpanel.ui.nodes.VLVIndexTreeNode;
082import org.opends.guitools.controlpanel.ui.renderer.TreeCellRenderer;
083import org.opends.guitools.controlpanel.util.Utilities;
084import org.opends.guitools.controlpanel.util.ViewPositions;
085import org.forgerock.i18n.LocalizableMessage;
086
087/**
088 * The pane that is displayed when the user clicks on 'Browse Indexes'.
089 *
090 */
091public class BrowseIndexPanel extends StatusGenericPanel
092implements IndexModifiedListener
093{
094  private static final long serialVersionUID = 4560020571983291585L;
095
096  private JComboBox backends;
097  private JLabel lNoBackendsFound;
098
099  private IndexBrowserRightPanel entryPane;
100  private TreePanel treePane;
101
102  private JScrollPane treeScroll;
103
104  private JButton newIndex;
105  private JButton newVLVIndex;
106
107  private CategoryTreeNode standardIndexes = new CategoryTreeNode(
108      INFO_CTRL_PANEL_INDEXES_CATEGORY_NODE.get());
109  private CategoryTreeNode vlvIndexes = new CategoryTreeNode(
110      INFO_CTRL_PANEL_VLV_INDEXES_CATEGORY_NODE.get());
111
112  private AbstractIndexDescriptor lastCreatedIndex;
113
114  private TreePath lastIndexTreePath;
115
116  private CategoryTreeNode[] categoryNodes = {
117      standardIndexes, vlvIndexes
118  };
119
120  private JMenuItem deleteMenuItem;
121
122  private GenericDialog newIndexDialog;
123  private NewIndexPanel newIndexPanel;
124  private GenericDialog newVLVIndexDialog;
125  private NewVLVIndexPanel newVLVIndexPanel;
126
127  private boolean ignoreSelectionEvents;
128
129  private boolean firstTreeRepopulate = true;
130
131  /**
132   * Default constructor.
133   *
134   */
135  public BrowseIndexPanel()
136  {
137    super();
138    createLayout();
139  }
140
141  /** {@inheritDoc} */
142  public boolean requiresBorder()
143  {
144    return false;
145  }
146
147  /** {@inheritDoc} */
148  public boolean requiresScroll()
149  {
150    return false;
151  }
152
153  /** {@inheritDoc} */
154  public void toBeDisplayed(boolean visible)
155  {
156    super.toBeDisplayed(visible);
157    Window w = Utilities.getParentDialog(this);
158    if (w instanceof GenericDialog)
159    {
160      ((GenericDialog)w).getRootPane().setDefaultButton(null);
161    }
162    else if (w instanceof GenericFrame)
163    {
164      ((GenericFrame)w).getRootPane().setDefaultButton(null);
165    }
166  }
167
168  /**
169   * Creates the layout of the panel (but the contents are not populated here).
170   */
171  private void createLayout()
172  {
173    setBackground(ColorAndFontConstants.greyBackground);
174    GridBagConstraints gbc = new GridBagConstraints();
175    gbc.anchor = GridBagConstraints.WEST;
176    gbc.gridx = 0;
177    gbc.gridy = 0;
178    gbc.gridwidth = 5;
179    gbc.weightx = 1.0;
180    gbc.fill = GridBagConstraints.BOTH;
181    addErrorPane(gbc);
182
183    gbc.gridy ++;
184    gbc.gridwidth = 1;
185    gbc.weightx = 0;
186    gbc.fill = GridBagConstraints.NONE;
187    gbc.gridx = 0;
188    gbc.fill = GridBagConstraints.HORIZONTAL;
189    gbc.insets = new Insets(10, 10, 0, 0);
190    JLabel lBackend =
191      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_BACKEND_LABEL.get());
192    add(lBackend, gbc);
193
194    backends = Utilities.createComboBox();
195    backends.setModel(new DefaultComboBoxModel(new String[]{}));
196    ItemListener comboListener = new ItemListener()
197    {
198      /** {@inheritDoc} */
199      public void itemStateChanged(ItemEvent ev)
200      {
201        if (!ignoreSelectionEvents &&
202            ev.getStateChange() == ItemEvent.SELECTED)
203        {
204          repopulateTree(treePane.getTree());
205        }
206      }
207    };
208    backends.addItemListener(comboListener);
209    gbc.insets.left = 5;
210    gbc.gridx ++;
211    add(backends, gbc);
212    lNoBackendsFound = Utilities.createDefaultLabel(
213        INFO_CTRL_PANEL_NO_BACKENDS_FOUND_LABEL.get());
214    add(lNoBackendsFound, gbc);
215    lNoBackendsFound.setVisible(false);
216
217    newIndex = Utilities.createButton(
218        INFO_CTRL_PANEL_NEW_INDEX_BUTTON_LABEL.get());
219    newIndex.setOpaque(false);
220    newIndex.addActionListener(new ActionListener()
221    {
222      /** {@inheritDoc} */
223      public void actionPerformed(ActionEvent ev)
224      {
225        newIndexClicked();
226      }
227    });
228    gbc.gridx ++;
229    gbc.insets.left = 10;
230    add(newIndex, gbc);
231
232    newVLVIndex = Utilities.createButton(
233        INFO_CTRL_PANEL_NEW_VLV_INDEX_BUTTON_LABEL.get());
234    newVLVIndex.setOpaque(false);
235    newVLVIndex.addActionListener(new ActionListener()
236    {
237      /** {@inheritDoc} */
238      public void actionPerformed(ActionEvent ev)
239      {
240        newVLVIndexClicked();
241      }
242    });
243    gbc.gridx ++;
244    gbc.insets.right = 10;
245    add(newVLVIndex, gbc);
246    gbc.gridx ++;
247    gbc.weightx = 1.0;
248    add(Box.createHorizontalGlue(), gbc);
249
250    gbc.insets = new Insets(10, 0, 0, 0);
251    gbc.gridx = 0;
252    gbc.gridy ++;
253    gbc.weightx = 1.0;
254    gbc.weighty = 1.0;
255    gbc.fill = GridBagConstraints.BOTH;
256    gbc.gridwidth = 5;
257    add(createSplitPane(), gbc);
258  }
259
260  /** {@inheritDoc} */
261  public LocalizableMessage getTitle()
262  {
263    return INFO_CTRL_PANEL_MANAGE_INDEXES_TITLE.get();
264  }
265
266  /** {@inheritDoc} */
267  public Component getPreferredFocusComponent()
268  {
269    return backends;
270  }
271
272  /** {@inheritDoc} */
273  public void closeClicked()
274  {
275    super.closeClicked();
276  }
277
278  /** {@inheritDoc} */
279  public void okClicked()
280  {
281    // No ok button
282  }
283
284  /** {@inheritDoc} */
285  public GenericDialog.ButtonType getButtonType()
286  {
287    return GenericDialog.ButtonType.CLOSE;
288  }
289
290  private Component createSplitPane()
291  {
292    JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
293    pane.setOpaque(true); //content panes must be opaque
294
295    treePane = new TreePanel();
296    Utilities.setBorder(treePane, new EmptyBorder(10, 0, 10, 0));
297
298    entryPane = new IndexBrowserRightPanel();
299    treeScroll = Utilities.createScrollPane(treePane);
300
301    entryPane.addIndexSelectionListener(new IndexSelectionListener()
302    {
303      /** {@inheritDoc} */
304      public void indexSelected(IndexSelectionEvent ev)
305      {
306        AbstractIndexDescriptor index = ev.getIndex();
307        TreeNode parentNode;
308        if (index instanceof IndexDescriptor)
309        {
310          parentNode = standardIndexes;
311        }
312        else
313        {
314          parentNode = vlvIndexes;
315        }
316        DefaultTreeModel model =
317          (DefaultTreeModel)treePane.getTree().getModel();
318        int n = model.getChildCount(parentNode);
319        for (int i=0; i<n; i++)
320        {
321          AbstractIndexTreeNode node =
322            (AbstractIndexTreeNode)model.getChild(parentNode, i);
323          if (node.getName().equals(index.getName()))
324          {
325            TreePath newSelectionPath = new TreePath(node.getPath());
326            treePane.getTree().setSelectionPath(newSelectionPath);
327            treePane.getTree().scrollPathToVisible(newSelectionPath);
328            break;
329          }
330        }
331      }
332    });
333
334
335//  Create a split pane
336    pane.setLeftComponent(treeScroll);
337    pane.setRightComponent(entryPane);
338    pane.setResizeWeight(0.0);
339
340    treePane.getTree().addTreeSelectionListener(new TreeSelectionListener()
341    {
342      /** {@inheritDoc} */
343      public void valueChanged(TreeSelectionEvent ev)
344      {
345        if (!ignoreSelectionEvents)
346        {
347          TreePath[] paths = treePane.getTree().getSelectionPaths();
348
349          if (entryPane.mustCheckUnsavedChanges())
350          {
351            ignoreSelectionEvents = true;
352            treePane.getTree().setSelectionPath(lastIndexTreePath);
353            switch (entryPane.checkUnsavedChanges())
354            {
355            case DO_NOT_SAVE:
356              break;
357            case SAVE:
358              break;
359            case CANCEL:
360              ignoreSelectionEvents = false;
361              return;
362            }
363            if (paths != null)
364            {
365              treePane.getTree().setSelectionPaths(paths);
366            }
367            else
368            {
369              treePane.getTree().clearSelection();
370            }
371            ignoreSelectionEvents = false;
372          }
373
374
375          boolean deletableElementsSelected = false;
376          boolean nonDeletableElementsSelected = false;
377          if (paths != null)
378          {
379            for (TreePath path : paths)
380            {
381              Object node = path.getLastPathComponent();
382              if (node instanceof IndexTreeNode)
383              {
384                IndexDescriptor index = ((IndexTreeNode)node).getIndex();
385                if (index.isDatabaseIndex())
386                {
387                  nonDeletableElementsSelected = true;
388                }
389                else
390                {
391                  deletableElementsSelected = true;
392                }
393              }
394              else if (node instanceof VLVIndexTreeNode)
395              {
396                deletableElementsSelected = true;
397              }
398            }
399          }
400          deleteMenuItem.setEnabled(deletableElementsSelected &&
401              !nonDeletableElementsSelected);
402          updateEntryPane();
403        }
404      }
405    });
406    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Tree root");
407    for (DefaultMutableTreeNode node : categoryNodes)
408    {
409      root.add(node);
410    }
411    DefaultTreeModel model = new DefaultTreeModel(root);
412    JTree tree = treePane.getTree();
413    tree.setModel(model);
414    tree.setRootVisible(false);
415    tree.setVisibleRowCount(20);
416    tree.expandPath(new TreePath(root));
417    tree.setCellRenderer(new IndexTreeCellRenderer());
418    addPopupMenu();
419
420    treeScroll.setPreferredSize(
421        new Dimension(2 * treeScroll.getPreferredSize().width,
422            8 * treeScroll.getPreferredSize().height));
423    entryPane.setBorder(getRightPanelBorder());
424    entryPane.setPreferredSize(
425        new Dimension((treeScroll.getPreferredSize().width * 5) / 2,
426        treeScroll.getPreferredSize().height));
427    pane.setDividerLocation(treeScroll.getPreferredSize().width);
428    entryPane.displayVoid();
429    return pane;
430  }
431
432  /** {@inheritDoc} */
433  public void setInfo(ControlPanelInfo info)
434  {
435    super.setInfo(info);
436    treePane.setInfo(info);
437    entryPane.setInfo(info);
438    info.addIndexModifiedListener(this);
439  }
440
441  /** {@inheritDoc} */
442  public void configurationChanged(ConfigurationChangeEvent ev)
443  {
444    ignoreSelectionEvents = true;
445    ServerDescriptor desc = ev.getNewDescriptor();
446    updateSimpleBackendComboBoxModel(backends, lNoBackendsFound,
447        desc);
448    refreshContents(desc);
449  }
450
451  /**
452   * Adds a pop up menu.
453   *
454   */
455  private void addPopupMenu()
456  {
457    final JPopupMenu popup = new JPopupMenu();
458    JMenuItem menuItem = Utilities.createMenuItem(
459        INFO_CTRL_PANEL_NEW_INDEX_MENU.get());
460    menuItem.addActionListener(new ActionListener()
461    {
462      /** {@inheritDoc} */
463      public void actionPerformed(ActionEvent ev)
464      {
465        newIndexClicked();
466      }
467    });
468    popup.add(menuItem);
469    menuItem = Utilities.createMenuItem(
470        INFO_CTRL_PANEL_NEW_VLV_INDEX_MENU.get());
471    menuItem.addActionListener(new ActionListener()
472    {
473      /** {@inheritDoc} */
474      public void actionPerformed(ActionEvent ev)
475      {
476        newVLVIndexClicked();
477      }
478    });
479    popup.add(menuItem);
480    popup.add(new JSeparator());
481    deleteMenuItem = Utilities.createMenuItem(
482        INFO_CTRL_PANEL_DELETE_INDEX_MENU.get());
483    deleteMenuItem.addActionListener(new ActionListener()
484    {
485      /** {@inheritDoc} */
486      public void actionPerformed(ActionEvent ev)
487      {
488        deleteClicked();
489      }
490    });
491    popup.add(deleteMenuItem);
492    deleteMenuItem.setEnabled(false);
493
494    ((CustomTree)treePane.getTree()).setPopupMenu(popup);
495  }
496
497  /**
498   * Refresh the contents of the tree.
499   * @param desc the descriptor containing the index configuration.
500   */
501  private void refreshContents(final ServerDescriptor desc)
502  {
503    SwingUtilities.invokeLater(new Runnable()
504    {
505      /** {@inheritDoc} */
506      public void run()
507      {
508        repopulateTree(treePane.getTree());
509        ignoreSelectionEvents = false;
510        boolean userBackendsDefined = backends.getModel().getSize() > 0;
511        newIndex.setEnabled(userBackendsDefined);
512        newVLVIndex.setEnabled(userBackendsDefined);
513        if (!userBackendsDefined)
514        {
515          entryPane.displayVoid();
516          updateErrorPane(errorPane,
517              ERR_CTRL_PANEL_NO_BACKENDS_FOUND_TITLE.get(),
518              ColorAndFontConstants.errorTitleFont,
519              ERR_CTRL_PANEL_NO_BACKENDS_FOUND_DETAILS.get(),
520              ColorAndFontConstants.defaultFont);
521          errorPane.setVisible(true);
522        }
523        else
524        {
525          errorPane.setVisible(false);
526        }
527      }
528    });
529  }
530
531  /** {@inheritDoc} */
532  public void indexModified(IndexModifiedEvent ev)
533  {
534    refreshContents(getInfo().getServerDescriptor());
535  }
536
537  /** {@inheritDoc} */
538  public void backendIndexesModified(IndexModifiedEvent ev)
539  {
540    refreshContents(getInfo().getServerDescriptor());
541  }
542
543  /**
544   * Repopulates the contents of the tree.
545   * @param tree the tree to be repopulated.
546   */
547  private void repopulateTree(JTree tree)
548  {
549    ignoreSelectionEvents = true;
550
551    final Point currentPosition = treeScroll.getViewport().getViewPosition();
552    DefaultMutableTreeNode root = getRoot(tree);
553
554    TreePath path = tree.getSelectionPath();
555    DefaultMutableTreeNode lastSelectedNode = null;
556    if (path != null)
557    {
558      lastSelectedNode = (DefaultMutableTreeNode)path.getLastPathComponent();
559    }
560    TreePath newSelectionPath = null;
561
562    BackendDescriptor backend = null;
563    String backendName = (String)backends.getSelectedItem();
564    if (backendName != null)
565    {
566      for (BackendDescriptor b : getInfo().getServerDescriptor().getBackends())
567      {
568        if (b.getBackendID().equalsIgnoreCase(backendName))
569        {
570          backend = b;
571          break;
572        }
573      }
574    }
575
576    ArrayList<ArrayList<? extends AbstractIndexTreeNode>> nodes = new ArrayList<>();
577    ArrayList<IndexTreeNode> standardIndexNodes = new ArrayList<>();
578    ArrayList<VLVIndexTreeNode> vlvIndexNodes = new ArrayList<>();
579    nodes.add(standardIndexNodes);
580    nodes.add(vlvIndexNodes);
581
582    if (backend != null)
583    {
584      for (IndexDescriptor index : backend.getIndexes())
585      {
586        standardIndexNodes.add(new IndexTreeNode(index.getName(), index));
587      }
588      for (VLVIndexDescriptor index : backend.getVLVIndexes())
589      {
590        vlvIndexNodes.add(new VLVIndexTreeNode(index.getName(), index));
591      }
592    }
593
594
595    DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
596    int i = 0;
597    int positionUnderRoot = 0;
598    for (DefaultMutableTreeNode parent : categoryNodes)
599    {
600      if (nodes.get(i).isEmpty())
601      {
602        if (root.getIndex(parent) != -1)
603        {
604          model.removeNodeFromParent(parent);
605          parent.removeAllChildren();
606        }
607      }
608      else
609      {
610        boolean expand = true;
611        if (root.getIndex(parent) == -1)
612        {
613          model.insertNodeInto(parent, root, positionUnderRoot);
614        }
615        else
616        {
617          expand = tree.isExpanded(new TreePath(parent)) || parent.getChildCount() == 0;
618          parent.removeAllChildren();
619        }
620        for (AbstractIndexTreeNode node : nodes.get(i))
621        {
622          parent.add(node);
623          if (newSelectionPath == null &&
624              (lastSelectedNode != null || lastCreatedIndex != null))
625          {
626            if (lastCreatedIndex != null)
627            {
628              if (node instanceof IndexTreeNode &&
629                  lastCreatedIndex instanceof IndexDescriptor)
630              {
631                if (node.getName().equals(lastCreatedIndex.getName()))
632                {
633                  newSelectionPath = new TreePath(node.getPath());
634                  lastCreatedIndex = null;
635                }
636              }
637              else if (node instanceof VLVIndexTreeNode
638                  && lastCreatedIndex instanceof VLVIndexDescriptor
639                  && node.getName().equals(lastCreatedIndex.getName()))
640              {
641                newSelectionPath = new TreePath(node.getPath());
642                lastCreatedIndex = null;
643              }
644            }
645            else if (node.getName().equals(lastSelectedNode.getUserObject()))
646            {
647              newSelectionPath = new TreePath(node.getPath());
648            }
649          }
650        }
651        model.nodeStructureChanged(parent);
652        if (expand)
653        {
654          tree.expandPath(new TreePath(parent.getPath()));
655        }
656        positionUnderRoot++;
657      }
658      i++;
659    }
660
661    if (newSelectionPath == null && firstTreeRepopulate)
662    {
663      newSelectionPath = new TreePath(standardIndexes.getPath());
664    }
665    if (newSelectionPath != null)
666    {
667      tree.setSelectionPath(newSelectionPath);
668      tree.scrollPathToVisible(newSelectionPath);
669    }
670
671    updateEntryPane();
672
673    SwingUtilities.invokeLater(new Runnable()
674    {
675      public void run()
676      {
677        if (firstTreeRepopulate)
678        {
679          treeScroll.getViewport().setViewPosition(new Point(0, 0));
680        }
681        else
682        {
683          treeScroll.getViewport().setViewPosition(currentPosition);
684        }
685      }
686    });
687    firstTreeRepopulate = false;
688    ignoreSelectionEvents = false;
689  }
690
691  /**
692   * Updates the contents of the right panel.
693   *
694   */
695  private void updateEntryPane()
696  {
697    ViewPositions pos = Utilities.getViewPositions(entryPane);
698    TreePath[] paths = treePane.getTree().getSelectionPaths();
699    TreePath path = null;
700    if (paths != null && paths.length == 1)
701    {
702      path = paths[0];
703    }
704    lastIndexTreePath = path;
705    if (path != null)
706    {
707      Object node = path.getLastPathComponent();
708      if (node instanceof IndexTreeNode)
709      {
710        entryPane.updateStandardIndex(
711            ((IndexTreeNode)node).getIndex());
712      }
713      else if (node instanceof VLVIndexTreeNode)
714      {
715        entryPane.updateVLVIndex(((VLVIndexTreeNode)node).getIndex());
716      }
717      else if (node == standardIndexes)
718      {
719        String backendName = (String)backends.getSelectedItem();
720        entryPane.updateBackendIndexes(backendName);
721      }
722      else if (node == vlvIndexes)
723      {
724        String backendName = (String)backends.getSelectedItem();
725        entryPane.updateBackendVLVIndexes(backendName);
726      }
727      else
728      {
729        entryPane.displayVoid();
730      }
731    }
732    else
733    {
734      if (paths != null && paths.length > 1)
735      {
736        entryPane.displayMultiple();
737      }
738      else
739      {
740        entryPane.displayVoid();
741      }
742    }
743    Utilities.updateViewPositions(pos);
744  }
745
746  private DefaultMutableTreeNode getRoot(JTree tree)
747  {
748    return (DefaultMutableTreeNode)tree.getModel().getRoot();
749  }
750
751  private void newIndexClicked()
752  {
753    if (newIndexPanel == null)
754    {
755      newIndexPanel =
756        new NewIndexPanel((String)backends.getSelectedItem(),
757          Utilities.getParentDialog(this));
758      newIndexPanel.setInfo(getInfo());
759      newIndexDialog = new GenericDialog(null, newIndexPanel);
760      Utilities.centerGoldenMean(newIndexDialog,
761          Utilities.getParentDialog(this));
762      newIndexPanel.addConfigurationElementCreatedListener(
763          new ConfigurationElementCreatedListener()
764          {
765            public void elementCreated(ConfigurationElementCreatedEvent ev)
766            {
767              Object o = ev.getConfigurationObject();
768              if (o instanceof AbstractIndexDescriptor)
769              {
770                lastCreatedIndex = (AbstractIndexDescriptor)o;
771              }
772            }
773          });
774    }
775    else if (!newIndexDialog.isVisible())
776    {
777      String backendID = (String)backends.getSelectedItem();
778      for (BackendDescriptor backend :
779        getInfo().getServerDescriptor().getBackends())
780      {
781        if (backend.getBackendID().equalsIgnoreCase(backendID))
782        {
783          newIndexPanel.update(backend);
784          break;
785        }
786      }
787    }
788    newIndexDialog.setVisible(true);
789  }
790
791  private void newVLVIndexClicked()
792  {
793    if (newVLVIndexPanel == null)
794    {
795      newVLVIndexPanel =
796        new NewVLVIndexPanel((String)backends.getSelectedItem(),
797          Utilities.getParentDialog(this));
798      newVLVIndexPanel.setInfo(getInfo());
799      newVLVIndexDialog = new GenericDialog(null, newVLVIndexPanel);
800      Utilities.centerGoldenMean(newVLVIndexDialog,
801          Utilities.getParentDialog(this));
802      newVLVIndexPanel.addConfigurationElementCreatedListener(
803          new ConfigurationElementCreatedListener()
804          {
805            /** {@inheritDoc} */
806            public void elementCreated(ConfigurationElementCreatedEvent ev)
807            {
808              Object o = ev.getConfigurationObject();
809              if (o instanceof AbstractIndexDescriptor)
810              {
811                lastCreatedIndex = (AbstractIndexDescriptor)o;
812              }
813            }
814          });
815    }
816    else if (!newVLVIndexDialog.isVisible())
817    {
818      String backendID = (String)backends.getSelectedItem();
819      for (BackendDescriptor backend :
820        getInfo().getServerDescriptor().getBackends())
821      {
822        if (backend.getBackendID().equalsIgnoreCase(backendID))
823        {
824          newVLVIndexPanel.update(backend);
825          break;
826        }
827      }
828    }
829    newVLVIndexDialog.setVisible(true);
830  }
831
832  private void deleteClicked()
833  {
834    ArrayList<LocalizableMessage> errors = new ArrayList<>();
835    TreePath[] paths = treePane.getTree().getSelectionPaths();
836    ArrayList<AbstractIndexDescriptor> indexesToDelete = new ArrayList<>();
837    ArrayList<String> indexesNames = new ArrayList<>();
838    if (paths != null)
839    {
840      for (TreePath path : paths)
841      {
842        Object node = path.getLastPathComponent();
843        if (node instanceof IndexTreeNode)
844        {
845          indexesToDelete.add(((IndexTreeNode)node).getIndex());
846        }
847        else if (node instanceof VLVIndexTreeNode)
848        {
849          indexesToDelete.add(((VLVIndexTreeNode)node).getIndex());
850        }
851      }
852    }
853    else
854    {
855      errors.add(ERR_CTRL_PANEL_NO_INDEX_SELECTED.get());
856    }
857    for (AbstractIndexDescriptor index : indexesToDelete)
858    {
859      indexesNames.add(index.getName());
860    }
861    String nameLabel = Utilities.getStringFromCollection(indexesNames, ", ");
862    String backendName = indexesToDelete.get(0).getBackend().getBackendID();
863    if (errors.isEmpty())
864    {
865      ProgressDialog dlg = new ProgressDialog(
866          Utilities.createFrame(),
867          Utilities.getParentDialog(this),
868          INFO_CTRL_PANEL_DELETE_INDEXES_TITLE.get(), getInfo());
869      DeleteIndexTask newTask = new DeleteIndexTask(getInfo(), dlg,
870          indexesToDelete);
871      for (Task task : getInfo().getTasks())
872      {
873        task.canLaunch(newTask, errors);
874      }
875      if (errors.isEmpty())
876      {
877        if (displayConfirmationDialog(
878            INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
879            INFO_CTRL_PANEL_CONFIRMATION_INDEXES_DELETE_DETAILS.get(nameLabel,
880                backendName)))
881        {
882          launchOperation(newTask,
883              INFO_CTRL_PANEL_DELETING_INDEXES_SUMMARY.get(),
884              INFO_CTRL_PANEL_DELETING_INDEXES_COMPLETE.get(),
885              INFO_CTRL_PANEL_DELETING_INDEXES_SUCCESSFUL.get(nameLabel, backendName),
886              ERR_CTRL_PANEL_DELETING_INDEXES_ERROR_SUMMARY.get(),
887              ERR_CTRL_PANEL_DELETING_INDEXES_ERROR_DETAILS.get(nameLabel),
888              null,
889              dlg);
890          dlg.setVisible(true);
891        }
892      }
893    }
894    if (!errors.isEmpty())
895    {
896      displayErrorDialog(errors);
897    }
898  }
899
900  private HashMap<Object, ImageIcon> hmCategoryImages = new HashMap<>();
901  private HashMap<Class<?>, ImageIcon> hmImages = new HashMap<>();
902  {
903    Object[] nodes = {standardIndexes, vlvIndexes};
904    String[] paths = {"ds-idx-folder.png", "ds-vlv-idx-folder.png"};
905    for (int i=0; i<nodes.length; i++)
906    {
907      hmCategoryImages.put(nodes[i],
908          Utilities.createImageIcon(IconPool.IMAGE_PATH+"/"+paths[i]));
909    }
910    Class<?>[] classes = {IndexTreeNode.class, VLVIndexTreeNode.class};
911    String[] ocPaths = {"ds-idx.png", "ds-vlv-idx.png"};
912    for (int i=0; i<classes.length; i++)
913    {
914      hmImages.put(classes[i],
915          Utilities.createImageIcon(IconPool.IMAGE_PATH+"/"+ocPaths[i]));
916    }
917  }
918
919  /** Specific class used to render the nodes in the tree.  It uses specific icons for the nodes. */
920  protected class IndexTreeCellRenderer extends TreeCellRenderer
921  {
922    private ImageIcon readOnlyIndexIcon =
923      Utilities.createImageIcon(IconPool.IMAGE_PATH+"/ds-idx-ro.png");
924
925    private static final long serialVersionUID = -6953837045703643228L;
926
927    /** {@inheritDoc} */
928    public Component getTreeCellRendererComponent(JTree tree, Object value,
929        boolean isSelected, boolean isExpanded, boolean isLeaf, int row,
930        boolean hasFocus)
931    {
932      super.getTreeCellRendererComponent(tree, value, isSelected, isExpanded,
933          isLeaf, row, hasFocus);
934      setIcon(getIcon(value));
935      return this;
936    }
937
938    private ImageIcon getIcon(Object value)
939    {
940      ImageIcon icon = null;
941      if (value instanceof IndexTreeNode
942          && ((IndexTreeNode)value).getIndex().isDatabaseIndex())
943      {
944        icon = readOnlyIndexIcon;
945      }
946      if (icon == null)
947      {
948        icon = hmImages.get(value.getClass());
949        if (icon == null)
950        {
951          icon = hmCategoryImages.get(value);
952        }
953      }
954      return icon;
955    }
956  }
957}