From 21fbbc2c156a419cd90abb7af20e8800ea97d631 Mon Sep 17 00:00:00 2001
From: Lasse Holmstedt <lasse.holmstedt@nokia.com>
Date: Fri, 23 Apr 2010 13:19:28 +0200
Subject: [PATCH] Added preview menu and shortcuts for qt quick (Ctrl+Alt+R)
 This was needed since we cannot start stuff otherwise without a project

Task-number: BAUHAUS-450
Reviewed-by: kkoehne
---
 src/plugins/qmldesigner/designmodecontext.cpp |  4 +-
 .../qmldesigner/qmldesignerconstants.h        |  3 ++
 .../qmljseditor/QmlJSEditor.pluginspec        |  1 +
 src/plugins/qmljseditor/qmljseditor.cpp       |  1 +
 src/plugins/qmljseditor/qmljseditor.h         |  1 +
 src/plugins/qmljseditor/qmljseditor.pro       |  6 ++-
 .../qmljseditor/qmljseditor_dependencies.pri  |  1 +
 .../qmljseditor/qmljseditorconstants.h        |  5 ++
 src/plugins/qmljseditor/qmljseditorplugin.cpp | 41 ++++++++++++++++-
 src/plugins/qmljseditor/qmljseditorplugin.h   | 18 ++++++++
 .../qmljseditor/qmljspreviewrunner.cpp        | 46 +++++++++++++++++++
 src/plugins/qmljseditor/qmljspreviewrunner.h  | 34 ++++++++++++++
 12 files changed, 156 insertions(+), 5 deletions(-)
 create mode 100644 src/plugins/qmljseditor/qmljspreviewrunner.cpp
 create mode 100644 src/plugins/qmljseditor/qmljspreviewrunner.h

diff --git a/src/plugins/qmldesigner/designmodecontext.cpp b/src/plugins/qmldesigner/designmodecontext.cpp
index baddfa1c779..5f6fd8fcb38 100644
--- a/src/plugins/qmldesigner/designmodecontext.cpp
+++ b/src/plugins/qmldesigner/designmodecontext.cpp
@@ -39,7 +39,9 @@ namespace Internal {
 DesignModeContext::DesignModeContext(DesignModeWidget *widget) : IContext(widget),
     m_widget(widget)
 {
-    m_context << Core::UniqueIDManager::instance()->uniqueIdentifier(Constants::C_FORMEDITOR);
+    Core::UniqueIDManager *uuidManager =Core::UniqueIDManager::instance();
+    m_context << uuidManager->uniqueIdentifier(Constants::C_FORMEDITOR)
+              << uuidManager->uniqueIdentifier(Constants::C_QT_QUICK_TOOLS_MENU);
 }
 
 DesignModeContext::~DesignModeContext()
diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h
index fc2313a72f8..6c2817d6884 100644
--- a/src/plugins/qmldesigner/qmldesignerconstants.h
+++ b/src/plugins/qmldesigner/qmldesignerconstants.h
@@ -39,6 +39,9 @@ const char * const DELETE               = "QmlDesigner.Delete";
 const char * const C_DESIGN_MODE        = "QmlDesigner::DesignMode";
 const char * const C_FORMEDITOR         = "QmlDesigner::QmlFormEditor";
 
+// special context for preview menu, shared b/w designer and text editor
+const char * const C_QT_QUICK_TOOLS_MENU = "QmlDesigner::ToolsMenu";
+
 // actions
 const char * const SWITCH_TEXT_DESIGN   = "QmlDesigner.SwitchTextDesign";
 
diff --git a/src/plugins/qmljseditor/QmlJSEditor.pluginspec b/src/plugins/qmljseditor/QmlJSEditor.pluginspec
index 478fa0819f8..f5f242c05ad 100644
--- a/src/plugins/qmljseditor/QmlJSEditor.pluginspec
+++ b/src/plugins/qmljseditor/QmlJSEditor.pluginspec
@@ -16,5 +16,6 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <dependencyList>
         <dependency name="Core" version="1.3.84"/>
         <dependency name="TextEditor" version="1.3.84"/>
+        <dependency name="ProjectExplorer" version="1.3.84"/>
     </dependencyList>
 </plugin>
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index d2764ae2f96..9afd59c903b 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -577,6 +577,7 @@ QmlJSEditorEditable::QmlJSEditorEditable(QmlJSTextEditor *editor)
     Core::UniqueIDManager *uidm = Core::UniqueIDManager::instance();
     m_context << uidm->uniqueIdentifier(QmlJSEditor::Constants::C_QMLJSEDITOR_ID);
     m_context << uidm->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+    m_context << uidm->uniqueIdentifier(QmlDesigner::Constants::C_QT_QUICK_TOOLS_MENU);
 }
 
 // Use preferred mode from Bauhaus settings
diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h
index 1fb222e51b5..49fb1222a23 100644
--- a/src/plugins/qmljseditor/qmljseditor.h
+++ b/src/plugins/qmljseditor/qmljseditor.h
@@ -215,6 +215,7 @@ public:
 public slots:
     void followSymbolUnderCursor();
     virtual void setFontSettings(const TextEditor::FontSettings &);
+    void openPreview();
 
 private slots:
     void onDocumentUpdated(QmlJS::Document::Ptr doc);
diff --git a/src/plugins/qmljseditor/qmljseditor.pro b/src/plugins/qmljseditor/qmljseditor.pro
index fd3fca3966d..0f0c3e238ce 100644
--- a/src/plugins/qmljseditor/qmljseditor.pro
+++ b/src/plugins/qmljseditor/qmljseditor.pro
@@ -21,7 +21,8 @@ HEADERS += \
     qmljshighlighter.h \
     qmljshoverhandler.h \
     qmljsmodelmanager.h \
-    qmljsmodelmanagerinterface.h
+    qmljsmodelmanagerinterface.h \
+    qmljspreviewrunner.h
 
 SOURCES += \
     qmljscodecompletion.cpp \
@@ -34,7 +35,8 @@ SOURCES += \
     qmljshighlighter.cpp \
     qmljshoverhandler.cpp \
     qmljsmodelmanager.cpp \
-    qmljsmodelmanagerinterface.cpp
+    qmljsmodelmanagerinterface.cpp \
+    qmljspreviewrunner.cpp
 
 RESOURCES += qmljseditor.qrc
 OTHER_FILES += QmlJSEditor.pluginspec QmlJSEditor.mimetypes.xml
diff --git a/src/plugins/qmljseditor/qmljseditor_dependencies.pri b/src/plugins/qmljseditor/qmljseditor_dependencies.pri
index 987e47a74d7..c478dc233f9 100644
--- a/src/plugins/qmljseditor/qmljseditor_dependencies.pri
+++ b/src/plugins/qmljseditor/qmljseditor_dependencies.pri
@@ -1,5 +1,6 @@
 include(../../plugins/coreplugin/coreplugin.pri)
 include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
 include(../../shared/indenter/indenter.pri)
 include(../../libs/qmljs/qmljs.pri)
 include(../../libs/utils/utils.pri)
diff --git a/src/plugins/qmljseditor/qmljseditorconstants.h b/src/plugins/qmljseditor/qmljseditorconstants.h
index 6dc041aff57..0db49ad417f 100644
--- a/src/plugins/qmljseditor/qmljseditorconstants.h
+++ b/src/plugins/qmljseditor/qmljseditorconstants.h
@@ -35,7 +35,10 @@
 namespace QmlJSEditor {
 namespace Constants {
 
+// menus
+const char * const M_QTQUICK = "QtQuickDesigner.Menu";
 const char * const M_CONTEXT = "QML JS Editor.ContextMenu";
+
 const char * const RUN_SEP = "QmlJSEditor.Run.Separator";
 const char * const C_QMLJSEDITOR_ID = "QMLProjectManager.QMLJSEditor";
 const char * const C_QMLJSEDITOR_DISPLAY_NAME = QT_TRANSLATE_NOOP("OpenWith::Editors", "QMLJS Editor");
@@ -46,6 +49,8 @@ const char * const FOLLOW_SYMBOL_UNDER_CURSOR = "QmlJSEditor.FollowSymbolUnderCu
 const char * const QML_MIMETYPE = "application/x-qml";
 const char * const JS_MIMETYPE = "application/javascript";
 
+
+
 } // namespace Constants
 } // namespace QmlJSEditor
 
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp
index e1171190cd8..a2b005f416e 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.cpp
+++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp
@@ -36,6 +36,9 @@
 #include "qmljshoverhandler.h"
 #include "qmljsmodelmanager.h"
 #include "qmlfilewizard.h"
