/*
    SuperCollider Qt IDE
    Copyright (c) 2012 Jakob Leben & Tim Blechmann
    http://www.audiosynth.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

#include "multi_editor.hpp"
#include "editor_box.hpp"
#include "main_window.hpp"
#include "lookup_dialog.hpp"
#include "code_editor/sc_editor.hpp"
#include "util/multi_splitter.hpp"
#include "../core/doc_manager.hpp"
#include "../core/sig_mux.hpp"
#include "../core/main.hpp"
#include "../core/sc_process.hpp"
#include "../core/session_manager.hpp"

#include <yaml-cpp/node/node.h>
#include <yaml-cpp/parser.h>

#include <QApplication>
#include <QDebug>
#include <QDialog>
#include <QFileInfo>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QListView>
#include <QMenu>
#include <QPainter>
#include <QStandardItemModel>
#include <QShortcut>
#include <QStyle>
#include <QTreeWidget>
#include <QVBoxLayout>


namespace ScIDE {

class DocumentSelectPopUp : public QDialog {
public:
    DocumentSelectPopUp(const CodeEditorBox::History& history, QWidget* parent):
#ifndef Q_OS_MAC
        QDialog(parent, Qt::Popup | Qt::FramelessWindowHint)
#else
        QDialog(parent, Qt::Dialog | Qt::FramelessWindowHint)
#endif
    {
        mModel = new QStandardItemModel(this);
        populateModel(history);

        mListView = new QListView();
        mListView->setModel(mModel);
        mListView->setFrameShape(QFrame::NoFrame);

        QHBoxLayout* layout = new QHBoxLayout(this);
        layout->addWidget(mListView);
        layout->setContentsMargins(1, 1, 1, 1);

        connect(mListView, SIGNAL(activated(QModelIndex)), this, SLOT(accept()));

        mListView->setFocus(Qt::OtherFocusReason);

        QModelIndex nextIndex = mModel->index(1, 0);
        mListView->setCurrentIndex(nextIndex);

        mListView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    }

    Document* exec(const QPoint& pos) {
        move(pos);
        if (QDialog::exec())
            return currentDocument();
        else
            return 0;
    }

private:
    bool event(QEvent* event) {
        if (event->type() == QEvent::ShortcutOverride) {
            event->accept();
            return true;
        }
        return QWidget::event(event);
    }

    void keyReleaseEvent(QKeyEvent* ke) {
        // adapted from qtcreator
        if (ke->modifiers() == 0
            /*HACK this is to overcome some event inconsistencies between platforms*/
            || (ke->modifiers() == Qt::AltModifier && (ke->key() == Qt::Key_Alt || ke->key() == -1))) {
            ke->accept();
            accept();
        }
        QDialog::keyReleaseEvent(ke);
    }

    void keyPressEvent(QKeyEvent* ke) {
        switch (ke->key()) {
        case Qt::Key_Down:
        case Qt::Key_Tab:
            cycleDown();
            ke->accept();
            return;

        case Qt::Key_Up:
        case Qt::Key_Backtab:
            cycleUp();
            ke->accept();
            return;

        case Qt::Key_Escape:
            reject();
            return;

        default:;
        }

        QDialog::keyPressEvent(ke);
    }

    void paintEvent(QPaintEvent*) {
        QPainter painter(this);
        painter.setBrush(Qt::NoBrush);
        painter.setPen(palette().color(QPalette::Dark));
        painter.drawRect(rect().adjusted(0, 0, -1, -1));
    }

    void cycleDown() {
        int row = mListView->currentIndex().row() + 1;
        if (!mModel->hasIndex(row, 0))
            row = 0;

        QModelIndex nextIndex = mModel->index(row, 0);
        mListView->setCurrentIndex(nextIndex);
    }

    void cycleUp() {
        int row = mListView->currentIndex().row() - 1;
        if (!mModel->hasIndex(row, 0))
            row = mModel->rowCount() - 1;

        QModelIndex nextIndex = mModel->index(row, 0);
        mListView->setCurrentIndex(nextIndex);
    }

    Document* currentDocument() {
        QStandardItem* currentItem = mModel->itemFromIndex(mListView->currentIndex());
        return currentItem ? currentItem->data().value<Document*>() : NULL;
    }

    void populateModel(const CodeEditorBox::History& history) {
        QList<Document*> displayDocuments;
        foreach (GenericCodeEditor* editor, history)
            displayDocuments << editor->document();

        QList<Document*> managerDocuments = Main::documentManager()->documents();
        foreach (Document* document, managerDocuments)
            if (!displayDocuments.contains(document))
                displayDocuments << document;

        foreach (Document* document, displayDocuments) {
            QStandardItem* item = new QStandardItem(document->title());
            item->setData(QVariant::fromValue(document));
            mModel->appendRow(item);
        }
    }

    QListView* mListView;
    QStandardItemModel* mModel;
};

EditorTabBar::EditorTabBar(QWidget* parent): QTabBar(parent) {
    setDocumentMode(true);
    setTabsClosable(true);
    setMovable(true);
    setUsesScrollButtons(true);
    setDrawBase(false);
    setElideMode(Qt::ElideNone);
}

void EditorTabBar::mousePressEvent(QMouseEvent* event) {
    if (event->button() == Qt::RightButton) {
        showContextMenu(event);
        event->accept();
        return;
    } else if (event->button() == Qt::MiddleButton) {
        mTabUnderCursor = tabAt(event->pos());
        onCloseTab();
        event->accept();
        return;
    }

    QTabBar::mousePressEvent(event);
}


void EditorTabBar::mouseDoubleClickEvent(QMouseEvent* event) {
    if (event->button() == Qt::LeftButton) {
        if (tabAt(event->pos()) == -1) { // no tab under cursor
            MainWindow::instance()->newDocument();
            event->accept();
            return;
        }
    }

    QTabBar::mouseDoubleClickEvent(event);
}

