OSDN Git Service

[denncoCreator] fixed a crash bug.
[dennco/denncoCreator.git] / Source / mainwindow.cpp
index 978af16..d9f74b6 100644 (file)
 #include "ui_mainwindow.h"
 
 #include "dccreator.h"
+#include "dccontent.h"
 #include "dcglvisualizerwidget.h"
 #include "dctreeviewwidget.h"
+#include "dccellcodescripttreeviewwidget.h"
 #include "TKConsole.h"
 #include "utils/dcresources.h"
 #include "utils/dcskeltoncreatorutil.h"
+#include "dialog/dcinputnewcontentdirdialog.h"
+#include "dialog/dcmanagecellcodedialog.h"
+#include "dialog/dccodeeditorexternaleditorsettingdialog.h"
+#include "dccellscriptseditorwindow.h"
 
 #include <QCloseEvent>
 #include <QFileDialog>
 #include <QMessageBox>
 #include <QSettings>
+#include <QLocalSocket>
+
+#if defined(Q_WS_WIN)
+    const QString DENNCO_ENGINE = "QtDennco.exe";
+#elif defined(Q_WS_MAC)
+    const QString DENNCO_ENGINE = "QtDennco.app";
+#elif defined(Q_OS_UNIX)
+    const QString DENNCO_ENGINE = "./QtDennco";
+#endif
+
+class SleeperThread : public QThread
+{
+public:
+    static void msleep(unsigned long msecs)
+    {
+        QThread::msleep(msecs);
+    }
+};
 
 MainWindow::MainWindow(QWidget *parent) :
     QMainWindow(parent),
@@ -50,28 +74,33 @@ MainWindow::MainWindow(QWidget *parent) :
 
     TKLog::setDestination(new TKConsole);
 
-    mCreator = new DCCreator(this);
-    mVisualizerWidget = new DCGLVisualizerWidget(mCreator, this) ;
-    setCentralWidget(mVisualizerWidget);
+    d_creator = new DCCreator(this);
+    d_visualizerWidget = new DCGLVisualizerWidget(d_creator, this) ;
+    setCentralWidget(d_visualizerWidget);
 
-    mTreeViewWidget = new DCTreeViewWidget(this, mCreator);
-    ui->treeViewDock->layout()->addWidget(mTreeViewWidget);
+    d_treeViewWidget = new DCTreeViewWidget(this, d_creator);
+    ui->treeViewDock->layout()->addWidget(d_treeViewWidget);
+
+    d_cellCodeScriptTreeViewWidget = new DCCellCodeScriptTreeViewWidget(this, d_creator);
+    ui->cellCodeScriptTreeViewDock->layout()->addWidget(d_cellCodeScriptTreeViewWidget);
+
+    DCCellScriptsEditorWindow::construct(d_creator);
 
     setCurrentContent("");
     setUnifiedTitleAndToolBarOnMac(true);
+
+    tabifyDockWidget(ui->dock2,ui->dock1);
 }
 
 MainWindow::~MainWindow()
 {
     delete ui;
-    if (mCreator)
-        delete mCreator;
+    if (d_creator)
+        delete d_creator;
 }
 
 
-//! [3]
 void MainWindow::closeEvent(QCloseEvent *event)
