void confirmSubscription(ViewEvent.SubscriptionRequest event) {
    final Contact contact = event.contact;

    WebPanel panel = panel(Tr.tr("Authorization request"), contact);

    String expl = Tr.tr("When accepting, this contact will be able to see your online status.");
    panel.add(textArea(expl));

    WebNotificationPopup popup =
        NotificationManager.showNotification(
            panel,
            NotificationOption.accept,
            NotificationOption.decline,
            NotificationOption.cancel);
    popup.setClickToClose(false);
    popup.addNotificationListener(
        new NotificationListener() {
          @Override
          public void optionSelected(NotificationOption option) {
            switch (option) {
              case accept:
                mView.getControl().sendSubscriptionResponse(contact, true);
                break;
              case decline:
                mView.getControl().sendSubscriptionResponse(contact, false);
            }
          }

          @Override
          public void accepted() {}

          @Override
          public void closed() {}
        });
  }
示例#2
0
  void showPasswordDialog(boolean wasWrong) {
    WebPanel passPanel = new WebPanel();
    WebLabel passLabel = new WebLabel(Tr.tr("Please enter your key password:"******"Wrong password"));
      wrongLabel.setForeground(Color.RED);
      passPanel.add(wrongLabel, BorderLayout.SOUTH);
    }
    WebOptionPane passPane =
        new WebOptionPane(
            passPanel, WebOptionPane.QUESTION_MESSAGE, WebOptionPane.OK_CANCEL_OPTION);
    JDialog dialog = passPane.createDialog(mMainFrame, Tr.tr("Enter password"));
    dialog.setModal(true);
    dialog.addWindowFocusListener(
        new WindowAdapter() {
          @Override
          public void windowGainedFocus(WindowEvent e) {
            passField.requestFocusInWindow();
          }
        });
    // blocking
    dialog.setVisible(true);

    Object value = passPane.getValue();
    if (value != null && value.equals(WebOptionPane.OK_OPTION))
      mControl.connect(passField.getPassword());
  }
  void confirmContactDeletion(final Contact contact) {
    WebPanel panel = panel(Tr.tr("Contact was deleted on server"), contact);

    String expl =
        Tr.tr("Remove this contact from your contact list?") + "\n" + View.REMOVE_CONTACT_NOTE;
    panel.add(textArea(expl));

    WebNotificationPopup popup =
        NotificationManager.showNotification(
            panel, NotificationOption.yes, NotificationOption.no, NotificationOption.cancel);
    popup.setClickToClose(false);
    popup.addNotificationListener(
        new NotificationListener() {
          @Override
          public void optionSelected(NotificationOption option) {
            switch (option) {
              case yes:
                mView.getControl().deleteContact(contact);
            }
          }

          @Override
          public void accepted() {}

          @Override
          public void closed() {}
        });
  }
示例#4
0
 public static void showWrongJavaVersionDialog() {
   String jVersion = System.getProperty("java.version");
   if (jVersion.length() >= 3) jVersion = jVersion.substring(2, 3);
   String errorText = Tr.tr("The installed Java version is too old") + ": " + jVersion;
   errorText += System.getProperty("line.separator");
   errorText += Tr.tr("Please install Java 8.");
   WebOptionPane.showMessageDialog(
       null, errorText, Tr.tr("Unsupported Java Version"), WebOptionPane.ERROR_MESSAGE);
 }
    AddUserDialog() {
      this.setTitle(Tr.tr("Add New Contact"));
      // this.setSize(400, 280);
      this.setResizable(false);
      this.setModal(true);

      GroupPanel groupPanel = new GroupPanel(10, false);
      groupPanel.setMargin(5);

      // editable fields
      WebPanel namePanel = new WebPanel();
      namePanel.setLayout(new BorderLayout(10, 5));
      namePanel.add(new WebLabel(Tr.tr("Display Name:")), BorderLayout.WEST);
      mNameField = new WebTextField();
      namePanel.add(mNameField, BorderLayout.CENTER);
      groupPanel.add(namePanel);
      groupPanel.add(new WebSeparator(true, true));

      mEncryptionBox = new WebCheckBox(Tr.tr("Encryption"));
      mEncryptionBox.setAnimated(false);
      mEncryptionBox.setSelected(true);
      groupPanel.add(mEncryptionBox);
      groupPanel.add(new WebSeparator(true, true));

      groupPanel.add(new WebLabel("JID:"));
      mJIDField = new WebTextField(38);
      groupPanel.add(mJIDField);
      groupPanel.add(new WebSeparator(true, true));

      this.add(groupPanel, BorderLayout.CENTER);

      // buttons
      WebButton cancelButton = new WebButton(Tr.tr("Cancel"));
      cancelButton.addActionListener(
          new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
              AddUserDialog.this.dispose();
            }
          });
      final WebButton saveButton = new WebButton(Tr.tr("Save"));
      saveButton.addActionListener(
          new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
              AddUserDialog.this.saveUser();
              AddUserDialog.this.dispose();
            }
          });

      GroupPanel buttonPanel = new GroupPanel(2, cancelButton, saveButton);
      buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING));
      this.add(buttonPanel, BorderLayout.SOUTH);

      this.pack();
    }