void EditorTabBar::showContextMenu(QMouseEvent* event) {
    mTabUnderCursor = tabAt(event->pos());

    QMenu* menu = new QMenu(this);
    // Cannot have a close tab action if we are not over a tab
    if (mTabUnderCursor == -1) {
        menu->addAction(tr("Close All Tabs"), this, SLOT(onCloseOtherTabs()));
    } else {
        menu->addAction(tr("Close"), this, SLOT(onCloseTab()));
        menu->addAction(tr("Close Other Tabs"), this, SLOT(onCloseOtherTabs()));
        menu->addAction(tr("Close Tabs to the Right"), this, SLOT(onCloseTabsToTheRight()));
    }

    menu->popup(event->screenPos().toPoint());
}

void EditorTabBar::onCloseTab() {
    Document* doc = tabData(mTabUnderCursor).value<Document*>();
    assert(doc);

    MainWindow::close(doc);
}

void EditorTabBar::onCloseOtherTabs() {
    QVector<Document*> docsToClose;

    for (int currentTab = 0; currentTab != count(); ++currentTab) {
        if (currentTab != mTabUnderCursor)
            docsToClose.append(tabData(currentTab).value<Document*>());
    }

    for (Document* doc : docsToClose)
        MainWindow::close(doc);
}

void EditorTabBar::onCloseTabsToTheRight() {
    QVector<Document*> docsToClose;

    for (int currentTab = mTabUnderCursor + 1; currentTab != count(); ++currentTab)
        docsToClose.append(tabData(currentTab).value<Document*>());

    for (Document* doc : docsToClose)
        MainWindow::close(doc);
}


MultiEditor::MultiEditor(Main* main, QWidget* parent):
    QWidget(parent),
    mEditorSigMux(new SignalMultiplexer(this)),
    mBoxSigMux(new SignalMultiplexer(this)),
#ifdef __APPLE__
    mDocModifiedIcon(QApplication::style()->standardIcon(QStyle::SP_DriveHDIcon))
#else
    mDocModifiedIcon(QIcon::fromTheme("document-save"))
#endif
{
    mTabs = new EditorTabBar;

    mSplitter = new MultiSplitter(this);
    CodeEditorBox* defaultBox = newBox(mSplitter);

    mSplitter->addWidget(defaultBox);

    multiEditorLayout = new QVBoxLayout;
    multiEditorLayout->setContentsMargins(0, 0, 0, 0);
    multiEditorLayout->setSpacing(0);
    multiEditorLayout->addWidget(mTabs);
    multiEditorLayout->addWidget(mSplitter);
    setLayout(multiEditorLayout);

    makeSignalConnections();

    connect(main, SIGNAL(applySettingsRequest(Settings::Manager*)), this, SLOT(applySettings(Settings::Manager*)));

    createActions();

    setCurrentBox(defaultBox); // will updateActions();

    applySettings(main->settings());
}

void MultiEditor::makeSignalConnections() {
    DocumentManager* docManager = Main::documentManager();

    connect(docManager, SIGNAL(opened(Document*, int, int)), this, SLOT(onOpen(Document*, int, int)));
    connect(docManager, SIGNAL(closed(Document*)), this, SLOT(onClose(Document*)));
    connect(docManager, SIGNAL(saved(Document*)), this, SLOT(update(Document*)));
    connect(docManager, SIGNAL(showRequest(Document*, int, int)), this, SLOT(show(Document*, int, int)));
    connect(docManager, SIGNAL(titleChanged(Document*)), this, SLOT(update(Document*)));

    connect(mTabs, SIGNAL(currentChanged(int)), this, SLOT(onCurrentTabChanged(int)));
    connect(mTabs, SIGNAL(tabCloseRequested(int)), this, SLOT(onCloseRequest(int)));
    connect(mTabs, SIGNAL(tabMoved(int, int)), this, SLOT(updateDocOrder(int, int)));

    mBoxSigMux->connect(SIGNAL(currentChanged(GenericCodeEditor*)), this,
                        SLOT(onCurrentEditorChanged(GenericCodeEditor*)));
}

void MultiEditor::updateDocOrder(int from, int to) { Q_EMIT(updateDockletOrder(from, to)); }

void MultiEditor::breakSignalConnections() {
    DocumentManager* docManager = Main::documentManager();
    docManager->disconnect(this);
    mTabs->disconnect(this);
    mBoxSigMux->disconnect(this);
}

