@After
 protected void tearDown() throws Exception {
   GPF.getDefaultInstance().getOperatorSpiRegistry().removeOperatorSpi(operatorSpi1);
   GPF.getDefaultInstance().getOperatorSpiRegistry().removeOperatorSpi(operatorSpi2);
   GPF.getDefaultInstance().getOperatorSpiRegistry().removeOperatorSpi(graphOpSpiOneNode);
   GPF.getDefaultInstance().getOperatorSpiRegistry().removeOperatorSpi(graphOpSpiTwoNodes);
   GPF.getDefaultInstance().getOperatorSpiRegistry().removeOperatorSpi(usesOtherGraphSpi);
 }
 @Before
 protected void setUp() throws Exception {
   GPF.getDefaultInstance().getOperatorSpiRegistry().addOperatorSpi(operatorSpi1);
   GPF.getDefaultInstance().getOperatorSpiRegistry().addOperatorSpi(operatorSpi2);
   graphOpSpiOneNode = createOp2GraphSpi();
   graphOpSpiTwoNodes = createSourcelessOp1Op2GraphSpi();
   usesOtherGraphSpi = createUsesOtherGraphSpi();
   assertTrue(GPF.getDefaultInstance().getOperatorSpiRegistry().addOperatorSpi(graphOpSpiOneNode));
   assertTrue(
       GPF.getDefaultInstance().getOperatorSpiRegistry().addOperatorSpi(graphOpSpiTwoNodes));
   GPF.getDefaultInstance().getOperatorSpiRegistry().addOperatorSpi(usesOtherGraphSpi);
 }
  private static boolean registerModule(
      Path pythonModuleRoot, String pythonModuleName, final String pythonClassName) {

    String pythonModuleRelPath = pythonModuleName.replace('.', '/');

    Path pythonModuleFile = pythonModuleRoot.resolve(pythonModuleRelPath + ".py");
    if (!Files.exists(pythonModuleFile)) {
      LOG.severe(String.format("Missing Python module '%s'", pythonModuleFile.toUri()));
      return false;
    }

    Path pythonInfoXmlFile = pythonModuleRoot.resolve(pythonModuleRelPath + "-info.xml");
    if (!Files.exists(pythonInfoXmlFile)) {
      LOG.warning(
          String.format(
              "Missing operator metadata file '%s'. Using defaults.", pythonInfoXmlFile.toUri()));
    }

    DefaultOperatorDescriptor operatorDescriptor =
        createOperatorDescriptor(pythonInfoXmlFile, pythonModuleName);
    File pythonModuleRootFile = FileUtils.toFile(pythonModuleRoot);

    PyOperatorSpi operatorSpi =
        new PyOperatorSpi(operatorDescriptor) {

          @Override
          public Operator createOperator() throws OperatorException {
            PyOperator pyOperator = (PyOperator) super.createOperator();

            pyOperator.setParameterDefaultValues();
            pyOperator.setPythonModulePath(pythonModuleRootFile.getPath());
            pyOperator.setPythonModuleName(pythonModuleName);
            pyOperator.setPythonClassName(pythonClassName);
            return pyOperator;
          }
        };

    String operatorName =
        operatorDescriptor.getAlias() != null
            ? operatorDescriptor.getAlias()
            : operatorDescriptor.getName();
    GPF.getDefaultInstance().getOperatorSpiRegistry().addOperatorSpi(operatorName, operatorSpi);
    LOG.info(
        String.format(
            "Python operator '%s' registered (Python module: '%s', class: '%s', root: '%s')",
            operatorName, pythonModuleName, pythonClassName, pythonModuleRootFile));
    return true;
  }
  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;
  }