示例#6
0
  private void confirmNewKey(final Contact contact, final PGPUtils.PGPCoderKey key) {
    WebPanel panel = new GroupPanel(GAP_DEFAULT, false);
    panel.setOpaque(false);

    panel.add(new WebLabel(Tr.tr("Received new key for contact")).setBoldFont());
    panel.add(new WebSeparator(true, true));

    panel.add(new WebLabel(Tr.tr("Contact:")));
    String contactText = Utils.name(contact) + " " + Utils.jid(contact.getJID(), 30, true);
    panel.add(new WebLabel(contactText).setBoldFont());

    panel.add(new WebLabel(Tr.tr("Key fingerprint:")));
    WebTextArea fpArea = Utils.createFingerprintArea();
    fpArea.setText(Utils.fingerprint(key.fingerprint));
    panel.add(fpArea);

    String expl =
        Tr.tr(
            "When declining the key further communication to and from this contact will be blocked.");
    WebTextArea explArea = new WebTextArea(expl, 3, 30);
    explArea.setEditable(false);
    explArea.setLineWrap(true);
    explArea.setWrapStyleWord(true);
    panel.add(explArea);

    WebNotificationPopup popup =
        NotificationManager.showNotification(
            panel,
            NotificationOption.accept,
            NotificationOption.decline,
            NotificationOption.cancel);
    popup.setClickToClose(false);
    popup.addNotificationListener(
        new NotificationListener() {
          @Override
          public void optionSelected(NotificationOption option) {
            switch (option) {
              case accept:
                mControl.acceptKey(contact, key);
                break;
              case decline:
                mControl.declineKey(contact);
            }
          }

          @Override
          public void accepted() {}

          @Override
          public void closed() {}
        });
  }
 private void showAboutDialog() {
   WebPanel aboutPanel = new WebPanel(new GridLayout(0, 1, 5, 5));
   aboutPanel.add(new WebLabel("Kontalk Java Client v" + Kontalk.VERSION));
   WebLinkLabel linkLabel = new WebLinkLabel();
   linkLabel.setLink("http://www.kontalk.org");
   linkLabel.setText(Tr.tr("Visit kontalk.org"));
   aboutPanel.add(linkLabel);
   WebLabel soundLabel = new WebLabel(Tr.tr("Notification sound by") + " FxProSound");
   aboutPanel.add(soundLabel);
   Icon icon = Utils.getIcon("kontalk.png");
   WebOptionPane.showMessageDialog(
       this, aboutPanel, Tr.tr("About"), WebOptionPane.INFORMATION_MESSAGE, icon);
 }
  void showPresenceError(Contact contact, RosterHandler.Error error) {
    WebPanel panel = panel(Tr.tr("Contact error"), contact);

    panel.add(new WebLabel(Tr.tr("Error:")).setBoldFont());
    String errorText = Tr.tr(error.toString());
    switch (error) {
      case SERVER_NOT_FOUND:
        errorText = Tr.tr("Server not found");
        break;
    }

    panel.add(textArea(errorText));

    NotificationManager.showNotification(panel, NotificationOption.cancel);
  }
 void setEnabled(boolean enabled, boolean isMember) {
   mTextArea.setEnabled(enabled);
   Color textBG = enabled ? Color.WHITE : Color.LIGHT_GRAY;
   mTextArea.setBackground(textBG);
   mOverlay.setBackground(textBG);
   mOverlayLabel.setText(isMember ? Tr.tr("You are not a member of this group") : "");
 }
  private static WebPanel panel(String title, Contact contact) {
    WebPanel panel = new GroupPanel(GAP_DEFAULT, false);
    panel.setOpaque(false);

    panel.add(new WebLabel(title).setBoldFont());
    panel.add(new WebSeparator(true, true));

    panel.add(new WebLabel(Tr.tr("Contact:")).setBoldFont());
    panel.add(new WebLabel(contactText(contact)));

    return panel;
  }
  void confirmNewKey(final Contact contact, final PGPUtils.PGPCoderKey key) {
    WebPanel panel = panel(Tr.tr("Received new key for contact"), contact);

    panel.add(new WebLabel(Tr.tr("Key fingerprint:")));
    WebTextArea fpArea = Utils.createFingerprintArea();
    fpArea.setText(Utils.fingerprint(key.fingerprint));
    panel.add(fpArea);

    String expl =
        Tr.tr(
            "When declining the key further communication to and from this contact will be blocked.");
    panel.add(textArea(expl));

    WebNotificationPopup popup =
        NotificationManager.showNotification(
            panel,
            NotificationOption.accept,
            NotificationOption.decline,
            NotificationOption.cancel);
    popup.setClickToClose(false);
    popup.addNotificationListener(
        new NotificationListener() {
          @Override
          public void optionSelected(NotificationOption option) {
            switch (option) {
              case accept:
                mView.getControl().acceptKey(contact, key);
                break;
              case decline:
                mView.getControl().declineKey(contact);
            }
          }

          @Override
          public void accepted() {}

          @Override
          public void closed() {}
        });
  }
  // TODO more information for message exs
  void showSecurityErrors(KonMessage message) {
    String errorText = "<html>";

    boolean isOut = !message.isInMessage();
    errorText += isOut ? Tr.tr("Encryption error") : Tr.tr("Decryption error");
    errorText += ":";

    for (Coder.Error error : message.getCoderStatus().getErrors()) {
      errorText += "<br>";
      switch (error) {
        case UNKNOWN_ERROR:
          errorText += Tr.tr("Unknown error");
          break;
        case KEY_UNAVAILABLE:
          errorText += Tr.tr("Key for receiver not found.");
          break;
        case INVALID_PRIVATE_KEY:
          errorText += Tr.tr("This message was encrypted with an old or invalid key");
          break;
        default:
          errorText += Tr.tr("Unusual coder error") + ": " + error.toString();
      }
    }

    errorText += "</html>";

    // TODO too intrusive for user, but use the explanation above for message view
    // NotificationManager.showNotification(mChatView, errorText);
  }