+#include "qmljspreviewrunner.h"
+
+#include <qmldesigner/qmldesignerconstants.h>
 
 #include <coreplugin/icore.h>
 #include <coreplugin/coreconstants.h>
@@ -61,6 +64,7 @@
 #include <QtCore/QSettings>
 #include <QtCore/QDir>
 #include <QtCore/QCoreApplication>
+#include <QtGui/QMenu>
 #include <QtGui/QAction>
 
 using namespace QmlJSEditor;
@@ -96,7 +100,8 @@ bool QmlJSEditorPlugin::initialize(const QStringList & /*arguments*/, QString *e
     addAutoReleasedObject(m_modelManager);
 
     QList<int> context;
-    context<< core->uniqueIDManager()->uniqueIdentifier(QmlJSEditor::Constants::C_QMLJSEDITOR_ID);
+    context << core->uniqueIDManager()->uniqueIdentifier(QmlJSEditor::Constants::C_QMLJSEDITOR_ID)
+            << core->uniqueIDManager()->uniqueIdentifier(QmlDesigner::Constants::C_QT_QUICK_TOOLS_MENU);
 
     m_editor = new QmlJSEditorFactory(this);
     addObject(m_editor);
@@ -118,7 +123,18 @@ bool QmlJSEditorPlugin::initialize(const QStringList & /*arguments*/, QString *e
     Core::ActionManager *am =  core->actionManager();
     Core::ActionContainer *contextMenu = am->createMenu(QmlJSEditor::Constants::M_CONTEXT);
 
-    Core::Command *cmd = 0;
+    Core::ActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS);
+    Core::ActionContainer *menuQtQuick = am->createMenu(Constants::M_QTQUICK);
+    menuQtQuick->menu()->setTitle(tr("Qt Quick"));
+    mtools->addMenu(menuQtQuick);
+    m_actionPreview = new QAction("&Preview", this);
+
+    QList<int> toolsMenuContext = QList<int>()
+                                  << core->uniqueIDManager()->uniqueIdentifier(QmlDesigner::Constants::C_QT_QUICK_TOOLS_MENU);
+    Core::Command *cmd = addToolAction(m_actionPreview,  am, toolsMenuContext,
+                   QLatin1String("QtQuick.Preview"), menuQtQuick, tr("Ctrl+Alt+R"));
+    connect(cmd->action(), SIGNAL(triggered()), SLOT(openPreview()));
+    m_previewRunner = new QmlJSPreviewRunner(this);
 
     QAction *followSymbolUnderCursorAction = new QAction(tr("Follow Symbol Under Cursor"), this);
     cmd = am->registerAction(followSymbolUnderCursorAction, Constants::FOLLOW_SYMBOL_UNDER_CURSOR, context);
@@ -158,6 +174,15 @@ void QmlJSEditorPlugin::extensionsInitialized()
 {
 }
 
+void QmlJSEditorPlugin::openPreview()
+{
+    Core::EditorManager *em = Core::EditorManager::instance();
+
+    if (em->currentEditor() && em->currentEditor()->id() == Constants::C_QMLJSEDITOR_ID)
+        m_previewRunner->run(em->currentEditor()->file()->fileName());
+
+}
+
 void QmlJSEditorPlugin::initializeEditor(QmlJSEditor::Internal::QmlJSTextEditor *editor)
 {
     QTC_ASSERT(m_instance, /**/);
@@ -179,4 +204,16 @@ void QmlJSEditorPlugin::followSymbolUnderCursor()
         editor->followSymbolUnderCursor();
 }
 
+Core::Command *QmlJSEditorPlugin::addToolAction(QAction *a, Core::ActionManager *am,
+                                          const QList<int> &context, const QString &name,
+                                          Core::ActionContainer *c1, const QString &keySequence)
+{
+    Core::Command *command = am->registerAction(a, name, context);
+    if (!keySequence.isEmpty())
+        command->setDefaultKeySequence(QKeySequence(keySequence));
+    c1->addAction(command);
+    return command;
+}
+
+
 Q_EXPORT_PLUGIN(QmlJSEditorPlugin)
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.h b/src/plugins/qmljseditor/qmljseditorplugin.h
index 1f8b9738fc1..b119e554d0a 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.h
+++ b/src/plugins/qmljseditor/qmljseditorplugin.h
@@ -32,10 +32,18 @@
 
 #include <extensionsystem/iplugin.h>
 
+QT_FORWARD_DECLARE_CLASS(QAction)
+
 namespace TextEditor {
 class TextEditorActionHandler;
 } // namespace TextEditor
 
+namespace Core {
+class Command;
+class ActionContainer;
+class ActionManager;
+}
+
 namespace QmlJSEditor {
 
 class ModelManagerInterface;
@@ -46,6 +54,7 @@ namespace Internal {
 class QmlJSEditorFactory;
 class CodeCompletion;
 class QmlJSTextEditor;
+class QmlJSPreviewRunner;
 
 class QmlJSEditorPlugin : public ExtensionSystem::IPlugin
 {
@@ -67,9 +76,18 @@ public:
 public Q_SLOTS:
     void followSymbolUnderCursor();
 
+private Q_SLOTS:
+    void openPreview();
+
 private:
+    Core::Command *addToolAction(QAction *a, Core::ActionManager *am, const QList<int> &context, const QString &name,
+                                 Core::ActionContainer *c1, const QString &keySequence);
+
     static QmlJSEditorPlugin *m_instance;
 
+    QAction *m_actionPreview;
+    QmlJSPreviewRunner *m_previewRunner;
+
     ModelManagerInterface *m_modelManager;
     QmlFileWizard *m_wizard;
     QmlJSEditorFactory *m_editor;
diff --git a/src/plugins/qmljseditor/qmljspreviewrunner.cpp b/src/plugins/qmljseditor/qmljspreviewrunner.cpp
new file mode 100644
index 00000000000..edae36100f9
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljspreviewrunner.cpp
@@ -0,0 +1,46 @@
+#include "qmljspreviewrunner.h"
+
+#include <projectexplorer/environment.h>
+#include <utils/synchronousprocess.h>
+
+#include <QtGui/QMessageBox>
+#include <QtGui/QApplication>
+
+#include <QDebug>
+
+namespace QmlJSEditor {
+namespace Internal {
+
+QmlJSPreviewRunner::QmlJSPreviewRunner(QObject *parent) :
+    QObject(parent)
+{
+    // prepend creator/bin dir to search path (only useful for special creator-qml package)
+    const QString searchPath = QCoreApplication::applicationDirPath()
+                               + Utils::SynchronousProcess::pathSeparator()
+                               + QString(qgetenv("PATH"));
+    m_qmlViewerDefaultPath = Utils::SynchronousProcess::locateBinary(searchPath, QLatin1String("qml"));
+
+    ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
+    m_applicationLauncher.setEnvironment(environment.toStringList());
+}
+
+
+void QmlJSPreviewRunner::run(const QString &filename)
+{
+    QString errorMessage;
+    if (!filename.isEmpty()) {
+        m_applicationLauncher.start(ProjectExplorer::ApplicationLauncher::Gui, m_qmlViewerDefaultPath,
+                                    QStringList() << filename);
+
+    } else {
+        errorMessage = "No file specified.";
+    }
+
+    if (!errorMessage.isEmpty())
+        QMessageBox::warning(0, tr("Failed to preview Qt Quick file"),
+                             tr("Could not preview Qt Quick (QML) file. Reason: \n%1").arg(errorMessage));
+}
+
+
+} // namespace Internal
+} // namespace QmlJSEditor
diff --git a/src/plugins/qmljseditor/qmljspreviewrunner.h b/src/plugins/qmljseditor/qmljspreviewrunner.h
new file mode 100644
index 00000000000..869327b10cc
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljspreviewrunner.h
@@ -0,0 +1,34 @@
+#ifndef QMLJSPREVIEWRUNNER_H
+#define QMLJSPREVIEWRUNNER_H
+
+#include <QObject>
+
+#include <projectexplorer/applicationlauncher.h>
+
+namespace QmlJSEditor {
+namespace Internal {
+
+class QmlJSPreviewRunner : public QObject
+{
+    Q_OBJECT
+public:
+    explicit QmlJSPreviewRunner(QObject *parent = 0);
+    void run(const QString &filename);
+
+signals:
+
+public slots:
+
+private:
+    QString m_qmlViewerDefaultPath;
+
+    ProjectExplorer::ApplicationLauncher m_applicationLauncher;
+
+};
+
+
+} // namespace Internal
+} // namespace QmlJSEditor
+
+
+#endif // QMLJSPREVIEWRUNNER_H
-- 
GitLab