protected void deleteCurrent() {
      int num_logs_deleted = 0;
      Set<Group> groups_changed = new HashSet<>();

      for (TreePath tp : display.logTree.getSelectionPaths()) {
        if (tp.getPathCount() == 3) {
          Group group = (Group) tp.getPath()[1];
          LogReference reference = (LogReference) tp.getLastPathComponent();

          Debug.warn("deleting {%s} from {%s}", reference, group);
          group.remove(reference);

          ++num_logs_deleted;
          groups_changed.add(group);
        } else {
          Debug.warn("cannot delete {%s}", tp.getLastPathComponent());
        }
      }

      for (Group group : groups_changed) {
        TreeModelEvent removeEvent = new TreeModelEvent(this, new Object[] {this, group});

        for (TreeModelListener listener : listeners) listener.treeStructureChanged(removeEvent);
      }

      ToolMessage.displayAndPrint("deleted %d logs", num_logs_deleted);
    }
  private void controlConnectAction() {
    if (robot == null) {
      assert (display.connectButton.getText().equals("connect"));
    } else {
      assert (display.connectButton.getText().equals("disconnect"));
      Debug.info("trying to kill %s", robot);

      final RobotConnection _robot = robot;
      Center.addEvent(
          new Center.EventRunnable() {
            @Override
            protected void run() {
              _robot.kill();
            }
          });

      return;
    }

    String address = (String) display.robotAddressBox.getSelectedItem();
    if (address == null) {
      ToolMessage.displayError("choose valid address");
      return;
    }

    address = address.trim();

    if (display.localCheckBox.isSelected() && !address.endsWith(".local")) {
      address += ".local";
    }

    display.connectButton.setEnabled(false);
    Center.addEvent(new ControlConnectRunnable(address));
  }
  private void controlLoadAction() {
    if (robot == null) {
      Path selected = (Path) display.pathBox.getSelectedItem();
      if (selected == null) {
        Debug.error("null path");
        ToolMessage.display("load action: null path", Color.RED);
        return;
      }

      if (FileIO.isValidLogFolder(selected)) {
        updateComboBoxAndSettings(display.pathBox, UserSettings.loadPathes, selected);

        lastGroup = Group.groupFromPath(selected);
        LogReference[] added;
        try {
          added = FileIO.readAllRefsFromPath(selected, true);
        } catch (Throwable e) {
          ToolMessage.displayError(
              "error {%s} (see below) reading Log refs from %s", e.getMessage(), selected);
          e.printStackTrace();

          return;
        }
        lastGroup.add(added);

        // Log[] addedLogs = new Log[added.length];
        // for (int i = 0; i < added.length; ++i)
        // addedLogs[i] = added[i].get();

        ToolMessage.displayInfo("loaded %d logs into %s", added.length, lastGroup);

        Events.GGroupAdded.generate(this, lastGroup);
        Events.GLogRefsFound.generate(this, added);
        // Events.GLogsFound.generate(this, addedLogs);

        display.leftSideTabs.setSelectedComponent(display.logTab);
      } else {
        Debug.error("invalid Log folder: " + selected.toString());
        ToolMessage.display("invalid Log folder: " + selected.toString(), Color.RED);
        return;
      }

    } else {
      Debug.error("cannot load session while streaming (%s)", robot);
      ToolMessage.display("cannot load session while streaming", Color.ORANGE);
    }
  }
  protected ToolDisplayHandler() {
    ToolMessage.displayInfo("creating new display and handler: %s", this);
    display = new ToolDisplay();
    listener = new TitleListener();

    setupUtilitiesTab();
    setupControlTab();
    setupLogsTab();
    setupLogDisplay();
    setupFooter();

    Center.listen(Events.LogsFound.class, this, true);
    Center.listen(Events.LogRefsFound.class, this, true);
    Center.listen(Events.GroupAdded.class, this, true);

    final String boundsKey = this.toString();
    Center.listen(
        new NBToolShutdownListener() {
          @Override
          public void nbtoolShutdownCallback() {
            DisplaySettings end =
                new DisplaySettings(
                    display.getBounds(), viewProfile, display.topLevelSplit.getDividerLocation());

            UserSettings.BOUNDS_MAP.put(boundsKey, end);
          }
        });

    DisplaySettings ds = UserSettings.BOUNDS_MAP.get(boundsKey);
    if (ds != null) {
      display.setBounds(ds.bounds);
      display.topLevelSplit.setDividerLocation(ds.splitLocation);
      viewProfile = ds.profile == null ? ViewProfile.DEFAULT_PROFILE : ds.profile;
    }

    display.setTitle("nbtool v" + ToolSettings.VERSION + "." + ToolSettings.MINOR_VERSION);
    display.setMinimumSize(MIN_SIZE);

    if (id == 0) {
      display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    } else {
      display.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
    }

    setupKeyBindings();

    display.topLevelSplit.setContinuousLayout(false);
    display.topLevelSplit.setAutoscrolls(false);

    Dimension min = ToolSettings.DEFAULT_BOUNDS.getSize();
    min.width = 0;

    display.leftSideTabs.setMinimumSize(min);
    display.displayTabs.setMinimumSize(min);

    display.topLevelSplit.requestFocus();
  }
 private void controlSelectAction() {
   Path selected = PathChooser.chooseDirPath(display, null);
   if (selected != null) {
     if (FileIO.isValidLogFolder(selected)) {
       updateComboBoxAndSettings(display.pathBox, UserSettings.loadPathes, selected);
     } else {
       ToolMessage.displayError("invalid path to logs: %s", selected);
     }
   }
 }
 @Override
 public void ioFinished(IOInstance instance) {
   if (instance == robot) {
     ToolMessage.displayWarn("robot %s disconnected!", instance);
     display.rpcScrollPane.setViewportView(new JLabel("no connection"));
     display.connectButton.setText("connect");
     display.loadButton.setEnabled(true);
     robot = null;
   } else {
     Debug.error("informed of dead connection %s but robot=%s", instance, robot);
   }
 }
    @Override
    protected void run() {
      Debug.warn("trying to connect to %s", robotAddress);
      robot = RobotConnection.connectToRobot(robotAddress, outerThis);

      if (robot == null) {
        ToolMessage.displayError("connection failed to: %s", robotAddress);

        SwingUtilities.invokeLater(
            new Runnable() {
              @Override
              public void run() {
                display.connectButton.setEnabled(true);
              }
            });

        return;
      } else {
        ToolMessage.displayWarn("SUCCESS: connected to %s (%s)", robotAddress, robot);

        SwingUtilities.invokeLater(
            new Runnable() {
              @Override
              public void run() {
                display.connectButton.setEnabled(true);

                display.connectButton.setText("disconnect");
                display.loadButton.setEnabled(false);
                updateComboBoxAndSettings(
                    display.robotAddressBox, UserSettings.addresses, robotAddress);

                controlRequestFlags();

                lastGroup = Group.groupForStream(robotAddress);
                Events.GGroupAdded.generate(this, lastGroup);
              }
            });
      }
    }