示例#13
0
  private void statusChanged() {
    Control.Status status = mControl.getCurrentStatus();
    switch (status) {
      case CONNECTING:
        mStatusBarLabel.setText(Tr.tr("Connecting..."));
        break;
      case CONNECTED:
        mChatView.setColor(Color.WHITE);
        mStatusBarLabel.setText(Tr.tr("Connected"));
        NotificationManager.hideAllNotifications();
        break;
      case DISCONNECTING:
        mStatusBarLabel.setText(Tr.tr("Disconnecting..."));
        break;
      case DISCONNECTED:
        mChatView.setColor(Color.LIGHT_GRAY);
        mStatusBarLabel.setText(Tr.tr("Not connected"));
        // if (mTrayIcon != null)
        //    trayIcon.setImage(updatedImage);
        break;
      case SHUTTING_DOWN:
        mMainFrame.save();
        mChatListView.save();
        mTrayManager.removeTray();
        mMainFrame.setVisible(false);
        mMainFrame.dispose();
        break;
      case FAILED:
        mStatusBarLabel.setText(Tr.tr("Connecting failed"));
        break;
      case ERROR:
        mChatView.setColor(Color.lightGray);
        mStatusBarLabel.setText(Tr.tr("Connection error"));
        break;
    }

    mMainFrame.onStatusChanged(status);
  }
  ThreadDetails(final Component focusGainer, KonThread thread) {
    mThread = thread;

    GroupPanel groupPanel = new GroupPanel(View.GAP_BIG, false);
    groupPanel.setMargin(View.MARGIN_BIG);

    groupPanel.add(new WebLabel(Tr.tr("Edit Chat")).setBoldFont());
    groupPanel.add(new WebSeparator(true, true));

    // editable fields
    groupPanel.add(new WebLabel(Tr.tr("Subject:")));
    String subj = mThread.getSubject();
    mSubjectField = new WebTextField(subj, 22);
    mSubjectField.setInputPrompt(subj);
    mSubjectField.setHideInputPromptOnFocus(false);
    groupPanel.add(mSubjectField);
    groupPanel.add(new WebSeparator(true, true));

    final WebSlider colorSlider = new WebSlider(WebSlider.HORIZONTAL);

    groupPanel.add(new WebLabel(Tr.tr("Custom Background")));
    mColorOpt = new WebRadioButton(Tr.tr("Color:") + " ");
    Optional<Color> optBGColor = mThread.getViewSettings().getBGColor();
    mColorOpt.setSelected(optBGColor.isPresent());
    mColorOpt.addItemListener(
        new ItemListener() {
          @Override
          public void itemStateChanged(ItemEvent e) {
            colorSlider.setEnabled(e.getStateChange() == ItemEvent.SELECTED);
          }
        });
    mColor = new WebButton();
    mColor.setMinimumHeight(25);
    Color oldColor = optBGColor.orElse(DEFAULT_BG);
    mColor.setBottomBgColor(oldColor);
    groupPanel.add(new GroupPanel(GroupingType.fillLast, mColorOpt, mColor));

    colorSlider.setMinimum(0);
    colorSlider.setMaximum(100);
    colorSlider.setPaintTicks(false);
    colorSlider.setPaintLabels(false);
    colorSlider.setEnabled(optBGColor.isPresent());
    final GradientData gradientData = GradientData.getDefaultValue();
    // TODO set location for color
    gradientData.getColor(0);
    colorSlider.addChangeListener(
        new ChangeListener() {
          @Override
          public void stateChanged(ChangeEvent e) {
            float v = colorSlider.getValue() / (float) 100;
            Color c = gradientData.getColorForLocation(v);
            mColor.setBottomBgColor(c);
            mColor.repaint();
          }
        });
    groupPanel.add(colorSlider);

    mImgOpt = new WebRadioButton(Tr.tr("Image:") + " ");
    String imgPath = mThread.getViewSettings().getImagePath();
    mImgOpt.setSelected(!imgPath.isEmpty());
    mImgOpt.addItemListener(
        new ItemListener() {
          @Override
          public void itemStateChanged(ItemEvent e) {
            mImgChooser.setEnabled(e.getStateChange() == ItemEvent.SELECTED);
            mImgChooser.getChooseButton().setEnabled(e.getStateChange() == ItemEvent.SELECTED);
          }
        });
    mImgChooser = Utils.createImageChooser(!imgPath.isEmpty(), imgPath);
    groupPanel.add(new GroupPanel(GroupingType.fillLast, mImgOpt, mImgChooser));
    UnselectableButtonGroup.group(mColorOpt, mImgOpt);
    groupPanel.add(new WebSeparator());

    //        groupPanel.add(new WebLabel(Tr.tr("Participants:")));
    //        mParticipantsList = new WebCheckBoxList();
    //        mParticipantsList.setVisibleRowCount(10);
    //        for (User oneUser : UserList.getInstance().getAll()) {
    //            boolean selected = mThread.getUser().contains(oneUser);
    //            mParticipantsList.getCheckBoxListModel().addCheckBoxElement(
    //                    new UserElement(oneUser),
    //                    selected);
    //        }
    final WebButton saveButton = new WebButton(Tr.tr("Save"));
    //        mParticipantsList.getModel().addListDataListener(new ListDataListener() {
    //            @Override
    //            public void intervalAdded(ListDataEvent e) {
    //            }
    //            @Override
    //            public void intervalRemoved(ListDataEvent e) {
    //            }
    //            @Override
    //            public void contentsChanged(ListDataEvent e) {
    //                saveButton.setEnabled(!mParticipantsList.getCheckedValues().isEmpty());
    //            }
    //        });
    //
    //        groupPanel.add(new WebScrollPane(mParticipantsList));
    //        groupPanel.add(new WebSeparator(true, true));

    this.add(groupPanel, BorderLayout.CENTER);

    saveButton.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            //                if (mParticipantsList.getCheckedValues().size() > 1) {
            //                        String infoText = Tr.t/r("More than one receiver not supported
            // (yet).");
            //                        WebOptionPane.showMessageDialog(ThreadListView.this,
            //                                infoText,
            //                                Tr.t/r("Sorry"),
            //                                WebOptionPane.INFORMATION_MESSAGE);
            //                    return;
            //                }
            ThreadDetails.this.save();

            // close popup
            focusGainer.requestFocus();
          }
        });
    // this.getRootPane().setDefaultButton(saveButton);

    GroupPanel buttonPanel = new GroupPanel(2, saveButton);
    buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING));
    this.add(buttonPanel, BorderLayout.SOUTH);
  }
示例#15
0
    StatusDialog() {
      this.setTitle(Tr.tr("Status"));
      this.setResizable(false);
      this.setModal(true);

      GroupPanel groupPanel = new GroupPanel(10, false);
      groupPanel.setMargin(5);

      String[] strings = mConf.getStringArray(Config.NET_STATUS_LIST);
      List<String> stats = new ArrayList<>(Arrays.<String>asList(strings));
      String currentStatus = "";
      if (!stats.isEmpty()) currentStatus = stats.remove(0);

      stats.remove("");

      groupPanel.add(new WebLabel(Tr.tr("Your current status:")));
      mStatusField = new WebTextField(currentStatus, 30);
      groupPanel.add(mStatusField);
      groupPanel.add(new WebSeparator(true, true));

      groupPanel.add(new WebLabel(Tr.tr("Previously used:")));
      mStatusList = new WebList(stats);
      mStatusList.setMultiplySelectionAllowed(false);
      mStatusList.addListSelectionListener(
          new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
              if (e.getValueIsAdjusting()) return;
              mStatusField.setText(mStatusList.getSelectedValue().toString());
            }
          });
      WebScrollPane listScrollPane = new ScrollPane(mStatusList);
      groupPanel.add(listScrollPane);
      this.add(groupPanel, BorderLayout.CENTER);

      // buttons
      WebButton cancelButton = new WebButton(Tr.tr("Cancel"));
      cancelButton.addActionListener(
          new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
              StatusDialog.this.dispose();
            }
          });
      final WebButton saveButton = new WebButton(Tr.tr("Save"));
      saveButton.addActionListener(
          new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
              StatusDialog.this.saveStatus();
              StatusDialog.this.dispose();
            }
          });
      this.getRootPane().setDefaultButton(saveButton);

      GroupPanel buttonPanel = new GroupPanel(2, cancelButton, saveButton);
      buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING));
      this.add(buttonPanel, BorderLayout.SOUTH);

      this.pack();
    }
  ComposingArea(ChatView chatView) {
    mChatView = chatView;

    mTextArea = new WebTextArea();
    mTextArea.setMargin(View.MARGIN_SMALL);
    mTextArea.setBorder(null);
    mTextArea.setLineWrap(true);
    mTextArea.setWrapStyleWord(true);
    mTextArea.setFontSize(View.FONT_SIZE_NORMAL);
    mTextArea.setInputPrompt(Tr.tr("Type to compose"));
    mTextArea.setInputPromptHorizontalPosition(SwingConstants.LEFT);
    mTextArea.setComponentPopupMenu(Utils.createCopyMenu(true));
    mTextArea
        .getDocument()
        .addDocumentListener(
            new DocumentChangeListener() {
              @Override
              public void documentChanged(DocumentEvent e) {
                mChatView.onKeyTypeEvent(e.getDocument().getLength() == 0);
              }
            });

    mScrollPane = new ComponentUtils.ScrollPane(mTextArea, false);
    mScrollPane.setBorder(null);

    // text area overlay
    mOverlayLabel = new WebLabel().setBoldFont();

    mOverlay =
        new WebOverlay(mScrollPane, mOverlayLabel, SwingConstants.CENTER, SwingConstants.CENTER);
    mOverlay.setUndecorated(false).setMargin(View.MARGIN_SMALL).setWebColoredBackground(false);

    // old transfer handler of text area is fallback for bottom panel
    mDropHandler = new FileDropHandler(mTextArea.getTransferHandler());
    mTextArea.setTransferHandler(mDropHandler);

    // when text changed...
    mTextArea
        .getDocument()
        .addDocumentListener(
            new DocumentChangeListener() {
              @Override
              public void documentChanged(DocumentEvent e) {
                // these are strange times
                SwingUtilities.invokeLater(
                    new Runnable() {
                      public void run() {
                        ComposingArea.this.adjustSize();
                      }
                    });
              }
            });
    ((AbstractDocument) mTextArea.getDocument())
        .setDocumentFilter(
            new DocumentFilter() {
              @Override
              public void replace(
                  FilterBypass fb, int offset, int length, String string, AttributeSet attr)
                  throws BadLocationException {
                // input implementation of the "/me" command, XEP-0245
                if (length == 0 && offset == 0 && string.equals("/")) {
                  fb.insertString(0, View.THE_ME_COMMAND, attr);
                  return;
                }
                super.replace(fb, offset, length, string, attr);
              }
            });

    // ...or window is resized
    mChatView.addComponentListener(
        new ComponentAdapter() {
          @Override
          public void componentResized(ComponentEvent e) {
            ComposingArea.this.adjustSize();
          }
        });
  }
示例#17
0
  MainFrame(
      final View view,
      TableView<?, ?> userList,
      TableView<?, ?> threadList,
      Component content,
      Component searchPanel,
      Component statusBar) {
    mView = view;

    // general view + behaviour
    this.setTitle("Kontalk Java Client");
    this.setSize(mConf.getInt(Config.VIEW_FRAME_WIDTH), mConf.getInt(Config.VIEW_FRAME_HEIGHT));

    this.setIconImage(Utils.getImage("kontalk.png"));

    // closing behaviour
    this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    this.addWindowListener(
        new WindowAdapter() {
          @Override
          public void windowClosing(WindowEvent e) {
            if (mConf.getBoolean(Config.MAIN_TRAY_CLOSE)
                && SystemTray.getSystemTray().getTrayIcons().length > 0)
              MainFrame.this.toggleState();
            else mView.callShutDown();
          }
        });

    // menu
    WebMenuBar menubar = new WebMenuBar();
    this.setJMenuBar(menubar);

    WebMenu konNetMenu = new WebMenu("KonNet");
    konNetMenu.setMnemonic(KeyEvent.VK_K);

    mConnectMenuItem = new WebMenuItem(Tr.tr("Connect"));
    mConnectMenuItem.setAccelerator(Hotkey.ALT_C);
    mConnectMenuItem.setToolTipText(Tr.tr("Connect to Server"));
    mConnectMenuItem.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent event) {
            mView.callConnect();
          }
        });
    konNetMenu.add(mConnectMenuItem);

    mDisconnectMenuItem = new WebMenuItem(Tr.tr("Disconnect"));
    mDisconnectMenuItem.setAccelerator(Hotkey.ALT_D);
    mDisconnectMenuItem.setToolTipText(Tr.tr("Disconnect from Server"));
    mDisconnectMenuItem.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent event) {
            mView.callDisconnect();
          }
        });
    konNetMenu.add(mDisconnectMenuItem);
    konNetMenu.addSeparator();

    WebMenuItem statusMenuItem = new WebMenuItem(Tr.tr("Set status"));
    statusMenuItem.setAccelerator(Hotkey.ALT_S);
    statusMenuItem.setToolTipText(Tr.tr("Set status text send to other user"));
    statusMenuItem.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent event) {
            WebDialog statusDialog = new StatusDialog();
            statusDialog.setVisible(true);
          }
        });
    konNetMenu.add(statusMenuItem);
    konNetMenu.addSeparator();

    WebMenuItem exitMenuItem = new WebMenuItem(Tr.tr("Exit"));
    exitMenuItem.setAccelerator(Hotkey.ALT_E);
    exitMenuItem.setToolTipText(Tr.tr("Exit application"));
    exitMenuItem.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent event) {
            mView.callShutDown();
          }
        });
    konNetMenu.add(exitMenuItem);

    menubar.add(konNetMenu);

    WebMenu optionsMenu = new WebMenu(Tr.tr("Options"));
    optionsMenu.setMnemonic(KeyEvent.VK_O);

    WebMenuItem conConfMenuItem = new WebMenuItem(Tr.tr("Preferences"));
    conConfMenuItem.setAccelerator(Hotkey.ALT_P);
    conConfMenuItem.setToolTipText(Tr.tr("Set application preferences"));
    conConfMenuItem.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent event) {
            mView.showConfig();
          }
        });
    optionsMenu.add(conConfMenuItem);

    menubar.add(optionsMenu);

    WebMenu helpMenu = new WebMenu(Tr.tr("Help"));
    helpMenu.setMnemonic(KeyEvent.VK_H);

    WebMenuItem aboutMenuItem = new WebMenuItem(Tr.tr("About"));
    aboutMenuItem.setToolTipText(Tr.tr("About Kontalk"));
    aboutMenuItem.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent event) {
            MainFrame.this.showAboutDialog();
          }
        });
    helpMenu.add(aboutMenuItem);

    menubar.add(helpMenu);

    // Layout...
    this.setLayout(new BorderLayout(5, 5));

    // ...left...
    WebPanel sidePanel = new WebPanel(false);
    sidePanel.add(searchPanel, BorderLayout.NORTH);
    mTabbedPane = new WebTabbedPane(WebTabbedPane.LEFT);
    WebButton newThreadButton = new WebButton(Tr.tr("New"));
    newThreadButton.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            // TODO new thread button
          }
        });
    // String threadOverlayText =
    //        Tr.t/r("No chats to display. You can create a new chat from your contacts");
    WebScrollPane threadPane = createTablePane(threadList, newThreadButton, "threadOverlayText");
    mTabbedPane.addTab("", threadPane);
    mTabbedPane.setTabComponentAt(Tab.THREADS.ordinal(), new WebVerticalLabel(Tr.tr("Chats")));

    WebButton newUserButton = new WebButton(Tr.tr("Add"));
    newUserButton.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            WebDialog addUserDialog = new AddUserDialog();
            addUserDialog.setVisible(true);
          }
        });
    // String userOverlayText = T/r.tr("No contacts to display. You have no friends ;(");
    WebScrollPane userPane = createTablePane(userList, newUserButton, "userOverlayText");
    mTabbedPane.addTab("", userPane);
    mTabbedPane.setTabComponentAt(Tab.USER.ordinal(), new WebVerticalLabel(Tr.tr("Contacts")));
    mTabbedPane.setPreferredSize(new Dimension(250, -1));
    mTabbedPane.addChangeListener(
        new ChangeListener() {
          @Override
          public void stateChanged(ChangeEvent e) {
            mView.tabPaneChanged(Tab.values()[mTabbedPane.getSelectedIndex()]);
          }
        });

    sidePanel.add(mTabbedPane, BorderLayout.CENTER);
    this.add(sidePanel, BorderLayout.WEST);

    // ...right...
    this.add(content, BorderLayout.CENTER);

    // ...bottom
    this.add(statusBar, BorderLayout.SOUTH);
  }