private ChartyGUI() {
    setPreferredSize(new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT));

    // load logo
    final ArrayList<Image> icons = new ArrayList<Image>();
    try {
      for(final int size : ICON_SIZES) {
        final InputStream in = IOUtils.getResource("logo/" + size + ".png");
        icons.add(ImageIO.read(in));
      }
    } catch(final IOException e) {
      e.printStackTrace();
    }
    setIconImages(icons);

    final DataModel model = new DataModel(this);
    ctrl = new Controller(this, model);

    // menu bar
    final JMenuBar menuBar = new JMenuBar();
    setJMenuBar(menuBar);
    final JMenu fileMenu = new JMenu("File");
    menuBar.add(fileMenu);
    fileMenu.add(ctrl.getActionFor(GRAMMAR_NEW));
    fileMenu.add(ctrl.getActionFor(GRAMMAR_OPEN));
    fileMenu.add(ctrl.getActionFor(GRAMMAR_SAVE));
    fileMenu.add(ctrl.getActionFor(GRAMMAR_SAVE_AS));
    fileMenu.addSeparator();
    fileMenu.add(ctrl.getActionFor(EXIT));
    final JMenu displayMenu = new JMenu("Display");
    menuBar.add(displayMenu);
    final ButtonGroup rendererGroup = new ButtonGroup();
    final ButtonGroup strategyGroup = new ButtonGroup();
    // no selection items
    addMenuItem(null, NodeRenderer.class, null, rendererGroup);
    addMenuItem(null, TreeStrategy.class, null, strategyGroup);
    // renderer items
    addMenuItem(DISPLAY_DEFAULT, DefaultRenderer.class, displayMenu, rendererGroup);
    addMenuItem(DISPLAY_BOX, SimpleRenderer.class, displayMenu, rendererGroup);
    // custom item as last
    if(Controller.CUSTOM_RENDERER != null) {
      addMenuItem(CUSTOM_RENDERER, Controller.CUSTOM_RENDERER.getClass(),
          displayMenu, rendererGroup);
    }
    displayMenu.addSeparator();
    // strategy items
    addMenuItem(DISPLAY_BOTTOM_UP, BottomUpStrategy.class, displayMenu, strategyGroup);
    addMenuItem(DISPLAY_TOP_DOWN, TopDownStrategy.class, displayMenu, strategyGroup);
    // custom item as last
    if(Controller.CUSTOM_STRATEGY != null) {
      addMenuItem(CUSTOM_STRATEGY, Controller.CUSTOM_STRATEGY.getClass(),
          displayMenu, strategyGroup);
    }
    displayMenu.addSeparator();
    // the latex item and rest
    addMenuItem(DISPLAY_LATEX, LaTeXDisplay.class, displayMenu, null);
    displayMenu.addSeparator();
    displayMenu.add(ctrl.getActionFor(VIEW_SAVE));
    displayMenu.add(ctrl.getActionFor(SYNTAX_TREE_SAVE));
    // Left side: edit grammar and phrase
    editor = new GrammarEditor(ctrl);
    model.setDocument(editor.getDocument());
    final JPanel edit = new JPanel(new BorderLayout());
    edit.add(editor, BorderLayout.CENTER);
    final PhraseInput input = new PhraseInput(ctrl);
    edit.add(input, BorderLayout.PAGE_END);

    // Right side: view parse tree and parser output
    treeViewer = new ParseTreeViewer(ctrl);
    final JSplitPane view = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
        treeViewer, new ParserInfoViewer(model.getInfoTableModel()));
    view.setDividerLocation(WINDOW_HEIGHT / 2);
    view.setOneTouchExpandable(true);
    view.setResizeWeight(1.0 / 2);

    try {
      final File grammar = INI.getObject("last", "grammar", Converter.FILE_CONVERTER, "");
      if(grammar == null || !grammar.exists()) {
        model.setDefaultGrammar();
      } else {
        try {
          model.setOpenedFile(grammar);
        } catch(final IOException e) {
          // fall-back for unreadable files
          model.setDefaultGrammar();
        }
      }
    } catch(final IOException e) {
      e.printStackTrace();
    }

    // new content pane
    final JPanel content = new JPanel(new BorderLayout());
    setContentPane(content);

    // split the screen in two halfs
    final JSplitPane vertical = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
        edit, view);
    vertical.setDividerLocation(WINDOW_WIDTH / 2);
    vertical.setResizeWeight(1.0 / 2);
    content.add(vertical, BorderLayout.CENTER);

    // make the window ready for display
    pack();
    input.focus();

    wasInCenter = initialPosition == null;
    if(wasInCenter) {
      // to the center of the screen
      setLocationRelativeTo(null);
      initialPosition = new Integer[] { getX(), getY()};
    } else {
      setLocation(initialPosition[0], initialPosition[1]);
    }

    // set extended state
    setExtendedState(WINDOW_EXTEND_STATE);

    // shows unresolved / cycling threads -- safer close
    // ensures call of dispose
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
  }