private ToolAdapterOperatorDescriptor requestSelection() {
   ToolAdapterOperatorDescriptor selected = null;
   int selectedRow = operatorsTable.getSelectedRow();
   if (selectedRow >= 0) {
     selected = ((OperatorsTableModel) operatorsTable.getModel()).getObjectAt(selectedRow);
   } else {
     SnapDialogs.showWarning(Bundle.MessageNoSelection_Text());
   }
   return selected;
 }
 public static void showDialog(AppContext appContext, String helpID) {
   if (instance == null) {
     instance = new ToolAdaptersManagementDialog(appContext, Bundle.Dialog_Title(), helpID);
   }
   instance.show();
 }
  private JTable createPropertiesPanel() {
    DefaultTableModel model =
        new DefaultTableModel(1, 2) {
          @Override
          public boolean isCellEditable(int row, int column) {
            return column == 1;
          }
        };
    model.setValueAt(Bundle.PathLabel_Text(), 0, 0);
    model.setValueAt(ToolAdapterIO.getUserAdapterPath(), 0, 1);
    model.addTableModelListener(
        l -> {
          String newPath = model.getValueAt(0, 1).toString();
          File path = new File(newPath);
          if (!path.exists()
              && SnapDialogs.Answer.YES
                  == SnapDialogs.requestDecision(
                      "Path does not exist",
                      "The path you have entered does not exist.\nDo you want to create it?",
                      true,
                      "Don't ask me in the future")) {
            if (!path.mkdirs()) {
              SnapDialogs.showError("Path could not be created!");
            }
          }
          if (path.exists()) {
            File oldPath = ToolAdapterIO.getUserAdapterPath();
            ToolAdapterOperatorDescriptor[] operatorDescriptors =
                ToolAdapterActionRegistrar.getActionMap()
                    .values()
                    .toArray(
                        new ToolAdapterOperatorDescriptor
                            [ToolAdapterActionRegistrar.getActionMap().values().size()]);
            for (ToolAdapterOperatorDescriptor descriptor : operatorDescriptors) {
              ToolAdapterActionRegistrar.removeOperatorMenu(descriptor);
            }
            ToolAdapterIO.setAdaptersPath(Paths.get(newPath));
            if (!newPath.equals(oldPath.getAbsolutePath())) {
              Collection<ToolAdapterOpSpi> toolAdapterOpSpis =
                  ToolAdapterIO.searchAndRegisterAdapters();
              for (ToolAdapterOpSpi spi : toolAdapterOpSpis) {
                ToolAdapterActionRegistrar.registerOperatorMenu(
                    (ToolAdapterOperatorDescriptor) spi.getOperatorDescriptor());
              }
              refreshContent();
            }
          }
        });
    JTable table = new JTable(model);
    TableColumn labelColumn = table.getColumnModel().getColumn(0);
    labelColumn.setPreferredWidth((CHECK_COLUMN_WIDTH + LABEL_COLUMN_WIDTH) / 2);
    TableColumn pathColumn = table.getColumnModel().getColumn(1);
    pathColumn.setPreferredWidth(COLUMN_WIDTH);
    pathColumn.setCellEditor(new FileChooserCellEditor());
    table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
    table.setRowHeight(PATH_ROW_HEIGHT);
    table.setBorder(BorderFactory.createLineBorder(Color.black));
    table.addFocusListener(
        new FocusListener() {
          @Override
          public void focusGained(FocusEvent e) {}

          @Override
          public void focusLost(FocusEvent e) {
            Object source = e.getSource();
            if (!table.equals(source)) {
              table.editingCanceled(new ChangeEvent(source));
              table.clearSelection();
            }
          }
        });
    return table;
  }
  private JPanel createButtonsPanel() {
    JPanel panel = new JPanel(new SpringLayout());

    /** New adapter button */
    panel.add(
        createButton(
            "New",
            TangoIcons.actions_document_new(TangoIcons.Res.R22),
            Bundle.ToolTipNewOperator_Text(),
            e -> {
              ToolAdapterOperatorDescriptor newOperatorSpi =
                  new ToolAdapterOperatorDescriptor(
                      ToolAdapterConstants.OPERATOR_NAMESPACE + "NewOperator",
                      ToolAdapterOp.class,
                      "NewOperator",
                      null,
                      null,
                      null,
                      null,
                      null,
                      null);
              ToolAdapterEditorDialog dialog =
                  new ToolAdapterEditorDialog(appContext, newOperatorSpi, true);
              dialog.show();
              refreshContent();
            }));
    /** Duplicate adapter button */
    panel.add(
        createButton(
            "Copy",
            TangoIcons.actions_edit_copy(TangoIcons.Res.R22),
            Bundle.ToolTipCopyOperator_Text(),
            e -> {
              ToolAdapterOperatorDescriptor operatorDesc = requestSelection();
              if (operatorDesc != null) {
                String opName = operatorDesc.getName();
                int newNameIndex = 0;
                while (GPF.getDefaultInstance().getOperatorSpiRegistry().getOperatorSpi(opName)
                    != null) {
                  newNameIndex++;
                  opName =
                      operatorDesc.getName()
                          + ToolAdapterConstants.OPERATOR_GENERATED_NAME_SEPARATOR
                          + newNameIndex;
                }
                ToolAdapterEditorDialog dialog =
                    new ToolAdapterEditorDialog(appContext, operatorDesc, newNameIndex);
                dialog.show();
                refreshContent();
              }
            }));
    /** Edit adapter button */
    panel.add(
        createButton(
            "Edit",
            TangoIcons.apps_accessories_text_editor(TangoIcons.Res.R22),
            Bundle.ToolTipEditOperator_Text(),
            e -> {
              ToolAdapterOperatorDescriptor operatorDesc = requestSelection();
              if (operatorDesc != null) {
                ToolAdapterEditorDialog dialog =
                    new ToolAdapterEditorDialog(appContext, operatorDesc, false);
                dialog.show();
                refreshContent();
              }
            }));
    /** Delete adapter button */
    panel.add(
        createButton(
            "Delete",
            TangoIcons.actions_edit_clear(TangoIcons.Res.R22),
            Bundle.ToolTipDeleteOperator_Text(),
            e -> {
              ToolAdapterOperatorDescriptor operatorDescriptor = requestSelection();
              if (operatorDescriptor != null) {
                if (SnapDialogs.Answer.YES
                    == SnapDialogs.requestDecision(
                        Bundle.MessageConfirmRemoval_TitleText(),
                        Bundle.MessageConfirmRemoval_Text(),
                        true,
                        Bundle.MessageConfirmRemovalDontAsk_Text())) {
                  if (operatorDescriptor.isFromPackage()) {
                    SnapDialogs.showWarning(
                        String.format(
                            Bundle.MessagePackageModules_Text(), operatorDescriptor.getName()));
                  } else {
                    ToolAdapterActionRegistrar.removeOperatorMenu(operatorDescriptor);
                    ToolAdapterIO.removeOperator(operatorDescriptor);
                  }
                  refreshContent();
                }
              }
            }));
    /** Execute adapter button */
    panel.add(
        createButton(
            "Run",
            TangoIcons.actions_media_playback_start(TangoIcons.Res.R22),
            Bundle.ToolTipExecuteOperator_Text(),
            e -> {
              ToolAdapterOperatorDescriptor operatorDesc = requestSelection();
              if (operatorDesc != null) {
                // close();
                final ToolAdapterExecutionDialog operatorDialog =
                    new ToolAdapterExecutionDialog(
                        operatorDesc, appContext, operatorDesc.getLabel());
                operatorDialog.show();
              }
            }));

    makeCompactGrid(panel, 1, 5, 0, 0, DEFAULT_PADDING, DEFAULT_PADDING);

    return panel;
  }