12 changed files with 431 additions and 15 deletions
@ -0,0 +1,68 @@ |
|||||
|
/*
|
||||
|
This file is part of cpp-ethereum. |
||||
|
|
||||
|
cpp-ethereum 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 3 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
/** @file FileIo.cpp
|
||||
|
* @author Arkadiy Paronyan arkadiy@ethdev.com |
||||
|
* @date 2015 |
||||
|
* Ethereum IDE client. |
||||
|
*/ |
||||
|
|
||||
|
#include <stdexcept> |
||||
|
#include <QDir> |
||||
|
#include <QFile> |
||||
|
#include <QFileInfo> |
||||
|
#include <QTextStream> |
||||
|
#include "FileIo.h" |
||||
|
|
||||
|
using namespace dev::mix; |
||||
|
|
||||
|
void FileIo::makeDir(QString const& _path) |
||||
|
{ |
||||
|
QDir dirPath(_path); |
||||
|
if (!dirPath.exists()) |
||||
|
dirPath.mkpath(dirPath.path()); |
||||
|
} |
||||
|
|
||||
|
QString FileIo::readFile(QString const& _path) |
||||
|
{ |
||||
|
QFile file(_path); |
||||
|
if(file.open(QIODevice::ReadOnly | QIODevice::Text)) |
||||
|
{ |
||||
|
QTextStream stream(&file); |
||||
|
QString data = stream.readAll(); |
||||
|
return data; |
||||
|
} |
||||
|
else |
||||
|
throw std::runtime_error(tr("Error reading file %1").arg(_path).toStdString()); |
||||
|
} |
||||
|
|
||||
|
void FileIo::writeFile(QString const& _path, QString const& _data) |
||||
|
{ |
||||
|
QFile file(_path); |
||||
|
if(file.open(QIODevice::WriteOnly | QIODevice::Text)) |
||||
|
{ |
||||
|
QTextStream stream(&file); |
||||
|
stream << _data; |
||||
|
} |
||||
|
else |
||||
|
throw std::runtime_error(tr("Error writing file %1").arg(_path).toStdString()); |
||||
|
} |
||||
|
|
||||
|
void FileIo::copyFile(QString const& _sourcePath, QString const& _destPath) |
||||
|
{ |
||||
|
if (!QFile::copy(_sourcePath, _destPath)) |
||||
|
throw std::runtime_error(tr("Error copying file %1 to %2").arg(_sourcePath).arg(_destPath).toStdString()); |
||||
|
} |
@ -0,0 +1,49 @@ |
|||||
|
/*
|
||||
|
This file is part of cpp-ethereum. |
||||
|
|
||||
|
cpp-ethereum 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 3 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
/** @file FileIo.h
|
||||
|
* @author Arkadiy Paronyan arkadiy@ethdev.com |
||||
|
* @date 2015 |
||||
|
* Ethereum IDE client. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <QObject> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace mix |
||||
|
{ |
||||
|
|
||||
|
///File services for QML
|
||||
|
class FileIo : public QObject |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
|
||||
|
public: |
||||
|
/// Create a directory if it does not exist. Throws on failure.
|
||||
|
Q_INVOKABLE void makeDir(QString const& _path); |
||||
|
/// Read file contents to a string. Throws on failure.
|
||||
|
Q_INVOKABLE QString readFile(QString const& _path); |
||||
|
/// Write contents to a file. Throws on failure.
|
||||
|
Q_INVOKABLE void writeFile(QString const& _path, QString const& _data); |
||||
|
/// Copy a file from _sourcePath to _destPath. Throws on failure.
|
||||
|
Q_INVOKABLE void copyFile(QString const& _sourcePath, QString const& _destPath); |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
} |
@ -1,16 +1,19 @@ |
|||||
<RCC> |
<RCC> |
||||
<qresource prefix="/"> |
<qresource prefix="/"> |
||||
<file>qml/BasicContent.qml</file> |
|
||||
<file>qml/main.qml</file> |
<file>qml/main.qml</file> |
||||
<file>qml/MainContent.qml</file> |
<file>qml/AlertMessageDialog.qml</file> |
||||
<file>qml/TabStyle.qml</file> |
<file>qml/BasicContent.qml</file> |
||||
<file>qml/Debugger.qml</file> |
|
||||
<file>qml/js/Debugger.js</file> |
|
||||
<file>qml/BasicMessage.qml</file> |
<file>qml/BasicMessage.qml</file> |
||||
<file>qml/TransactionDialog.qml</file> |
<file>qml/Debugger.qml</file> |
||||
|
<file>qml/MainContent.qml</file> |
||||
<file>qml/ModalDialog.qml</file> |
<file>qml/ModalDialog.qml</file> |
||||
<file>qml/AlertMessageDialog.qml</file> |
<file>qml/ProjectList.qml</file> |
||||
<file>qml/StateDialog.qml</file> |
<file>qml/StateDialog.qml</file> |
||||
<file>qml/StateList.qml</file> |
<file>qml/StateList.qml</file> |
||||
|
<file>qml/TabStyle.qml</file> |
||||
|
<file>qml/TransactionDialog.qml</file> |
||||
|
<file>qml/js/Debugger.js</file> |
||||
|
<file>qml/NewProjectDialog.qml</file> |
||||
|
<file>qml/ProjectModel.qml</file> |
||||
</qresource> |
</qresource> |
||||
</RCC> |
</RCC> |
||||
|
@ -0,0 +1,92 @@ |
|||||
|
import QtQuick 2.2 |
||||
|
import QtQuick.Controls 1.2 |
||||
|
import QtQuick.Layouts 1.1 |
||||
|
import QtQuick.Window 2.0 |
||||
|
import QtQuick.Dialogs 1.2 |
||||
|
|
||||
|
Window { |
||||
|
|
||||
|
modality: Qt.WindowModal |
||||
|
|
||||
|
width: 640 |
||||
|
height: 280 |
||||
|
|
||||
|
visible: false |
||||
|
|
||||
|
property alias projectTitle : titleField.text |
||||
|
property alias projectPath : pathField.text |
||||
|
signal accepted |
||||
|
|
||||
|
function open() { |
||||
|
visible = true; |
||||
|
titleField.focus = true; |
||||
|
} |
||||
|
|
||||
|
function close() { |
||||
|
visible = false; |
||||
|
} |
||||
|
|
||||
|
GridLayout { |
||||
|
id: dialogContent |
||||
|
columns: 2 |
||||
|
anchors.fill: parent |
||||
|
anchors.margins: 10 |
||||
|
rowSpacing: 10 |
||||
|
columnSpacing: 10 |
||||
|
|
||||
|
Label { |
||||
|
text: qsTr("Title") |
||||
|
} |
||||
|
TextField { |
||||
|
id: titleField |
||||
|
focus: true |
||||
|
Layout.fillWidth: true |
||||
|
} |
||||
|
|
||||
|
Label { |
||||
|
text: qsTr("Path") |
||||
|
} |
||||
|
RowLayout { |
||||
|
TextField { |
||||
|
id: pathField |
||||
|
Layout.fillWidth: true |
||||
|
} |
||||
|
Button { |
||||
|
text: qsTr("Browse") |
||||
|
onClicked: createProjectFileDialog.open() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
RowLayout |
||||
|
{ |
||||
|
anchors.bottom: parent.bottom |
||||
|
anchors.right: parent.right; |
||||
|
|
||||
|
Button { |
||||
|
enabled: titleField.text != "" && pathField.text != "" |
||||
|
text: qsTr("Ok"); |
||||
|
onClicked: { |
||||
|
close(); |
||||
|
accepted(); |
||||
|
} |
||||
|
} |
||||
|
Button { |
||||
|
text: qsTr("Cancel"); |
||||
|
onClicked: close(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
FileDialog { |
||||
|
id: createProjectFileDialog |
||||
|
visible: false |
||||
|
title: qsTr("Please choose a path for the project") |
||||
|
selectFolder: true |
||||
|
onAccepted: { |
||||
|
var u = createProjectFileDialog.fileUrl.toString(); |
||||
|
if (u.indexOf("file://") == 0) |
||||
|
u = u.substring(7, u.length) |
||||
|
pathField.text = u; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
import QtQuick 2.0 |
||||
|
import QtQuick.Window 2.0 |
||||
|
import QtQuick.Layouts 1.0 |
||||
|
import QtQuick.Controls 1.0 |
||||
|
import org.ethereum.qml.ProjectModel 1.0 |
||||
|
|
||||
|
Item { |
||||
|
ListView { |
||||
|
model: ProjectModel.listModel |
||||
|
delegate: renderDelegate |
||||
|
} |
||||
|
|
||||
|
Component { |
||||
|
id: renderDelegate |
||||
|
Item { |
||||
|
id: wrapperItem |
||||
|
height: 20 |
||||
|
width: parent.width |
||||
|
RowLayout { |
||||
|
anchors.fill: parent |
||||
|
Text { |
||||
|
Layout.fillWidth: true |
||||
|
Layout.fillHeight: true |
||||
|
text: title |
||||
|
font.pointSize: 12 |
||||
|
verticalAlignment: Text.AlignBottom |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Action { |
||||
|
id: createProjectAction |
||||
|
text: qsTr("&New project") |
||||
|
shortcut: "Ctrl+N" |
||||
|
enabled: true; |
||||
|
onTriggered: ProjectModel.createProject(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,140 @@ |
|||||
|
pragma Singleton |
||||
|
|
||||
|
import QtQuick 2.0 |
||||
|
import QtQuick.Window 2.0 |
||||
|
import QtQuick.Layouts 1.0 |
||||
|
import QtQuick.Controls 1.0 |
||||
|
import QtQuick.Dialogs 1.1 |
||||
|
import Qt.labs.settings 1.0 |
||||
|
|
||||
|
Item { |
||||
|
id: projectModel |
||||
|
|
||||
|
signal projectClosed |
||||
|
signal projectLoaded |
||||
|
|
||||
|
property bool isEmpty: projectFile === "" |
||||
|
readonly property string projectFileName: ".mix" |
||||
|
|
||||
|
property bool haveUnsavedChanges: false |
||||
|
property string projectFile: "" |
||||
|
property var projectData: null |
||||
|
property var listModel: projectListModel |
||||
|
|
||||
|
function saveAll() { |
||||
|
saveProject(); |
||||
|
} |
||||
|
|
||||
|
function createProject() { |
||||
|
closeProject(); |
||||
|
newProjectDialog.open(); |
||||
|
} |
||||
|
|
||||
|
function closeProject() { |
||||
|
console.log("closing project"); |
||||
|
if (haveUnsavedChanges) |
||||
|
saveMessageDialog.open(); |
||||
|
else |
||||
|
doCloseProject(); |
||||
|
} |
||||
|
|
||||
|
function saveProject() { |
||||
|
if (!isEmpty) { |
||||
|
var json = JSON.stringify(projectData); |
||||
|
fileIo.writeFile(projectFile, json) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function loadProject(path) { |
||||
|
if (!isEmpty) |
||||
|
closeProject(); |
||||
|
console.log("loading project at " + path); |
||||
|
var json = fileIo.readFile(path); |
||||
|
projectData = JSON.parse(json); |
||||
|
projectFile = path; |
||||
|
if (!projectData.files) |
||||
|
projectData.files = []; |
||||
|
|
||||
|
for(var i = 0; i < projectData.files; i++) { |
||||
|
var p = projectData.files[i]; |
||||
|
projectListModel.append({ |
||||
|
path: p, |
||||
|
name: p.substring(p.lastIndexOf("/") + 1, p.length) |
||||
|
}); |
||||
|
} |
||||
|
onProjectLoaded(); |
||||
|
} |
||||
|
|
||||
|
function doCloseProject() { |
||||
|
projectListModel.clear(); |
||||
|
projectFile = ""; |
||||
|
projectData = null; |
||||
|
projectClosed(); |
||||
|
} |
||||
|
|
||||
|
function doCreateProject(title, path) { |
||||
|
if (!isEmpty) |
||||
|
closeProject(); |
||||
|
console.log("creating project " + title + " at " + path); |
||||
|
if (path[path.length - 1] !== "/") |
||||
|
path += "/"; |
||||
|
var dirPath = path + title; |
||||
|
fileIo.makeDir(dirPath); |
||||
|
var projectFile = dirPath + "/" + projectFileName; |
||||
|
fileIo.writeFile(projectFile, ""); |
||||
|
loadProject(projectFile); |
||||
|
} |
||||
|
|
||||
|
NewProjectDialog { |
||||
|
id: newProjectDialog |
||||
|
visible: false |
||||
|
onAccepted: { |
||||
|
var title = newProjectDialog.projectTitle; |
||||
|
var path = newProjectDialog.projectPath; |
||||
|
projectModel.doCreateProject(title, path); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
MessageDialog { |
||||
|
id: saveMessageDialog |
||||
|
title: qsTr("Project") |
||||
|
text: qsTr("Do you want to save changes?") |
||||
|
standardButtons: StandardButton.Ok | StandardButton.Cancel |
||||
|
icon: StandardIcon.Question |
||||
|
onAccepted: { |
||||
|
projectModel.saveAll(); |
||||
|
projectModel.doCloseProject(); |
||||
|
} |
||||
|
onRejected: { |
||||
|
projectModel.doCloseProject(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ListModel { |
||||
|
id: projectListModel |
||||
|
} |
||||
|
|
||||
|
Component { |
||||
|
id: renderDelegate |
||||
|
Item { |
||||
|
id: wrapperItem |
||||
|
height: 20 |
||||
|
width: parent.width |
||||
|
RowLayout { |
||||
|
anchors.fill: parent |
||||
|
Text { |
||||
|
Layout.fillWidth: true |
||||
|
Layout.fillHeight: true |
||||
|
text: title |
||||
|
font.pointSize: 12 |
||||
|
verticalAlignment: Text.AlignBottom |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Settings { |
||||
|
id: projectSettings |
||||
|
property string lastProjectPath; |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue