Browse Source

Merge pull request #1315 from yann300/trackFileStatus

Mix - Track files status.
cl-refactor
Arkadiy Paronyan 10 years ago
parent
commit
21009510a6
  1. 19
      mix/FileIo.cpp
  2. 12
      mix/FileIo.h
  3. 110
      mix/qml/CodeEditorView.qml
  4. 63
      mix/qml/FilesSection.qml
  5. 3
      mix/qml/MainContent.qml
  6. 14
      mix/qml/ProjectList.qml
  7. 52
      mix/qml/ProjectModel.qml
  8. 6
      mix/qml/StatusPane.qml
  9. 17
      mix/qml/TransactionLog.qml
  10. 14
      mix/qml/WebCodeEditor.qml
  11. 17
      mix/qml/WebPreview.qml
  12. 12
      mix/qml/html/codeeditor.js
  13. 57
      mix/qml/js/ProjectModel.js
  14. 35
      mix/qml/main.qml

19
mix/FileIo.cpp

@ -20,6 +20,7 @@
* Ethereum IDE client. * Ethereum IDE client.
*/ */
#include <QFileSystemWatcher>
#include <QDebug> #include <QDebug>
#include <QDesktopServices> #include <QDesktopServices>
#include <QMimeDatabase> #include <QMimeDatabase>
@ -40,6 +41,10 @@ using namespace dev;
using namespace dev::crypto; using namespace dev::crypto;
using namespace dev::mix; using namespace dev::mix;
FileIo::FileIo(): m_watcher(new QFileSystemWatcher(this))
{
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &FileIo::fileChanged);
}
void FileIo::openFileBrowser(QString const& _dir) void FileIo::openFileBrowser(QString const& _dir)
{ {
@ -87,7 +92,9 @@ QString FileIo::readFile(QString const& _url)
void FileIo::writeFile(QString const& _url, QString const& _data) void FileIo::writeFile(QString const& _url, QString const& _data)
{ {
QFile file(pathFromUrl(_url)); QString path = pathFromUrl(_url);
m_watcher->removePath(path);
QFile file(path);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) if (file.open(QIODevice::WriteOnly | QIODevice::Text))
{ {
QTextStream stream(&file); QTextStream stream(&file);
@ -95,6 +102,7 @@ void FileIo::writeFile(QString const& _url, QString const& _data)
} }
else else
error(tr("Error writing file %1").arg(_url)); error(tr("Error writing file %1").arg(_url));
m_watcher->addPath(path);
} }
void FileIo::copyFile(QString const& _sourceUrl, QString const& _destUrl) void FileIo::copyFile(QString const& _sourceUrl, QString const& _destUrl)
@ -191,3 +199,12 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
return ret; return ret;
} }
void FileIo::watchFileChanged(QString const& _path)
{
m_watcher->addPath(pathFromUrl(_path));
}
void FileIo::stopWatching(QString const& _path)
{
m_watcher->removePath(pathFromUrl(_path));
}

12
mix/FileIo.h

@ -25,6 +25,8 @@
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <QObject> #include <QObject>
class QFileSystemWatcher;
namespace dev namespace dev
{ {
namespace mix namespace mix
@ -39,8 +41,11 @@ class FileIo: public QObject
signals: signals:
/// Signalled in case of IO error /// Signalled in case of IO error
void error(QString const& _errorText); void error(QString const& _errorText);
/// Signnalled when a file is changed.
void fileChanged(QString const& _filePath);
public: public:
FileIo();
/// Create a directory if it does not exist. Signals on failure. /// Create a directory if it does not exist. Signals on failure.
Q_INVOKABLE void makeDir(QString const& _url); Q_INVOKABLE void makeDir(QString const& _url);
/// Read file contents to a string. Signals on failure. /// Read file contents to a string. Signals on failure.
@ -55,12 +60,17 @@ public:
Q_INVOKABLE bool fileExists(QString const& _url); Q_INVOKABLE bool fileExists(QString const& _url);
/// Compress a folder, @returns sha3 of the compressed file. /// Compress a folder, @returns sha3 of the compressed file.
Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder); Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder);
/// Open a file browser /// Open a file browser.
Q_INVOKABLE void openFileBrowser(QString const& _dir); Q_INVOKABLE void openFileBrowser(QString const& _dir);
/// Listen for files change in @arg _path.
Q_INVOKABLE void watchFileChanged(QString const& _path);
/// Stop Listenning for files change in @arg _path.
Q_INVOKABLE void stopWatching(QString const& _path);
private: private:
QString getHomePath() const; QString getHomePath() const;
QString pathFromUrl(QString const& _url); QString pathFromUrl(QString const& _url);
QFileSystemWatcher* m_watcher;
}; };
} }