-//! [3] //! [4]
 {
     if (maybeSave()) {
         writeSettings();
@@ -83,8 +112,18 @@ void MainWindow::closeEvent(QCloseEvent *event)
 
 void MainWindow::newFile()
 {
-    QString dirName = QFileDialog::getSaveFileName(this, tr("Create new content"));
-    if (!dirName.isEmpty() && DCSkeltonCreatorUtil::createNewContent(dirName))
+    QString bdir = QDir::home().absolutePath();
+    if (d_contentOpenHistory.length()>0)
+    {
+        QDir d(d_contentOpenHistory.at(0));
+        d.cdUp();
+        bdir = d.absolutePath();
+    }
+    DCInputNewContentDirDialog dialog(bdir);
+    dialog.exec();
+
+    QString dirName = dialog.getResult();
+    if (dirName.length() > 0 && DCSkeltonCreatorUtil::createNewContent(dirName))
     {
         loadContent(dirName);
     }
@@ -92,18 +131,70 @@ void MainWindow::newFile()
 
 void MainWindow::open()
 {
-    if (maybeSave()) {
-        QString dirName = QFileDialog::getExistingDirectory(this, tr("Open a content"));
+    if (maybeSave())
+    {
+        QString dir = QDir::home().absolutePath();
+        if (d_contentOpenHistory.length()>0)
+        {
+            QDir d(d_contentOpenHistory.at(0));
+            d.cdUp();
+            dir = d.absolutePath();
+        }
+        QString dirName = QFileDialog::getExistingDirectory(this, tr("Open a content"),dir);
         if (!dirName.isEmpty())
             loadContent(dirName);
     }
 }
-//! [8]
 
-//! [9]
+bool MainWindow::openRecent(int idx)
+{
+    if (maybeSave())
+    {
+        if (d_contentOpenHistory.length() > idx)
+        {
+            loadContent(QString(d_contentOpenHistory.at(idx)));
+            return true;
+        }
+    }
+    return false;
+}
+
+void MainWindow::openRecent1()
+{
+    openRecent(0);
+}
+
+void MainWindow::openRecent2()
+{
+    openRecent(1);
+}
+
+void MainWindow::openRecent3()
+{
+    openRecent(2);
+}
+
+void MainWindow::openRecent4()
+{
+    openRecent(3);
+}
+
+void MainWindow::openRecent5()
+{
+    openRecent(4);
+}
+
+bool MainWindow::save(bool showMessage)
+{
+    if (!d_creator)
+        return false;
+
+    return d_creator->saveAll(showMessage);
+}
+
 bool MainWindow::save()
 {
-    return saveContent();
+    return save(true);
 }
 
 bool MainWindow::saveAs()
@@ -112,6 +203,12 @@ bool MainWindow::saveAs()
     return false;
 }
 
+void MainWindow::doExternalEditorSetting()
+{
+    DCCodeEditorExternalEditorSettingDialog dialog(this);
+    dialog.exec();
+}
+
 void MainWindow::about()
 {
    QMessageBox::about(this, tr("About Application"),
@@ -127,21 +224,37 @@ void MainWindow::documentWasModified()
 }
 //! [16]
 
-//! [17]
 void MainWindow::createActions()
-//! [17] //! [18]
 {
     newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this);
     newAct->setShortcuts(QKeySequence::New);
     newAct->setStatusTip(tr("Create a new file"));
     connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
 
-//! [19]
     openAct = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this);
     openAct->setShortcuts(QKeySequence::Open);
     openAct->setStatusTip(tr("Open an existing file"));
     connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
-//! [18] //! [19]
+
+    QAction *openRecentAct = new QAction(this);
+    connect(openRecentAct, SIGNAL(triggered()), this, SLOT(openRecent1()));
+    openRecentActs.append(openRecentAct);
+
+    openRecentAct = new QAction(this);
+    connect(openRecentAct, SIGNAL(triggered()), this, SLOT(openRecent2()));
+    openRecentActs.append(openRecentAct);
+
+    openRecentAct = new QAction(this);
+    connect(openRecentAct, SIGNAL(triggered()), this, SLOT(openRecent3()));
+    openRecentActs.append(openRecentAct);
+
+    openRecentAct = new QAction(this);
+    connect(openRecentAct, SIGNAL(triggered()), this, SLOT(openRecent4()));
+    openRecentActs.append(openRecentAct);
+
+    openRecentAct = new QAction(this);
+    connect(openRecentAct, SIGNAL(triggered()), this, SLOT(openRecent5()));
+    openRecentActs.append(openRecentAct);
 
     saveAct = new QAction(QIcon(":/images/save.png"), tr("&Save"), this);
     saveAct->setShortcuts(QKeySequence::Save);
@@ -153,16 +266,15 @@ void MainWindow::createActions()
     saveAsAct->setStatusTip(tr("Save the document under a new name"));
     connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
 
-//! [20]
     exitAct = new QAction(tr("E&xit"), this);
     exitAct->setShortcuts(QKeySequence::Quit);
-//! [20]
     exitAct->setStatusTip(tr("Exit the application"));
     connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
 
-//! [21]
+    manageCellCodeAct = new QAction(tr("Manage Cell Code..."), this);
+    connect(manageCellCodeAct, SIGNAL(triggered()), this, SLOT(manageCellCode()));
+
     cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this);
-//! [21]
     cutAct->setShortcuts(QKeySequence::Cut);
     cutAct->setStatusTip(tr("Cut the current selection's contents to the "
                             "clipboard"));
@@ -178,67 +290,88 @@ void MainWindow::createActions()
     pasteAct->setShortcuts(QKeySequence::Paste);
     pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
                               "selection"));