void MultiEditor::createActions() {
    Settings::Manager* settings = Main::settings();

    QAction* action;
    const QString editorCategory(tr("Text Editor"));

    // Edit

    mActions[Undo] = action = new QAction(QIcon::fromTheme("edit-undo"), tr("&Undo"), this);
    action->setShortcut(tr("Ctrl+Z", "Undo"));
    action->setStatusTip(tr("Undo last editing action"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(undo()));
    mEditorSigMux->connect(SIGNAL(undoAvailable(bool)), action, SLOT(setEnabled(bool)));
    settings->addAction(action, "editor-undo", editorCategory);

    mActions[Redo] = action = new QAction(QIcon::fromTheme("edit-redo"), tr("Re&do"), this);
    action->setShortcut(tr("Ctrl+Shift+Z", "Redo"));
    action->setStatusTip(tr("Redo next editing action"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(redo()));
    mEditorSigMux->connect(SIGNAL(redoAvailable(bool)), action, SLOT(setEnabled(bool)));
    settings->addAction(action, "editor-redo", editorCategory);

    mActions[Cut] = action = new QAction(QIcon::fromTheme("edit-cut"), tr("Cu&t"), this);
    action->setShortcut(tr("Ctrl+X", "Cut"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    action->setStatusTip(tr("Cut text to clipboard"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(cut()));
    mEditorSigMux->connect(SIGNAL(copyAvailable(bool)), action, SLOT(setEnabled(bool)));
    settings->addAction(action, "editor-cut", editorCategory);

    mActions[Copy] = action = new QAction(QIcon::fromTheme("edit-copy"), tr("&Copy"), this);
    action->setShortcut(tr("Ctrl+C", "Copy"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    action->setStatusTip(tr("Copy text to clipboard"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(copy()));
    mEditorSigMux->connect(SIGNAL(copyAvailable(bool)), action, SLOT(setEnabled(bool)));
    settings->addAction(action, "editor-copy", editorCategory);

    mActions[Paste] = action = new QAction(QIcon::fromTheme("edit-paste"), tr("&Paste"), this);
    action->setShortcut(tr("Ctrl+V", "Paste"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    action->setStatusTip(tr("Paste text from clipboard"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(paste()));
    settings->addAction(action, "editor-paste", editorCategory);

    mActions[IndentLineOrRegion] = action =
        new QAction(QIcon::fromTheme("format-indent-line"), tr("Autoindent Line or Region"), this);
    action->setStatusTip(tr("Autoindent Line or Region"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(indent()), SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-indent-auto", editorCategory);

    mActions[TriggerAutoCompletion] = action = new QAction(tr("Trigger Autocompletion"), this);
    action->setStatusTip(tr("Suggest possible completions of text at cursor"));
    action->setShortcut(tr("Ctrl+Space", "Trigger Autocompletion"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(triggerAutoCompletion()),
                           SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-autocompletion", editorCategory);

    mActions[TriggerMethodCallAid] = action = new QAction(tr("Trigger Method Call Aid"), this);
    action->setStatusTip(tr("Show arguments for currently typed method call"));
    action->setShortcut(tr("Ctrl+Shift+Space", "Trigger Method Call Aid"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(triggerMethodCallAid()),
                           SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-method-call-assist", editorCategory);

    mActions[ToggleComment] = action = new QAction(QIcon::fromTheme("edit-comment"), tr("Toggle &Comment"), this);
    action->setShortcut(tr("Ctrl+/", "Toggle Comment"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    action->setStatusTip(tr("Toggle Comment"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(toggleComment()), SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-toggle-comment", editorCategory);

    mActions[ToggleOverwriteMode] = action =
        new QAction(QIcon::fromTheme("edit-overwrite"), tr("Toggle &Overwrite Mode"), this);
    action->setShortcut(tr("Insert", "Toggle Overwrite Mode"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(toggleOverwriteMode()));
    settings->addAction(action, "editor-toggle-overwrite", editorCategory);

    mActions[CopyLineUp] = action = new QAction(QIcon::fromTheme("edit-copylineup"), tr("Copy Line Up"), this);
    action->setShortcut(tr("Ctrl+Alt+Up", "Copy Line Up"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(copyLineUp()));
    settings->addAction(action, "editor-copy-line-up", editorCategory);

    mActions[CopyLineDown] = action = new QAction(QIcon::fromTheme("edit-copylinedown"), tr("Copy Line Down"), this);
    action->setShortcut(tr("Ctrl+Alt+Down", "Copy Line Up"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(copyLineDown()));
    settings->addAction(action, "editor-copy-line-down", editorCategory);

    mActions[MoveLineUp] = action = new QAction(QIcon::fromTheme("edit-movelineup"), tr("Move Line Up"), this);
    action->setShortcut(tr("Ctrl+Shift+Up", "Move Line Up"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(moveLineUp()));
    settings->addAction(action, "editor-move-line-up", editorCategory);

    mActions[MoveLineDown] = action = new QAction(QIcon::fromTheme("edit-movelinedown"), tr("Move Line Down"), this);
    action->setShortcut(tr("Ctrl+Shift+Down", "Move Line Up"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(moveLineDown()));
    settings->addAction(action, "editor-move-line-down", editorCategory);

    mActions[DeleteWord] = action = new QAction(QIcon::fromTheme("edit-deleteword"), tr("Delete Word"), this);
#ifdef Q_OS_MAC
    action->setShortcut(tr("Meta+W", "Delete Word"));
#endif
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(deleteWord()));
    settings->addAction(action, "delete-word", editorCategory);

    mActions[GotoPreviousBlock] = action =
        new QAction(QIcon::fromTheme("edit-gotopreviousblock"), tr("Go to Previous Block"), this);
    action->setShortcut(tr("Ctrl+[", "Go to Previous Block"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(gotoPreviousBlock()),
                           SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-go-to-prev-block", editorCategory);

    mActions[GotoNextBlock] = action =
        new QAction(QIcon::fromTheme("edit-gotonextblock"), tr("Go to Next Block"), this);
    action->setShortcut(tr("Ctrl+]", "Go to Next Block"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(gotoNextBlock()), SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-go-to-next-block", editorCategory);

    mActions[SelectEnclosingBlock] = action = new QAction(tr("Select Enclosing Block"), this);
    action->setShortcut(tr("Ctrl+Shift+B", "Select Enclosing Block"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    action->setStatusTip(tr("Select everything between brackets that contain cursor"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(selectBlockAroundCursor()),
                           SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-select-enclosing-block", editorCategory);

    mActions[GotoPreviousRegion] = action =
        new QAction(QIcon::fromTheme("edit-gotopreviousregion"), tr("Go to Previous Region"), this);
    action->setShortcut(tr("Ctrl+Alt+[", "Go to Previous Region"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(gotoPreviousRegion()),
                           SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-go-to-prev-region", editorCategory);

    mActions[GotoNextRegion] = action =
        new QAction(QIcon::fromTheme("edit-gotonextregion"), tr("Go to Next Region"), this);
    action->setShortcut(tr("Ctrl+Alt+]", "Go to Next Region"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(gotoNextRegion()), SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-go-to-next-region", editorCategory);

    mActions[GotoPreviousEmptyLine] = action = new QAction(tr("Go to Previous Empty Line"), this);
    action->setShortcut(tr("Ctrl+Up", "Go to Previous Empty Line"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(gotoPreviousEmptyLine()));
    settings->addAction(action, "editor-go-to-prev-empty-line", editorCategory);

    mActions[GotoNextEmptyLine] = action = new QAction(tr("Go to Next Empty Line"), this);
    action->setShortcut(tr("Ctrl+Down", "Go to Next Empty Line"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(gotoNextEmptyLine()));
    settings->addAction(action, "editor-go-to-next-empty-line", editorCategory);

    mActions[SelectRegion] = action = new QAction(tr("Select Region"), this);
    action->setShortcut(tr("Ctrl+Shift+R", "Select Region"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(selectCurrentRegion()),
                           SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-select-region", editorCategory);

    // View

    mActions[DocClose] = action = new QAction(QIcon::fromTheme("window-close"), tr("&Close"), this);
    action->setShortcut(tr("Ctrl+W", "Close document"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    action->setStatusTip(tr("Close the current document"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(closeDocument()));
    settings->addAction(action, "ide-document-close", editorCategory);

    mActions[EnlargeFont] = action = new QAction(QIcon::fromTheme("zoom-in"), tr("&Enlarge Font"), this);
    action->setShortcut(tr("Ctrl++", "Enlarge font"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    action->setStatusTip(tr("Increase displayed font size"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(zoomIn()));
    settings->addAction(action, "editor-enlarge-font", editorCategory);

    mActions[ShrinkFont] = action = new QAction(QIcon::fromTheme("zoom-out"), tr("&Shrink Font"), this);
    action->setShortcut(tr("Ctrl+-", "Shrink font"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    action->setStatusTip(tr("Decrease displayed font size"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(zoomOut()));
    settings->addAction(action, "editor-shrink-font", editorCategory);

    mActions[ResetFontSize] = action = new QAction(QIcon::fromTheme("zoom-reset"), tr("&Reset Font Size"), this);
    action->setShortcut(tr("Ctrl+0", "Reset font"));
    action->setStatusTip(tr("Reset displayed font size"));
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(resetFontSize()));
    settings->addAction(action, "editor-reset-font-size", editorCategory);

    mActions[ShowWhitespace] = action = new QAction(tr("Show Spaces and Tabs"), this);
    action->setCheckable(true);
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
#ifdef Q_OS_MAC
    action->setShortcut(QKeySequence(Qt::META | Qt::Key_E, Qt::META | Qt::Key_V));
#else
    action->setShortcut(QKeySequence(Qt::ALT | Qt::Key_E, Qt::ALT | Qt::Key_V));
#endif
    connect(action, SIGNAL(triggered(bool)), this, SLOT(setShowWhitespace(bool)));
    settings->addAction(action, "editor-toggle-show-whitespace", editorCategory);

    mActions[ShowLinenumber] = action = new QAction(tr("Show Line Number"), this);
    action->setCheckable(true);
    action->setShortcut(tr("Ctrl+Alt+#", "Show Line Number"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    connect(action, SIGNAL(triggered(bool)), this, SLOT(setShowLinenumber(bool)));
    settings->addAction(action, "editor-toggle-show-line-number", editorCategory);

    mActions[ShowAutocompleteHelp] = action = new QAction(tr("Show Autocomplete Help"), this);
    action->setCheckable(true);
    connect(action, SIGNAL(triggered(bool)), this, SLOT(setShowAutocompleteHelp(bool)));
    settings->addAction(action, "editor-toggle-show-autocomplete-help", editorCategory);

    mActions[IndentWithSpaces] = action = new QAction(tr("Use Spaces for Indentation"), this);
    action->setCheckable(true);
    action->setStatusTip(tr("Indent with spaces instead of tabs"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered(bool)), SLOT(setSpaceIndent(bool)),
                           SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-toggle-space-indent", editorCategory);

    mActions[NextDocument] = action = new QAction(tr("Next Document"), this);
#ifndef Q_OS_MAC
    action->setShortcut(tr("Ctrl+Tab", "Next Document"));
#else
    action->setShortcut(tr("Meta+Tab", "Next Document"));
#endif
    connect(action, SIGNAL(triggered()), this, SLOT(showNextDocument()));
    settings->addAction(action, "editor-document-next", editorCategory);

    mActions[PreviousDocument] = action = new QAction(tr("Previous Document"), this);
#ifndef Q_OS_MAC
    action->setShortcut(tr("Ctrl+Shift+Tab", "Previous Document"));
#else
    action->setShortcut(tr("Meta+Shift+Tab", "Previous Document"));
#endif
    connect(action, SIGNAL(triggered()), this, SLOT(showPreviousDocument()));
    settings->addAction(action, "editor-document-previous", editorCategory);

    mActions[SwitchDocument] = action = new QAction(tr("Switch Document"), this);
    connect(action, SIGNAL(triggered()), this, SLOT(switchDocument()));
    settings->addAction(action, "editor-document-switch", editorCategory);

    mActions[SplitHorizontally] = action = new QAction(tr("Split To Right"), this);
    // action->setShortcut( tr("Ctrl+P, 3", "Split To Right"));
    connect(action, SIGNAL(triggered()), this, SLOT(splitHorizontally()));
    settings->addAction(action, "editor-split-right", editorCategory);

    mActions[SplitVertically] = action = new QAction(tr("Split To Bottom"), this);
    // action->setShortcut( tr("Ctrl+P, 2", "Split To Bottom"));
    connect(action, SIGNAL(triggered()), this, SLOT(splitVertically()));
    settings->addAction(action, "editor-split-bottom", editorCategory);

    mActions[RemoveCurrentSplit] = action = new QAction(tr("Remove Current Split"), this);
    // action->setShortcut( tr("Ctrl+P, 1", "Remove Current Split"));
    connect(action, SIGNAL(triggered()), this, SLOT(removeCurrentSplit()));
    settings->addAction(action, "editor-split-remove", editorCategory);

    mActions[RemoveAllSplits] = action = new QAction(tr("Remove All Splits"), this);
    // action->setShortcut( tr("Ctrl+P, 0", "Remove All Splits"));
    connect(action, SIGNAL(triggered()), this, SLOT(removeAllSplits()));
    settings->addAction(action, "editor-split-remove-all", editorCategory);

    // Language

    mActions[EvaluateCurrentDocument] = action =
        new QAction(QIcon::fromTheme("media-playback-start"), tr("Evaluate &File"), this);
    action->setStatusTip(tr("Evaluate current File"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(evaluateDocument()),
                           SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-eval-file", editorCategory);

    mActions[EvaluateRegion] = action =
        new QAction(QIcon::fromTheme("media-playback-start"), tr("&Evaluate Selection, Line or Region"), this);
    action->setShortcut(tr("Ctrl+Return", "Evaluate region"));
    action->setStatusTip(tr("Evaluate current region"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(evaluateRegion()), SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-eval-smart", editorCategory);

    mActions[EvaluateLine] = action =
        new QAction(QIcon::fromTheme("media-playback-start"), tr("&Evaluate Selection or Line"), this);
    action->setShortcut(tr("Shift+Return", "Evaluate selection/line"));
    action->setStatusTip(tr("Evaluate current selection/line"));
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    mEditorSigMux->connect(action, SIGNAL(triggered()), SLOT(evaluateLine()), SignalMultiplexer::ConnectionOptional);
    settings->addAction(action, "editor-eval-line", editorCategory);

    // These actions are not added to any menu, so they have to be added
    // at least to this widget, in order for the shortcuts to always respond:
    addAction(mActions[TriggerAutoCompletion]);
    addAction(mActions[TriggerMethodCallAid]);
    addAction(mActions[SwitchDocument]);

    // These actions have to be added because to the widget because they have
    // Qt::WidgetWithChildrenShortcut context:
    addAction(mActions[Cut]);
    addAction(mActions[Copy]);
    addAction(mActions[Paste]);
    addAction(mActions[DocClose]);
    addAction(mActions[EnlargeFont]);
    addAction(mActions[ShrinkFont]);
    addAction(mActions[ShowWhitespace]);
    addAction(mActions[ShowLinenumber]);
    addAction(mActions[IndentWithSpaces]);
    addAction(mActions[EvaluateCurrentDocument]);
    addAction(mActions[EvaluateRegion]);
    addAction(mActions[EvaluateLine]);
    addAction(mActions[ToggleComment]);
    addAction(mActions[ToggleOverwriteMode]);
    addAction(mActions[CopyLineUp]);
    addAction(mActions[CopyLineDown]);
    addAction(mActions[MoveLineUp]);
    addAction(mActions[MoveLineDown]);
    addAction(mActions[DeleteWord]);
    addAction(mActions[GotoPreviousBlock]);
    addAction(mActions[GotoNextBlock]);
    addAction(mActions[SelectEnclosingBlock]);
    addAction(mActions[GotoPreviousRegion]);
    addAction(mActions[GotoNextRegion]);
    addAction(mActions[GotoPreviousEmptyLine]);
    addAction(mActions[GotoNextEmptyLine]);
    addAction(mActions[SelectRegion]);
}

void MultiEditor::updateActions() {
    GenericCodeEditor* editor = currentEditor();
    ScCodeEditor* scEditor = qobject_cast<ScCodeEditor*>(editor);
    QTextDocument* doc = editor ? editor->textDocument() : 0;

    mActions[Undo]->setEnabled(doc && doc->isUndoAvailable());
    mActions[Redo]->setEnabled(doc && doc->isRedoAvailable());
    mActions[Copy]->setEnabled(editor && editor->textCursor().hasSelection());
    mActions[Cut]->setEnabled(mActions[Copy]->isEnabled());
    mActions[Paste]->setEnabled(editor);
    mActions[ToggleOverwriteMode]->setEnabled(editor);
    mActions[CopyLineUp]->setEnabled(editor);
    mActions[CopyLineDown]->setEnabled(editor);
    mActions[MoveLineUp]->setEnabled(editor);
    mActions[MoveLineDown]->setEnabled(editor);
    mActions[DeleteWord]->setEnabled(editor);
    mActions[GotoPreviousEmptyLine]->setEnabled(editor);
    mActions[GotoNextEmptyLine]->setEnabled(editor);
    mActions[DocClose]->setEnabled(editor);
    mActions[EnlargeFont]->setEnabled(editor);
    mActions[ShrinkFont]->setEnabled(editor);
    mActions[ResetFontSize]->setEnabled(editor);
    mActions[IndentWithSpaces]->setEnabled(scEditor);
    mActions[IndentWithSpaces]->setChecked(scEditor && scEditor->spaceIndent());

    // ScLang-specific actions
    bool editorIsScCodeEditor = qobject_cast<ScCodeEditor*>(editor); // NOOP at the moment, but
    mActions[ToggleComment]->setEnabled(editor && editorIsScCodeEditor);
    mActions[GotoPreviousBlock]->setEnabled(editor && editorIsScCodeEditor);
    mActions[GotoNextBlock]->setEnabled(editor && editorIsScCodeEditor);
    mActions[SelectEnclosingBlock]->setEnabled(editor && editorIsScCodeEditor);
    mActions[GotoPreviousRegion]->setEnabled(editor && editorIsScCodeEditor);
    mActions[GotoNextRegion]->setEnabled(editor && editorIsScCodeEditor);
    mActions[SelectRegion]->setEnabled(editor && editorIsScCodeEditor);
    mActions[IndentLineOrRegion]->setEnabled(editor && editorIsScCodeEditor);

    mActions[EvaluateCurrentDocument]->setEnabled(editor && editorIsScCodeEditor);
    mActions[EvaluateRegion]->setEnabled(editor && editorIsScCodeEditor);
    mActions[EvaluateLine]->setEnabled(editor && editorIsScCodeEditor);
}

void MultiEditor::applySettings(Settings::Manager* settings) {
    bool show_whitespace = settings->value("IDE/editor/showWhitespace").toBool();
    bool show_linenumber = settings->value("IDE/editor/showLinenumber").toBool();
    bool show_autocompletehelp = settings->value("IDE/editor/showAutocompleteHelp").toBool();
    mActions[ShowWhitespace]->setChecked(show_whitespace);
    mActions[ShowLinenumber]->setChecked(show_linenumber);
    mActions[ShowAutocompleteHelp]->setChecked(show_autocompletehelp);

    setMainComboBoxOption();

    int boxCount = mSplitter->findChildren<CodeEditorBox*>().count();
    if (boxCount > 1) {
        activateComboBoxWhenSplitting();
    }
}

void MultiEditor::activateComboBoxWhenSplitting() {
    emit splitViewActivated();
    bool comboBoxInUse = Main::settings()->value("IDE/editor/useComboBox").toBool();
    if (!comboBoxInUse) {
        bool comboBoxWhenSplitting = Main::settings()->value("IDE/editor/useComboBoxWhenSplitting").toBool();
        showEditorTabs(comboBoxWhenSplitting);
    }
}

void MultiEditor::setMainComboBoxOption() {
    bool comboBoxInUse = Main::settings()->value("IDE/editor/useComboBox").toBool();
    showEditorTabs(comboBoxInUse);
}

void MultiEditor::showEditorTabs(bool condition) {
    if (condition)
        mTabs->hide();
    else
        mTabs->show();
}

static QVariantList saveBoxState(CodeEditorBox* box, const QList<Document*>& documentList) {
    // save editors in reverse order - first one is last shown.
    QVariantList boxData;
    int idx = box->history().count();
    while (idx--) {
        GenericCodeEditor* editor = box->history()[idx];
        if (!editor->document()->filePath().isEmpty()) {
            int documentIndex = documentList.indexOf(editor->document());
            Q_ASSERT(documentIndex >= 0);
            QVariantMap editorData;
            editorData.insert("documentIndex", documentIndex);
            editorData.insert("position", editor->textCursor().position());
            boxData.append(editorData);
        }
    }
    return boxData;
}

static QVariantMap saveSplitterState(QSplitter* splitter, const QList<Document*>& documentList) {
    QVariantMap splitterData;

    splitterData.insert("state", splitter->saveState().toBase64());

    QVariantList childrenData;

    int childCount = splitter->count();
    for (int idx = 0; idx < childCount; idx++) {
        QWidget* child = splitter->widget(idx);

        CodeEditorBox* box = qobject_cast<CodeEditorBox*>(child);
        if (box) {
            QVariantList boxData = saveBoxState(box, documentList);
            childrenData.append(QVariant(boxData));
            continue;
        }

        QSplitter* childSplitter = qobject_cast<QSplitter*>(child);
        if (childSplitter) {
            QVariantMap childSplitterData = saveSplitterState(childSplitter, documentList);
            childrenData.append(QVariant(childSplitterData));
        }
    }

    splitterData.insert("elements", childrenData);

    return splitterData;
}

void MultiEditor::saveSession(Session* session) {
    QList<Document*> documentList;

    QVariantList tabsData;
    int tabCount = mTabs->count();
    for (int tabIdx = 0; tabIdx < tabCount; ++tabIdx) {
        Document* doc = documentForTab(tabIdx);
        if (doc) {
            documentList << doc;
            tabsData << doc->filePath();
        }
    }

    session->setValue("documents", QVariant::fromValue(tabsData));

    session->remove("editors");
    session->setValue("editors", saveSplitterState(mSplitter, documentList));
}

void MultiEditor::loadBoxState(CodeEditorBox* box, const QVariantList& data, const QList<Document*>& documentList) {
    int docCount = documentList.count();
    foreach (QVariant docVar, data) {
        QVariantMap docData = docVar.value<QVariantMap>();
        int docIndex = docData.value("documentIndex").toInt();
        int docPos = docData.value("position").toInt();
        if (docIndex >= 0 && docIndex < docCount)
            box->setDocument(documentList[docIndex], docPos);
    }
}

void MultiEditor::loadSplitterState(MultiSplitter* splitter, const QVariantMap& data,
                                    const QList<Document*>& documentList) {
    QByteArray state = QByteArray::fromBase64(data.value("state").value<QByteArray>());

    QVariantList childrenData = data.value("elements").value<QVariantList>();
    foreach (const QVariant& childVar, childrenData) {
        if (childVar.type() == QVariant::List) {
            CodeEditorBox* childBox = newBox(splitter);
            splitter->addWidget(childBox);
            QVariantList childBoxData = childVar.value<QVariantList>();
            loadBoxState(childBox, childBoxData, documentList);
        } else if (childVar.type() == QVariant::Map) {
            MultiSplitter* childSplitter = new MultiSplitter(this);
            splitter->addWidget(childSplitter);
            QVariantMap childSplitterData = childVar.value<QVariantMap>();
            loadSplitterState(childSplitter, childSplitterData, documentList);
        }
    }

    if (!splitter->restoreState(state))
        qWarning("MultiEditor: could not restore splitter state!");
}

void MultiEditor::switchSession(Session* session) {
    ///// Going offline...

    breakSignalConnections();

    DocumentManager* docManager = Main::documentManager();

    QList<Document*> documentList = docManager->documents();

    // close all docs
    foreach (Document* doc, documentList)
        docManager->close(doc);

    // remove all tabs
    while (mTabs->count())
        mTabs->removeTab(0);

    // remove all editors
    delete mSplitter;

    documentList.clear();

    mSplitter = new MultiSplitter(this);

    CodeEditorBox* firstBox = 0;

    if (session) {
        // open documents saved in the session
        QVariantList docDataList = session->value("documents").value<QVariantList>();
        foreach (const QVariant& docData, docDataList) {
            QString filePath = docData.toString();
            Document* doc = docManager->open(filePath, -1, 0, true);
            documentList << doc;
        }

        // restore tabs
        for (int i = 0; i < documentList.size(); ++i)
            insertTab(documentList[i], i);

        // restore editors
        if (session->contains("editors")) {
            QVariantMap splitterData = session->value("editors").value<QVariantMap>();
            loadSplitterState(mSplitter, splitterData, documentList);

            if (mSplitter->count()) {
                firstBox = mSplitter->findChild<CodeEditorBox>();
                if (!firstBox) {
                    qWarning("Session seems to contain invalid editor split data!");
                    delete mSplitter;
                    mSplitter = new MultiSplitter(this);
                }
            }
        }
    }

    if (!firstBox) {
        // Restoring the session didn't result in any editor box, so create one:
        firstBox = newBox(mSplitter);
        mSplitter->addWidget(firstBox);
    }

    layout()->addWidget(mSplitter);

    makeSignalConnections();

    ///// Back online.

    mCurrentEditorBox = 0; // ensure complete update
    setCurrentBox(firstBox);

    if (!session)
        // create a document on new session
        docManager->create();

    firstBox->setFocus(Qt::OtherFocusReason); // ensure focus

    setMainComboBoxOption();
    if (mSplitter->count() > 1)
        activateComboBoxWhenSplitting();
    else
        emit splitViewDeactivated();
}

int MultiEditor::insertTab(Document* doc, int insertIndex) {
    if (!doc)
        return -1;

    int tabIdx = tabForDocument(doc);
    if (tabIdx != -1)
        return tabIdx;

    QTextDocument* tdoc = doc->textDocument();

    QIcon icon;
    if (tdoc->isModified())
        icon = mDocModifiedIcon;

    insertIndex = insertIndex < 0 ? mTabs->currentIndex() + 1 : insertIndex;
    tabIdx = mTabs->insertTab(insertIndex, icon, doc->title());
    mTabs->setTabData(tabIdx, QVariant::fromValue<Document*>(doc));

    connect(tdoc, &QTextDocument::modificationChanged, [this, doc](bool) { onDocModified(doc); });

    return tabIdx;
}

void MultiEditor::setCurrent(Document* doc) {
    int tabIdx = tabForDocument(doc);
    if (tabIdx != -1)
        mTabs->setCurrentIndex(tabIdx);
}

void MultiEditor::updateTabsOrder(QList<Document*> docOrder) {
    mTabs->blockSignals(true);
    for (int idx = 0; idx < docOrder.count(); idx++) {
        if (docOrder.at(idx) != documentForTab(idx)) {
            Document* doc = docOrder.at(idx);
            int tabIdx = tabForDocument(doc);
            mTabs->moveTab(tabIdx, idx);
        }
    }
    mTabs->blockSignals(false);
}

void MultiEditor::showNextDocument() {
    int currentIndex = mTabs->currentIndex();
    mTabs->setCurrentIndex((currentIndex + 1) % mTabs->count());
}

void MultiEditor::showPreviousDocument() {
    int currentIndex = mTabs->currentIndex();
    if (currentIndex == 0) {
        mTabs->setCurrentIndex(mTabs->count() - 1);
    } else {
        mTabs->setCurrentIndex(currentIndex - 1);
    }
}

void MultiEditor::switchDocument() {
    CodeEditorBox* box = currentBox();

    DocumentSelectPopUp* popup = new DocumentSelectPopUp(box->history(), this);

    QRect popupRect(0, 0, 300, 200);
    popupRect.moveCenter(rect().center());
    popup->resize(popupRect.size());
    QPoint globalPosition = mapToGlobal(popupRect.topLeft());

    Document* selectedDocument = popup->exec(globalPosition);

    if (selectedDocument)
        box->setDocument(selectedDocument);
}

void MultiEditor::onOpen(Document* doc, int initialCursorPosition, int selectionLength) {
    insertTab(doc);

    currentBox()->setDocument(doc, initialCursorPosition, selectionLength);
    currentBox()->setFocus(Qt::OtherFocusReason);
}

void MultiEditor::onClose(Document* doc) {
    int tabIdx = tabForDocument(doc);
    if (tabIdx != -1)
        mTabs->removeTab(tabIdx);
    // TODO: each box should switch document according to their own history
}

void MultiEditor::onDocModified(Document* doc) {
    if (!doc)
        return;

    int tabIdx = tabForDocument(doc);
    if (tabIdx == -1)
        return;

    bool isModified = doc->textDocument()->isModified();
    QIcon icon;
    if (isModified)
        icon = mDocModifiedIcon;

    Main::evaluateCodeIfCompiled(
        QStringLiteral("var doc = Document.findByQUuid(\'%1\'); doc !? { doc.prSetEdited(%2) };")
            .arg(doc->id().constData())
            .arg(isModified),
        true);

    mTabs->setTabIcon(tabIdx, icon);
}

void MultiEditor::show(Document* doc, int pos, int selectionLength) {
    currentBox()->setDocument(doc, pos, selectionLength);
    currentBox()->setFocus(Qt::OtherFocusReason);
}

void MultiEditor::update(Document* doc) {
    int tabIdx = tabForDocument(doc);
    if (tabIdx != -1)
        mTabs->setTabText(tabIdx, doc->title());

    // update thisProcess.nowExecutingPath
    GenericCodeEditor* editor = currentEditor();
    if (editor->document() == doc)
        Main::documentManager()->setActiveDocument(doc);
}

void MultiEditor::onCloseRequest(int index) {
    Document* doc = documentForTab(index);
    if (doc)
        MainWindow::close(doc);
}

void MultiEditor::onCurrentTabChanged(int index) {
    if (index == -1)
        return;

    Document* doc = documentForTab(index);
    if (!doc)
        return;

    CodeEditorBox* curBox = currentBox();
    curBox->setDocument(doc);
    curBox->setFocus(Qt::OtherFocusReason);
}

void MultiEditor::onCurrentEditorChanged(GenericCodeEditor* editor) { setCurrentEditor(editor); }

void MultiEditor::onBoxActivated(CodeEditorBox* box) { setCurrentBox(box); }

Document* MultiEditor::documentForTab(int index) {
    QVariant doc = mTabs->tabData(index);
    if (doc.isValid() && !doc.isNull())
        return doc.value<Document*>();
    else
        return NULL;
}

int MultiEditor::tabForDocument(Document* doc) {
    int tabCount = mTabs->count();
    for (int idx = 0; idx < tabCount; ++idx) {
        Document* tabDoc = documentForTab(idx);
        if (tabDoc && tabDoc == doc)
            return idx;
    }
    return -1;
}

CodeEditorBox* MultiEditor::newBox(MultiSplitter* currSplitter) {
    CodeEditorBox* box = new CodeEditorBox(currSplitter);

    connect(box, SIGNAL(activated(CodeEditorBox*)), this, SLOT(onBoxActivated(CodeEditorBox*)));

    return box;
}

void MultiEditor::setCurrentBox(CodeEditorBox* box) {
    if (mCurrentEditorBox == box)
        return;

    mCurrentEditorBox = box;
    mBoxSigMux->setCurrentObject(box);
    setCurrentEditor(box->currentEditor());

    mCurrentEditorBox->setActive();
}

void MultiEditor::setCurrentEditor(GenericCodeEditor* editor) {
    if (editor) {
        int tabIndex = tabForDocument(editor->document());
        if (tabIndex != -1)
            mTabs->setCurrentIndex(tabIndex);
    }

    mEditorSigMux->setCurrentObject(editor);
    updateActions();

    Document* currentDocument = editor ? editor->document() : 0;
    Main::documentManager()->setActiveDocument(currentDocument);
    emit currentDocumentChanged(currentDocument);
}

GenericCodeEditor* MultiEditor::currentEditor() { return currentBox()->currentEditor(); }

void MultiEditor::split(Qt::Orientation splitDirection) {
    CodeEditorBox* box = newBox(mSplitter);
    CodeEditorBox* curBox = currentBox();
    GenericCodeEditor* curEditor = curBox->currentEditor();

    if (curEditor)
        box->setDocument(curEditor->document(), curEditor->textCursor().position());

    mSplitter->insertWidget(box, curBox, splitDirection);
    box->setFocus(Qt::OtherFocusReason);

    activateComboBoxWhenSplitting();
}

void MultiEditor::removeCurrentSplit() {
    int boxCount = mSplitter->findChildren<CodeEditorBox*>().count();
    if (boxCount < 2) {
        // Do not allow removing the one and only box.
        return;
    }

    CodeEditorBox* box = currentBox();
    mSplitter->removeWidget(box);

    // switch current box to first box found:
    box = mSplitter->findChild<CodeEditorBox>();
    Q_ASSERT(box);
    setCurrentBox(box);
    box->setFocus(Qt::OtherFocusReason);

    if (boxCount == 2) {
        emit splitViewDeactivated();
        setMainComboBoxOption();
    } else if (boxCount > 2) {
        activateComboBoxWhenSplitting();
    }
}

void MultiEditor::removeAllSplits() {
    CodeEditorBox* box = currentBox();
    Q_ASSERT(box);
    Q_ASSERT(mSplitter->count());
    if (mSplitter->count() == 1 && mSplitter->widget(0) == box)
        // Nothing to do.
        return;

    breakSignalConnections();

    MultiSplitter* newSplitter = new MultiSplitter(this);

    CodeEditorBox* nBox = newBox(newSplitter);
    newSplitter->addWidget(nBox);

    GenericCodeEditor* curEditor = box->currentEditor();
    if (curEditor)
        nBox->setDocument(curEditor->document(), curEditor->textCursor().position());

    delete mSplitter;
    mSplitter = newSplitter;
    layout()->addWidget(mSplitter);

    emit splitViewDeactivated();
    setMainComboBoxOption();

    mCurrentEditorBox = 0; // ensure complete update
    setCurrentBox(nBox);

    makeSignalConnections(); // ensure signal connections

    nBox->setFocus(Qt::OtherFocusReason);
}

void MultiEditor::setShowWhitespace(bool showWhitespace) {
    Main::settings()->setValue("IDE/editor/showWhitespace", showWhitespace);
    Main::instance()->applySettings();
}

void MultiEditor::setShowLinenumber(bool showLinenumber) {
    Main::settings()->setValue("IDE/editor/showLinenumber", showLinenumber);
    Main::instance()->applySettings();
}

void MultiEditor::setShowAutocompleteHelp(bool showAutocompleteHelp) {
    Main::settings()->setValue("IDE/editor/showAutocompleteHelp", showAutocompleteHelp);
}

} // namespace ScIDE