110
mix/qml/CodeEditorView.qml

@ -2,12 +2,14 @@ import QtQuick 2.0
import QtQuick.Window 2.0 import QtQuick.Window 2.0
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.0
import QtQuick.Controls 1.0 import QtQuick.Controls 1.0
import QtQuick.Dialogs 1.1
Item { Item {
id: codeEditorView id: codeEditorView
property string currentDocumentId: "" property string currentDocumentId: ""
signal documentEdit(string documentId) signal documentEdit(string documentId)
signal breakpointsChanged(string documentId) signal breakpointsChanged(string documentId)
signal isCleanChanged(var isClean, string documentId)
function getDocumentText(documentId) { function getDocumentText(documentId) {
for (var i = 0; i < editorListModel.count; i++) { for (var i = 0; i < editorListModel.count; i++) {
@ -51,12 +53,17 @@ Item {
breakpointsChanged(document.documentId); breakpointsChanged(document.documentId);
}); });
editor.setText(data, document.syntaxMode); editor.setText(data, document.syntaxMode);
editor.onIsCleanChanged.connect(function() {
isCleanChanged(editor.isClean, document.documentId);
});
} }
function getEditor(documentId) { function getEditor(documentId) {
for (var i = 0; i < editorListModel.count; i++) for (var i = 0; i < editorListModel.count; i++)
{
if (editorListModel.get(i).documentId === documentId) if (editorListModel.get(i).documentId === documentId)
return editors.itemAt(i).item; return editors.itemAt(i).item;
}
return null; return null;
} }
@ -91,6 +98,12 @@ Item {
editor.toggleBreakpoint(); editor.toggleBreakpoint();
} }
function resetEditStatus(docId) {
var editor = getEditor(docId);
if (editor)
editor.changeGeneration();
}
Component.onCompleted: projectModel.codeEditor = codeEditorView; Component.onCompleted: projectModel.codeEditor = codeEditorView;
Connections { Connections {
@ -98,17 +111,65 @@ Item {
onDocumentOpened: { onDocumentOpened: {
openDocument(document); openDocument(document);
} }
onProjectSaving: { onProjectSaving: {
for (var i = 0; i < editorListModel.count; i++) for (var i = 0; i < editorListModel.count; i++)
fileIo.writeFile(editorListModel.get(i).path, editors.itemAt(i).item.getText()); {
var doc = editorListModel.get(i);
fileIo.writeFile(doc.path, editors.itemAt(i).item.getText());
}
}
onProjectSaved: {
if (projectModel.appIsClosing)
return;
for (var i = 0; i < editorListModel.count; i++)
{
var doc = editorListModel.get(i);
resetEditStatus(doc.documentId);
}
} }
onProjectClosed: { onProjectClosed: {
for (var i = 0; i < editorListModel.count; i++) { for (var i = 0; i < editorListModel.count; i++)
editors.itemAt(i).visible = false; editors.itemAt(i).visible = false;
}
editorListModel.clear(); editorListModel.clear();
currentDocumentId = ""; currentDocumentId = "";
} }
onDocumentSaved: {
resetEditStatus(documentId);
}
onContractSaved: {
resetEditStatus(documentId);
}
onDocumentSaving: {
for (var i = 0; i < editorListModel.count; i++)
{
var doc = editorListModel.get(i);
if (doc.path === document.path)
{
fileIo.writeFile(document.path, editors.itemAt(i).item.getText());
break;
}
}
}
}
MessageDialog
{
id: messageDialog
title: qsTr("File Changed")
text: qsTr("This file has been changed outside of the editor. Do you want to reload it?")
standardButtons: StandardButton.Yes | StandardButton.No
property variant item
property variant doc
onYes: {
doLoadDocument(item, doc);
resetEditStatus(doc.documentId);
}
} }
Repeater { Repeater {
@ -121,10 +182,20 @@ Item {
anchors.fill: parent anchors.fill: parent
source: "CodeEditor.qml" source: "CodeEditor.qml"
visible: (index >= 0 && index < editorListModel.count && currentDocumentId === editorListModel.get(index).documentId) visible: (index >= 0 && index < editorListModel.count && currentDocumentId === editorListModel.get(index).documentId)
property bool changed: false
onVisibleChanged: { onVisibleChanged: {
loadIfNotLoaded() loadIfNotLoaded()
if (visible && item) if (visible && item)
{
loader.item.setFocus(); loader.item.setFocus();
if (changed)
{
changed = false;
messageDialog.item = loader.item;
messageDialog.doc = editorListModel.get(index);
messageDialog.open();
}
}
} }
Component.onCompleted: { Component.onCompleted: {
loadIfNotLoaded() loadIfNotLoaded()
@ -133,8 +204,39 @@ Item {
doLoadDocument(loader.item, editorListModel.get(index)) doLoadDocument(loader.item, editorListModel.get(index))
} }
Connections
{
target: projectModel
onDocumentChanged: {
if (!item)
return;
var current = editorListModel.get(index);
if (documentId === current.documentId)
{
if (currentDocumentId === current.documentId)
{
messageDialog.item = loader.item;
messageDialog.doc = editorListModel.get(index);
messageDialog.open();
}
else
changed = true
}
}
onDocumentUpdated: {
var document = projectModel.getDocument(documentId);
for (var i = 0; i < editorListModel.count; i++)
if (editorListModel.get(i).documentId === documentId)
{
editorListModel.set(i, document);
break;
}
}
}
function loadIfNotLoaded () { function loadIfNotLoaded () {
if(visible && !active) { if (visible && !active) {
active = true; active = true;
} }
} }

63
mix/qml/FilesSection.qml

@ -141,34 +141,53 @@ Rectangle
color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : "transparent" color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : "transparent"
property bool isSelected property bool isSelected
property bool renameMode property bool renameMode
Text {
id: nameText Row {
height: parent.height spacing: 3
visible: !renameMode
color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color
text: name;
font.family: fileNameFont.name
font.pointSize: ProjectFilesStyle.documentsList.fontSize
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter anchors.fill: parent
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2 anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2
width: parent.width Text {
Connections id: nameText
{ height: parent.height
target: selManager visible: !renameMode
onSelected: { color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color
if (groupName != sectionName) text: name;
rootItem.isSelected = false; font.family: fileNameFont.name
else if (doc === documentId) font.pointSize: ProjectFilesStyle.documentsList.fontSize
rootItem.isSelected = true; verticalAlignment: Text.AlignVCenter
else
rootItem.isSelected = false; Connections
{
target: selManager
onSelected: {
if (groupName != sectionName)
rootItem.isSelected = false;
else if (doc === documentId)
rootItem.isSelected = true;
else
rootItem.isSelected = false;
if (rootItem.isSelected && section.state === "hidden") if (rootItem.isSelected && section.state === "hidden")
section.state = ""; section.state = "";
}
onIsCleanChanged: {
if (groupName === sectionName && doc === documentId)
editStatusLabel.visible = !isClean;
}
} }
} }
DefaultLabel {
id: editStatusLabel
visible: false
color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color
verticalAlignment: Text.AlignVCenter
text: "*"
width: 10
height: parent.height
}
} }
TextInput { TextInput {

3
mix/qml/MainContent.qml

@ -173,6 +173,9 @@ Rectangle {
width: 350 width: 350
Layout.minimumWidth: 250 Layout.minimumWidth: 250
Layout.fillHeight: true Layout.fillHeight: true
Connections {
target: projectModel.codeEditor
}
} }
Rectangle { Rectangle {

14
mix/qml/ProjectList.qml

@ -67,8 +67,6 @@ Item {
color: ProjectFilesStyle.documentsList.background color: ProjectFilesStyle.documentsList.background
} }
Rectangle Rectangle
{ {
Layout.fillWidth: true Layout.fillWidth: true
@ -83,6 +81,7 @@ Item {
Repeater { Repeater {
model: [qsTr("Contracts"), qsTr("Javascript"), qsTr("Web Pages"), qsTr("Styles"), qsTr("Images"), qsTr("Misc")]; model: [qsTr("Contracts"), qsTr("Javascript"), qsTr("Web Pages"), qsTr("Styles"), qsTr("Images"), qsTr("Misc")];
signal selected(string doc, string groupName) signal selected(string doc, string groupName)
signal isCleanChanged(string doc, string groupName, var isClean)
property int incr: -1; property int incr: -1;
id: sectionRepeater id: sectionRepeater
FilesSection FilesSection
@ -145,6 +144,17 @@ Item {
} }
} }
onIsCleanChanged: {
for (var si = 0; si < sectionModel.count; si++) {
var document = sectionModel.get(si);
if (documentId === document.documentId && document.groupName === modelData)
{
selManager.isCleanChanged(documentId, modelData, isClean);
break;
}
}
}
onDocumentOpened: { onDocumentOpened: {
if (document.groupName === modelData) if (document.groupName === modelData)
sectionRepeater.selected(document.documentId, modelData); sectionRepeater.selected(document.documentId, modelData);

52
mix/qml/ProjectModel.qml

@ -7,12 +7,13 @@ import Qt.labs.settings 1.0
import "js/ProjectModel.js" as ProjectModelCode import "js/ProjectModel.js" as ProjectModelCode
Item { Item {
id: projectModel id: projectModel
signal projectClosed signal projectClosed
signal projectLoading(var projectData) signal projectLoading(var projectData)
signal projectLoaded() signal projectLoaded()
signal documentSaving(var document)
signal documentChanged(var documentId)
signal documentOpened(var document) signal documentOpened(var document)
signal documentRemoved(var documentId) signal documentRemoved(var documentId)
signal documentUpdated(var documentId) //renamed signal documentUpdated(var documentId) //renamed
@ -21,15 +22,17 @@ Item {
signal projectSaved() signal projectSaved()
signal newProject(var projectData) signal newProject(var projectData)
signal documentSaved(var documentId) signal documentSaved(var documentId)
signal contractSaved(var documentId)
signal deploymentStarted() signal deploymentStarted()
signal deploymentStepChanged(string message) signal deploymentStepChanged(string message)
signal deploymentComplete() signal deploymentComplete()
signal deploymentError(string error) signal deploymentError(string error)
signal isCleanChanged(var isClean, string documentId)
property bool isEmpty: (projectPath === "") property bool isEmpty: (projectPath === "")
readonly property string projectFileName: ".mix" readonly property string projectFileName: ".mix"
property bool haveUnsavedChanges: false property bool appIsClosing: false
property string projectPath: "" property string projectPath: ""
property string projectTitle: "" property string projectTitle: ""
property string currentDocumentId: "" property string currentDocumentId: ""
@ -38,11 +41,13 @@ Item {
property var listModel: projectListModel property var listModel: projectListModel
property var stateListModel: projectStateListModel.model property var stateListModel: projectStateListModel.model
property CodeEditorView codeEditor: null property CodeEditorView codeEditor: null
property var unsavedFiles: []
//interface //interface
function saveAll() { ProjectModelCode.saveAll(); } function saveAll() { ProjectModelCode.saveAll(); }
function saveCurrentDocument() { ProjectModelCode.saveCurrentDocument(); }
function createProject() { ProjectModelCode.createProject(); } function createProject() { ProjectModelCode.createProject(); }
function closeProject() { ProjectModelCode.closeProject(); } function closeProject(callBack) { ProjectModelCode.closeProject(callBack); }
function saveProject() { ProjectModelCode.saveProject(); } function saveProject() { ProjectModelCode.saveProject(); }
function loadProject(path) { ProjectModelCode.loadProject(path); } function loadProject(path) { ProjectModelCode.loadProject(path); }
function newHtmlFile() { ProjectModelCode.newHtmlFile(); } function newHtmlFile() { ProjectModelCode.newHtmlFile(); }
@ -69,6 +74,20 @@ Item {
} }
} }
Connections {
target: codeEditor
onIsCleanChanged: {
for (var i in unsavedFiles)
{
if (unsavedFiles[i] === documentId && isClean)
unsavedFiles.splice(i, 1);
}
if (!isClean)
unsavedFiles.push(documentId);
isCleanChanged(isClean, documentId);
}
}
NewProjectDialog { NewProjectDialog {
id: newProjectDialog id: newProjectDialog
visible: false visible: false
@ -79,18 +98,36 @@ Item {
} }
} }
Connections
{
target: fileIo
property bool saving: false
onFileChanged:
{
fileIo.watchFileChanged(_filePath);
var documentId = ProjectModelCode.getDocumentByPath(_filePath);
documentChanged(documentId);
}
}
MessageDialog { MessageDialog {
id: saveMessageDialog id: saveMessageDialog
title: qsTr("Project") title: qsTr("Project")
text: qsTr("Do you want to save changes?") text: qsTr("Some files require to be saved. Do you want to save changes?");
standardButtons: StandardButton.Ok | StandardButton.Cancel standardButtons: StandardButton.Yes | StandardButton.No | StandardButton.Cancel
icon: StandardIcon.Question icon: StandardIcon.Question
onAccepted: { property var callBack;
onYes: {
projectModel.saveAll(); projectModel.saveAll();
ProjectModelCode.doCloseProject(); ProjectModelCode.doCloseProject();
if (callBack)
callBack();
} }
onRejected: { onRejected: {}
onNo: {
ProjectModelCode.doCloseProject(); ProjectModelCode.doCloseProject();
if (callBack)
callBack();
} }
} }
@ -135,6 +172,7 @@ Item {
target: projectModel target: projectModel
onProjectClosed: { onProjectClosed: {
projectSettings.lastProjectPath = ""; projectSettings.lastProjectPath = "";
projectPath = "";
} }
} }

6
mix/qml/StatusPane.qml

@ -77,11 +77,15 @@ Rectangle {
function format(_message) function format(_message)
{ {
var formatted = _message.match(/(?:<dev::eth::)(.+)(?:>)/); var formatted = _message.match(/(?:<dev::eth::)(.+)(?:>)/);
if (formatted === null)
formatted = _message.match(/(?:<dev::)(.+)(?:>)/);
if (formatted.length > 1) if (formatted.length > 1)
formatted = formatted[1] + ": "; formatted = formatted[1];
else else
return _message; return _message;
var exceptionInfos = _message.match(/(?:tag_)(.+)/g); var exceptionInfos = _message.match(/(?:tag_)(.+)/g);
if (exceptionInfos !== null && exceptionInfos.length > 0)
formatted += ": "
for (var k in exceptionInfos) for (var k in exceptionInfos)
formatted += " " + exceptionInfos[k].replace("*]", "").replace("tag_", "").replace("=", ""); formatted += " " + exceptionInfos[k].replace("*]", "").replace("tag_", "").replace("=", "");
return formatted; return formatted;

17
mix/qml/TransactionLog.qml

@ -30,12 +30,23 @@ Item {
anchors.fill: parent anchors.fill: parent
RowLayout { RowLayout {
Connections
{
id: compilationStatus
target: codeModel
property bool compilationComplete: false
onCompilationComplete: compilationComplete = true
onCompilationError: compilationComplete = false
}
Connections Connections
{ {
target: projectModel target: projectModel
onProjectSaved: onProjectSaved:
{ {
if (codeModel.hasContract && !clientModel.running) if (projectModel.appIsClosing)
return;
if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running)
projectModel.stateListModel.debugDefaultState(); projectModel.stateListModel.debugDefaultState();
} }
onProjectClosed: onProjectClosed:
@ -44,6 +55,10 @@ Item {
transactionModel.clear(); transactionModel.clear();
callModel.clear(); callModel.clear();
} }
onContractSaved: {
if (compilationStatus.compilationComplete && codeModel.hasContract && !clientModel.running)
projectModel.stateListModel.debugDefaultState();
}
} }
ComboBox { ComboBox {

14
mix/qml/WebCodeEditor.qml

@ -6,8 +6,9 @@ import QtWebEngine 1.0
import QtWebEngine.experimental 1.0 import QtWebEngine.experimental 1.0
Item { Item {
signal editorTextChanged; signal editorTextChanged
signal breakpointsChanged; signal breakpointsChanged
property bool isClean: true
property string currentText: "" property string currentText: ""
property string currentMode: "" property string currentMode: ""
property bool initialized: false property bool initialized: false
@ -50,6 +51,10 @@ Item {
editorBrowser.runJavaScript("toggleBreakpoint()"); editorBrowser.runJavaScript("toggleBreakpoint()");
} }
function changeGeneration() {
editorBrowser.runJavaScript("changeGeneration()", function(result) {});
}
Connections { Connections {
target: appContext target: appContext
onClipboardChanged: syncClipboard() onClipboardChanged: syncClipboard()
@ -75,6 +80,7 @@ Item {
runJavaScript("getTextChanged()", function(result) { }); runJavaScript("getTextChanged()", function(result) { });
pollTimer.running = true; pollTimer.running = true;
syncClipboard(); syncClipboard();
parent.changeGeneration();
} }
} }
@ -103,7 +109,9 @@ Item {
}); });
} }
}); });
editorBrowser.runJavaScript("isClean()", function(result) {
isClean = result;
});
} }
} }
} }

17
mix/qml/WebPreview.qml

@ -87,8 +87,7 @@ Item {
Connections { Connections {
target: projectModel target: projectModel
//onProjectSaved : reloadOnSave();
//onDocumentSaved: reloadOnSave();
onDocumentAdded: { onDocumentAdded: {
var document = projectModel.getDocument(documentId) var document = projectModel.getDocument(documentId)
if (document.isHtml) if (document.isHtml)
@ -99,7 +98,13 @@ Item {
} }
onDocumentUpdated: { onDocumentUpdated: {
updateDocument(documentId, function(i) { pageListModel.set(i, projectModel.getDocument(documentId)) } ) var document = projectModel.getDocument(documentId);
for (var i = 0; i < pageListModel.count; i++)
if (pageListModel.get(i).documentId === documentId)
{
pageListModel.set(i, document);
break;
}
} }
onProjectLoading: { onProjectLoading: {
@ -116,6 +121,12 @@ Item {
} }
} }
onDocumentSaved:
{
if (!projectModel.getDocument(documentId).isContract)
reloadOnSave();
}
onProjectClosed: { onProjectClosed: {
pageListModel.clear(); pageListModel.clear();
} }

12
mix/qml/html/codeeditor.js

@ -18,7 +18,6 @@ editor.breakpointsChangeRegistered = false;
editor.on("change", function(eMirror, object) { editor.on("change", function(eMirror, object) {
editor.changeRegistered = true; editor.changeRegistered = true;
}); });
var mac = /Mac/.test(navigator.platform); var mac = /Mac/.test(navigator.platform);
@ -110,3 +109,14 @@ highlightExecution = function(start, end) {
executionMark.clear(); executionMark.clear();
executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" }); executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" });
} }
var changeId;
changeGeneration = function()
{
changeId = editor.changeGeneration(true);
}
isClean = function()
{
return editor.isClean(changeId);
}

57
mix/qml/js/ProjectModel.js

@ -25,6 +25,16 @@ Qt.include("TransactionHelper.js")
var htmlTemplate = "<html>\n<head>\n<script>\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>"; var htmlTemplate = "<html>\n<head>\n<script>\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>";
var contractTemplate = "contract Contract {\n}\n"; var contractTemplate = "contract Contract {\n}\n";
function saveCurrentDocument()
{
var doc = projectListModel.get(getDocumentIndex(currentDocumentId));
documentSaving(doc);
if (doc.isContract)
contractSaved(currentDocumentId);
else
documentSaved(currentDocumentId);
}
function saveAll() { function saveAll() {
saveProject(); saveProject();
} }
@ -33,16 +43,35 @@ function createProject() {
newProjectDialog.open(); newProjectDialog.open();
} }
function closeProject() { function closeProject(callBack) {
if (!isEmpty) { if (!isEmpty) {
if (haveUnsavedChanges) if (unsavedFiles.length > 0)
{
saveMessageDialog.callBack = callBack;
saveMessageDialog.open(); saveMessageDialog.open();
}
else else
{
doCloseProject(); doCloseProject();
if (callBack)
callBack();
}
} }
} }
function saveProject() { function saveProject() {
if (!isEmpty) {
var projectData = saveProjectFile();
if (projectData !== null)
{
projectSaving(projectData);
projectSaved();
}
}
}
function saveProjectFile()
{
if (!isEmpty) { if (!isEmpty) {
var projectData = { var projectData = {
files: [], files: [],
@ -55,13 +84,14 @@ function saveProject() {
deploymentDir: projectModel.deploymentDir deploymentDir: projectModel.deploymentDir
}; };
for (var i = 0; i < projectListModel.count; i++) for (var i = 0; i < projectListModel.count; i++)
projectData.files.push(projectListModel.get(i).fileName) projectData.files.push(projectListModel.get(i).fileName);
projectSaving(projectData);
var json = JSON.stringify(projectData, null, "\t"); var json = JSON.stringify(projectData, null, "\t");
var projectFile = projectPath + projectFileName; var projectFile = projectPath + projectFileName;
fileIo.writeFile(projectFile, json); fileIo.writeFile(projectFile, json);
projectSaved(); return projectData;
} }
return null;
} }
function loadProject(path) { function loadProject(path) {
@ -131,6 +161,8 @@ function addFile(fileName) {
}; };
projectListModel.append(docData); projectListModel.append(docData);
saveProjectFile();
fileIo.watchFileChanged(p);
return docData.documentId; return docData.documentId;
} }
@ -143,6 +175,17 @@ function getDocumentIndex(documentId)
return -1; return -1;
} }
function getDocumentByPath(_path)
{
for (var i = 0; i < projectListModel.count; i++)
{
var doc = projectListModel.get(i);
if (doc.path.indexOf(_path) !== -1)
return doc.documentId;
}
return null;
}
function openDocument(documentId) { function openDocument(documentId) {
if (documentId !== currentDocumentId) { if (documentId !== currentDocumentId) {
documentOpened(projectListModel.get(getDocumentIndex(documentId))); documentOpened(projectListModel.get(getDocumentIndex(documentId)));
@ -226,12 +269,16 @@ function renameDocument(documentId, newName) {
var i = getDocumentIndex(documentId); var i = getDocumentIndex(documentId);
var document = projectListModel.get(i); var document = projectListModel.get(i);
if (!document.isContract) { if (!document.isContract) {
fileIo.stopWatching(document.path);
var sourcePath = document.path; var sourcePath = document.path;
var destPath = projectPath + newName; var destPath = projectPath + newName;
fileIo.moveFile(sourcePath, destPath); fileIo.moveFile(sourcePath, destPath);
document.path = destPath; document.path = destPath;
document.name = newName; document.name = newName;
document.fileName = newName;
projectListModel.set(i, document); projectListModel.set(i, document);
fileIo.watchFileChanged(destPath);
saveProjectFile();
documentUpdated(documentId); documentUpdated(documentId);
} }
} }

35
mix/qml/main.qml

@ -17,6 +17,25 @@ ApplicationWindow {
minimumHeight: 300 minimumHeight: 300
title: qsTr("Mix") title: qsTr("Mix")
Connections
{
target: mainApplication
onClosing:
{
mainApplication.close();
close.accepted = false;
}
}
function close()
{
projectModel.appIsClosing = true;
if (projectModel.projectPath !== "")
projectModel.closeProject(function() { Qt.quit(); })
else
Qt.quit();
}
menuBar: MenuBar { menuBar: MenuBar {
Menu { Menu {
title: qsTr("File") title: qsTr("File")
@ -24,6 +43,7 @@ ApplicationWindow {
MenuItem { action: openProjectAction } MenuItem { action: openProjectAction }
MenuSeparator {} MenuSeparator {}
MenuItem { action: saveAllFilesAction } MenuItem { action: saveAllFilesAction }
MenuItem { action: saveCurrentDocument }
MenuSeparator {} MenuSeparator {}
MenuItem { action: addExistingFileAction } MenuItem { action: addExistingFileAction }
MenuItem { action: addNewJsFileAction } MenuItem { action: addNewJsFileAction }
@ -92,7 +112,10 @@ ApplicationWindow {
id: exitAppAction id: exitAppAction
text: qsTr("Exit") text: qsTr("Exit")
shortcut: "Ctrl+Q" shortcut: "Ctrl+Q"
onTriggered: Qt.quit(); onTriggered:
{
mainApplication.close();
}
} }
Action { Action {
@ -279,11 +302,19 @@ ApplicationWindow {
Action { Action {
id: saveAllFilesAction id: saveAllFilesAction
text: qsTr("Save All") text: qsTr("Save All")
shortcut: "Ctrl+S" shortcut: "Ctrl+Shift+A"
enabled: !projectModel.isEmpty enabled: !projectModel.isEmpty
onTriggered: projectModel.saveAll(); onTriggered: projectModel.saveAll();
} }
Action {
id: saveCurrentDocument
text: qsTr("Save Current Document")
shortcut: "Ctrl+S"
enabled: !projectModel.isEmpty
onTriggered: projectModel.saveCurrentDocument();
}
Action { Action {
id: closeProjectAction id: closeProjectAction
text: qsTr("Close Project") text: qsTr("Close Project")

Loading…
Cancel
Save