-//    connect(pasteAct, SIGNAL(triggered()), textEdit, SLOT(paste()));
+
+    //    connect(pasteAct, SIGNAL(triggered()), textEdit, SLOT(paste()));
+
+    playAct = new QAction(QIcon(":/images/playbutton.png"), tr("Play"), this);
+    playAct->setStatusTip(tr("Play the editing content"));
+
+    connect(playAct, SIGNAL(triggered()), this, SLOT(playContent()));
+
+    externalEditorSettingAct = new QAction(tr("&External editor..."), this);
+    externalEditorSettingAct->setStatusTip(tr("Setup properties for external code editor."));
+    connect(externalEditorSettingAct, SIGNAL(triggered()), this, SLOT(doExternalEditorSetting()));
 
     aboutAct = new QAction(tr("&About"), this);
     aboutAct->setStatusTip(tr("Show the application's About box"));
     connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
 
     cutAct->setEnabled(false);
-//! [23] //! [24]
     copyAct->setEnabled(false);
+    playAct->setEnabled(false);
 //    connect(textEdit, SIGNAL(copyAvailable(bool)),
 //            cutAct, SLOT(setEnabled(bool)));
 //    connect(textEdit, SIGNAL(copyAvailable(bool)),
 //            copyAct, SLOT(setEnabled(bool)));
 }
-//! [24]
 
-//! [25] //! [26]
 void MainWindow::createMenus()
-//! [25] //! [27]
 {
     fileMenu = menuBar()->addMenu(tr("&File"));
     fileMenu->addAction(newAct);
-//! [28]
     fileMenu->addAction(openAct);
-//! [28]
+    openRecentMenu = fileMenu->addMenu(tr("Opened recently"));
     fileMenu->addAction(saveAct);
-//! [26]
     fileMenu->addAction(saveAsAct);
     fileMenu->addSeparator();
     fileMenu->addAction(exitAct);
 
     editMenu = menuBar()->addMenu(tr("&Edit"));
+    editMenu->addAction(manageCellCodeAct);
+    editMenu->addSeparator();
     editMenu->addAction(cutAct);
     editMenu->addAction(copyAct);
     editMenu->addAction(pasteAct);
 
     menuBar()->addSeparator();
 
+    editMenu = menuBar()->addMenu(tr("&Play"));
+    editMenu->addAction(playAct);
+
+    menuBar()->addSeparator();
+
+    settingMenu = menuBar()->addMenu(tr("&Setting"));
+    settingMenu->addAction(externalEditorSettingAct);
     helpMenu = menuBar()->addMenu(tr("&Help"));
     helpMenu->addAction(aboutAct);
 }
-//! [27]
 
-//! [29] //! [30]
+void MainWindow::createOpenRecentMenu()
+{
+    openRecentMenu->clear();
+    for (int i = 0; i < d_contentOpenHistory.length() && i < openRecentActs.length(); i++)
+    {
+        openRecentActs.at(i)->setText(d_contentOpenHistory.at(i));
+        openRecentMenu->addAction(openRecentActs.at(i));
+    }
+}
+
 void MainWindow::createToolBars()
 {
     fileToolBar = addToolBar(tr("File"));
     fileToolBar->addAction(newAct);
-//! [29] //! [31]
     fileToolBar->addAction(openAct);
-//! [31]
     fileToolBar->addAction(saveAct);
 
     editToolBar = addToolBar(tr("Edit"));
     editToolBar->addAction(cutAct);
     editToolBar->addAction(copyAct);
     editToolBar->addAction(pasteAct);
+
+    playToolBar = addToolBar(tr("Play"));
+    playToolBar->addAction(playAct);
 }
-//! [30]
 
-//! [32]
 void MainWindow::createStatusBar()
 //! [32] //! [33]
 {
@@ -246,77 +379,128 @@ void MainWindow::createStatusBar()
 }
 //! [33]
 
-//! [34] //! [35]
 void MainWindow::readSettings()
-//! [34] //! [36]
 {
     QSettings settings("dennco project", "dennco creator");
     QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
     QSize size = settings.value("size", QSize(400, 400)).toSize();
+    d_contentOpenHistory = settings.value("contents", QStringList()).toStringList();
+
     resize(size);
     move(pos);
+    createOpenRecentMenu();
 }
-//! [35] //! [36]
 
-//! [37] //! [38]
 void MainWindow::writeSettings()
-//! [37] //! [39]
 {
     QSettings settings("dennco project", "dennco creator");
     settings.setValue("pos", pos());
     settings.setValue("size", size());
+    settings.setValue("contents", d_contentOpenHistory);
 }
-//! [38] //! [39]
 
-//! [40]
-bool MainWindow::maybeSave()
-//! [40] //! [41]
-{
-//    if (textEdit->document()->isModified()) {
- //       QMessageBox::StandardButton ret;
- //       ret = QMessageBox::warning(this, tr("Application"),
- //                    tr("The document has been modified.\n"
-//                        "Do you want to save your changes?"),
-//                     QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
-//        if (ret == QMessageBox::Save)
-//            return save();
-//        else if (ret == QMessageBox::Cancel)
-//            return false;
-//    }
-    return true;
+//static
+QByteArray MainWindow::readSettingsForCellScriptsEditorGeometory()
+{
+    QSettings settings("dennco project", "dennco creator");
+    return settings.value("segeometory").toByteArray();
 }
-//! [41]
 
-//! [42]
-void MainWindow::loadContent(const QString &contentDirectory)
+//static
+void MainWindow::writeSettingsForCellScriptsEditorGeometory(const QByteArray &value)
 {
-    if (!mCreator)
-        return;
+    QSettings settings("dennco project", "dennco creator");
+    settings.setValue("segeometory", value);
+}
 
-    mCreator->loadContent(contentDirectory);
+//static
+QString MainWindow::readSettingsForExternalScriptEditorPath()
+{
+    QSettings settings("dennco project", "dennco creator");
+    return settings.value("external editor path").toString();
+}
 
-    setCurrentContent(contentDirectory);
-    statusBar()->showMessage(tr("Content loaded"), 2000);
+//static
+QString MainWindow::readSettingsForExternalScriptEditorParameters()
+{
+    QSettings settings("dennco project", "dennco creator");
+    return settings.value("external editor param").toString();
 }
 
-bool MainWindow::saveContent()
+//static
+void MainWindow::writeSettingsForExternalScriptEditorPath(const QString &arg)
 {
-    if (!mCreator)
-        return false;
+    QSettings settings("dennco project", "dennco creator");
+    settings.setValue("external editor path", arg);
+}
+
+//static
+void MainWindow::writeSettingsForExternalScriptEditorParameters(const QString &arg)
+{
+    QSettings settings("dennco project", "dennco creator");
+    settings.setValue("external editor param", arg);
+}
 
-    if (mCreator->getCurrentContainer())
+bool MainWindow::maybeSave()
+{
+    if (d_creator->getCurrentContent())
     {
-        mCreator->saveAll();
-        statusBar()->showMessage(tr("Content saved"), 2000);
+        if (!DCCellScriptsEditorWindow::closeEditor())
+            return false;
+
+        if (d_creator->getCurrentContent()->getIsModified())
+        {
+            QMessageBox::StandardButton ret;
+            ret = QMessageBox::warning(this, tr("Application"),
+                tr("The content has been modified.\n"
+                "Do you want to save your changes?"),
+                QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
+            if (ret == QMessageBox::Save)
+                return save(false);
+            else if (ret == QMessageBox::Cancel)
+                return false;
+        }
     }
-
     return true;
 }
 
+void MainWindow::loadContent(const QString &contentDirectory)
+{
+    if (!d_creator)
+        return;
+
+    if (d_creator->loadContent(contentDirectory))
+    {
+        playAct->setEnabled(true);
+    }
+    else
+    {
+        playAct->setEnabled(false);
+    }
+
+    QString absContentDirectory = QDir().absoluteFilePath(contentDirectory);
+    int idx = d_contentOpenHistory.indexOf(absContentDirectory);
+    if (idx != -1)
+    {
+        d_contentOpenHistory.removeAt(idx);
+    }
+    d_contentOpenHistory.prepend(absContentDirectory);
+    while (d_contentOpenHistory.length()>5)
+    {
+        d_contentOpenHistory.removeLast();
+    }
+    setCurrentContent(contentDirectory);
+    createOpenRecentMenu();
+
+    QDir dir(contentDirectory);
+    QString title = dir.dirName();
+    title.append(" - dennco creator");
+    setWindowTitle(title);
+}
+
 void MainWindow::setCurrentContent(const QString &contentDirectory)
 {
     curContent = contentDirectory;
-//    textEdit->document()->setModified(false);
     setWindowModified(false);
 
     QString shownName = curContent;
@@ -324,12 +508,147 @@ void MainWindow::setCurrentContent(const QString &contentDirectory)
         shownName = "untitled.txt";
     setWindowFilePath(shownName);
 }
-//! [47]
 
-//! [48]
 QString MainWindow::strippedName(const QString &fullFileName)
-//! [48] //! [49]
 {
     return QFileInfo(fullFileName).fileName();
 }
-//! [49]
+
+void MainWindow::playContent()
+{
+    if (!d_creator || !d_creator->getCurrentContent())
+        return;
+
+    maybeSave();
+
+    if (d_player.state() != QProcess::NotRunning)
+    {
+        QLocalSocket *socket = new QLocalSocket(this);
+        connect(socket, SIGNAL(disconnected()), socket,SLOT(deleteLater()));
+
+        for (int retry = 0; retry < 20; retry++)
+        {
+            socket->connectToServer(d_IPCServerName);
+            if (socket->waitForConnected())
+            {
+                break;
+            }
+            SleeperThread::msleep(500);
+        }
+        QString requestData = "close,";
+        socket->write(requestData.toLocal8Bit());
+        socket->flush();
+        socket->waitForBytesWritten();
+        socket->close();
+
+        if (!d_player.waitForFinished())
+            d_player.kill();
+    }
+
+    d_IPCServerName = "denncoCreator_";
+    QTextStream s(&d_IPCServerName);
+    s.setIntegerBase(16);
+    s << qrand();
+
+    if (d_player.state() == QProcess::NotRunning)
+    {
+        QStringList args;
+#ifdef Q_WS_MAC
+        args << QCoreApplication::applicationDirPath() + "/../../../" + DENNCO_ENGINE;
+        args << "--args";
+#endif
+        args << "-creatorControlled";
+        args << d_IPCServerName;
+
+#ifdef Q_WS_MAC
+        d_player.start("open" , args);
+#else
+        d_player.start(DENNCO_ENGINE, args);
+#endif
+        d_player.waitForStarted();
+    }
+
+    if (d_player.state() == QProcess::Running)
+    {
+        QLocalSocket *socket = new QLocalSocket(this);
+        connect(socket, SIGNAL(disconnected()), socket,SLOT(deleteLater()));
+        for (int retry = 0; retry < 20; retry++)
+        {
+            socket->connectToServer(d_IPCServerName);
+            if (socket->waitForConnected())
+            {
+                break;
+            }
+            SleeperThread::msleep(500);
+        }
+        QString requestData = "load,";
+        requestData.append(d_creator->getCurrentContent()->getContentRootPath());
+        socket->write(requestData.toLocal8Bit());
+        socket->flush();
+        socket->waitForBytesWritten();
+        socket->close();
+    }
+}
+
+void MainWindow::manageCellCode()
+{
+    if (!d_creator)
+        return;
+
+    DCManageCellCodeDialog dialog(d_creator, NULL, this);
+    dialog.exec();
+}
+
+
+//static
+bool MainWindow::openExternalEditorFor(const QString &path)
+{
+    static QList<QProcess*> s_processes;
+    static QMutex s_mutex;
+
+    QMutexLocker locker(&s_mutex);
+
+    QString editorPath = readSettingsForExternalScriptEditorPath();
+    if (editorPath.isEmpty() || editorPath.length() == 0)
+    {
+        DCCodeEditorExternalEditorSettingDialog dialog;
+        dialog.exec();
+        editorPath = readSettingsForExternalScriptEditorPath();
+    }
+    if (editorPath.isEmpty() || editorPath.length() == 0)
+        return false;
+
+    QString parameterOrg = readSettingsForExternalScriptEditorParameters();
+    QString parameter = "";
+    int i = 0;
+    int j = parameterOrg.indexOf(QRegExp("%F[ \t\"']|%F$"),i);
+    while (j >= 0)
+    {
+        parameter += parameterOrg.mid(i, j-i);
+        parameter += path;
+        i = j + 2;
+        if (i > parameterOrg.length())
+            break;
+        j = parameterOrg.indexOf(QRegExp("%F[ \t\"']|%F$"),i);
+    }
+    if (i < parameterOrg.length())
+        parameter += parameterOrg.mid(i);
+
+    QList<QProcess*>::iterator it = s_processes.begin();
+    while (it != s_processes.end())
+    {
+        if ((*it)->state() != QProcess::Running)
+        {
+            delete (*it);
+            it = s_processes.erase(it);
+        }
+        else
+            ++it;
+    }
+    QProcess *newProcess = new QProcess;
+    newProcess->start("\"" + editorPath + "\" " + parameter);
+
+    s_processes.append(newProcess);
+
+    return true;
+}