From cc3601c6aebd23a2cb8b4acdc8efc6f8b4a2a51e Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 5 Feb 2015 19:06:26 +0100 Subject: [PATCH] - Project Tree redesign first shot. https://www.pivotaltracker.com/story/show/87372988 --- mix/qml/FilesSection.qml | 200 +++++++++++++++++++++++++++++++ mix/qml/MainContent.qml | 4 +- mix/qml/ProjectList.qml | 238 +++++++++++++++++++++---------------- mix/qml/Style.qml | 26 ++++ mix/qml/js/ProjectModel.js | 6 +- mix/qml/qmldir | 1 + mix/res.qrc | 3 + 7 files changed, 373 insertions(+), 105 deletions(-) create mode 100644 mix/qml/FilesSection.qml create mode 100644 mix/qml/Style.qml create mode 100644 mix/qml/qmldir diff --git a/mix/qml/FilesSection.qml b/mix/qml/FilesSection.qml new file mode 100644 index 000000000..01c9ede13 --- /dev/null +++ b/mix/qml/FilesSection.qml @@ -0,0 +1,200 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.3 +import "." + + +ColumnLayout { + id: wrapperItem + signal documentSelected(string doc, string groupName) + property alias model: filesList.model + property string sectionName; + property variant selManager; + property variant projectModel; + Layout.fillWidth: true + Layout.minimumHeight: hiddenHeightTopLevel() + height: hiddenHeightTopLevel() + Layout.maximumHeight: hiddenHeightTopLevel() + spacing: 0 + + function hiddenHeightTopLevel() + { + return section.state === "hidden" ? Style.documentsList.height : Style.documentsList.height * (model.count + 1); + } + + function hiddenHeightRepeater() + { + return section.state === "hidden" ? 0 : Style.documentsList.height * wrapperItem.model.count; + } + + function hiddenHeightElement() + { + return section.state === "hidden" ? 0 : Style.documentsList.height; + } + + RowLayout + { + anchors.top: parent.top + id: rowCol + width: parent.width + height: Style.documentsList.height + Text + { + id: section + text: sectionName + anchors.left: parent.left + anchors.leftMargin: Style.general.leftMargin + states: [ + State { + name: "hidden" + PropertyChanges { target: filesList; visible: false; } + PropertyChanges { target: rowCol; Layout.minimumHeight: Style.documentsList.height; Layout.maximumHeight: Style.documentsList.height; height: Style.documentsList.height; } + } + ] + } + + MouseArea { + id: titleMouseArea + anchors.fill: parent + hoverEnabled: true + z: 2 + onClicked: { + if (section.state === "hidden") + section.state = ""; + else + section.state = "hidden"; + } + } + } + + ColumnLayout { + height: wrapperItem.hiddenHeightRepeater() + Layout.minimumHeight: wrapperItem.hiddenHeightRepeater() + Layout.preferredHeight: wrapperItem.hiddenHeightRepeater() + Layout.maximumHeight: wrapperItem.hiddenHeightRepeater() + width: parent.width + visible: section.state !== "hidden" + Repeater + { + id: filesList + visible: section.state !== "hidden" + Rectangle + { + visible: section.state !== "hidden" + id: rootItem + Layout.fillWidth: true + Layout.minimumHeight: wrapperItem.hiddenHeightElement() + Layout.preferredHeight: wrapperItem.hiddenHeightElement() + Layout.maximumHeight: wrapperItem.hiddenHeightElement() + height: wrapperItem.hiddenHeightElement() + color: isSelected ? Style.documentsList.highlightColor : Style.documentsList.background + property bool isSelected + property bool renameMode + Text { + id: nameText + height: parent.height + visible: !renameMode + color: rootItem.isSelected ? Style.documentsList.selectedColor : Style.documentsList.color + text: name; + font.pointSize: Style.documentsList.fontSize + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Style.general.leftMargin + width: parent.width + Connections + { + target: selManager + onSelected: { + if (groupName != sectionName) + rootItem.isSelected = false; + else if (doc === documentId) + rootItem.isSelected = true; + else + rootItem.isSelected = false; + } + } + } + + TextInput { + id: textInput + text: nameText.text + visible: renameMode + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Style.general.leftMargin + MouseArea { + id: textMouseArea + anchors.fill: parent + hoverEnabled: true + z: 2 + onClicked: { + textInput.forceActiveFocus(); + } + } + + onVisibleChanged: { + if (visible) { + selectAll(); + forceActiveFocus(); + } + } + + onAccepted: close(true); + onCursorVisibleChanged: { + if (!cursorVisible) + close(false); + } + onFocusChanged: { + if (!focus) + close(false); + } + function close(accept) { + rootItem.renameMode = false; + if (accept) + { + projectModel.renameDocument(documentId, textInput.text); + nameText.text = textInput.text; + } + } + } + + MouseArea { + id: mouseArea + z: 1 + hoverEnabled: false + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked:{ + if (mouse.button === Qt.RightButton && !isContract) + contextMenu.popup(); + else if (mouse.button === Qt.LeftButton) + { + rootItem.isSelected = true; + projectModel.openDocument(documentId); + documentSelected(documentId, groupName); + } + } + } + + Menu { + id: contextMenu + MenuItem { + text: qsTr("Rename") + onTriggered: { + rootItem.renameMode = true; + } + } + MenuItem { + text: qsTr("Delete") + onTriggered: { + projectModel.removeDocument(documentId); + } + } + } + } + } + } +} + diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 247de143f..23cdec975 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -145,8 +145,8 @@ Rectangle { ProjectList { id: projectList - width: 200 - Layout.minimumWidth: 180 + width: 350 + Layout.minimumWidth: 250 Layout.fillHeight: true } Rectangle { diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index 30f945706..9f32adbe9 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -2,138 +2,174 @@ import QtQuick 2.0 import QtQuick.Window 2.0 import QtQuick.Layouts 1.0 import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.3 +import Qt.labs.settings 1.0 +import "." Item { property bool renameMode: false; ColumnLayout { anchors.fill: parent - Text { + id: filesCol + spacing: 0 + Rectangle + { + color: Style.title.background + height: Style.title.height Layout.fillWidth: true - color: "blue" - text: projectModel.projectTitle - horizontalAlignment: Text.AlignHCenter - visible: !projectModel.isEmpty; + Text + { + color: Style.title.color + text: projectModel.projectTitle + anchors.verticalCenter: parent.verticalCenter + visible: !projectModel.isEmpty; + anchors.left: parent.left + anchors.leftMargin: Style.general.leftMargin + } } - ListView { - id: projectList + + Rectangle + { Layout.fillWidth: true - Layout.fillHeight: true + height: 10 + color: Style.documentsList.background + } - model: projectModel.listModel + Item { + id: selManager + signal selected(string doc, string groupName) + } - delegate: renderDelegate - highlight: Rectangle { - color: "lightsteelblue"; - } - highlightFollowsCurrentItem: true - focus: true - clip: true + Rectangle + { + Layout.fillWidth: true + Layout.fillHeight: true + color: Style.documentsList.background - onCurrentIndexChanged: { - if (currentIndex >= 0 && currentIndex < projectModel.listModel.count) - projectModel.openDocument(projectModel.listModel.get(currentIndex).documentId); - } - } - Menu { - id: contextMenu - MenuItem { - text: qsTr("Rename") - onTriggered: { - renameMode = true; - } - } - MenuItem { - text: qsTr("Delete") - onTriggered: { - projectModel.removeDocument(projectList.model.get(projectList.currentIndex).documentId); + ColumnLayout + { + anchors.top: parent.top + width: parent.width + FilesSection + { + sectionName: "Contracts" + projectModel: projectModelConnection + model: ctrModel + selManager: selManager + onDocumentSelected: { + selManager.selected(doc, groupName); + } } - } - } - } - Component { - id: renderDelegate - Item { - id: wrapperItem - height: 20 - width: parent.width - RowLayout { - anchors.fill: parent - visible: !(index === projectList.currentIndex) || !renameMode - Text { - id: nameText - Layout.fillWidth: true - Layout.fillHeight: true - text: name - font.pointSize: 12 - verticalAlignment: Text.AlignBottom + + ListModel + { + id: ctrModel } - } - TextInput { - id: textInput - text: nameText.text - visible: (index === projectList.currentIndex) && renameMode - MouseArea { - id: textMouseArea - anchors.fill: parent - hoverEnabled: true - z:2 - onClicked: { - textInput.forceActiveFocus(); + FilesSection + { + id: javascriptSection + sectionName: "Javascript" + projectModel: projectModelConnection + model: javascriptModel + selManager: selManager + onDocumentSelected: { + selManager.selected(doc, groupName); } } - onVisibleChanged: { - if (visible) { - selectAll(); - forceActiveFocus(); + ListModel + { + id: javascriptModel + } + + FilesSection + { + id: htmlSection + sectionName: "HTML" + projectModel: projectModelConnection + model: htmlModel + selManager: selManager + onDocumentSelected: { + selManager.selected(doc, groupName); } } - onAccepted: close(true); - onCursorVisibleChanged: { - if (!cursorVisible) - close(false); + ListModel + { + id: htmlModel } - onFocusChanged: { - if (!focus) - close(false); + + FilesSection + { + id: stylesSection + sectionName: "Styles" + model: styleModel + projectModel: projectModelConnection + selManager: selManager + onDocumentSelected: { + selManager.selected(doc, groupName); + } } - function close(accept) { - renameMode = false; - if (accept) - projectModel.renameDocument(projectList.model.get(projectList.currentIndex).documentId, textInput.text); + + ListModel + { + id: styleModel } - } - MouseArea { - id: mouseArea - z: 1 - hoverEnabled: false - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked:{ - projectList.currentIndex = index; - if (mouse.button === Qt.RightButton && !projectList.model.get(index).isContract) - contextMenu.popup(); + + FilesSection + { + id: imgSection + projectModel: projectModelConnection + sectionName: "Images" + model: imgModel + selManager: selManager + onDocumentSelected: { + selManager.selected(doc, groupName); + } + } + + ListModel + { + id: imgModel } } } } + Connections { + id: projectModelConnection + signal projectFilesLoaded; target: projectModel - onProjectLoaded: { - projectList.currentIndex = 0; - if (projectList.currentIndex >= 0 && projectList.currentIndex < projectModel.listModel.count) - projectModel.openDocument(projectModel.listModel.get(projectList.currentIndex).documentId); - - } - onProjectClosed: { - projectList.currentIndex = -1; + function addDocToSubModel(index) + { + var item = projectModel.listModel.get(index); + if (item.groupName === "Contracts") + ctrModel.append(item); + else if (item.groupName === "HTML") + htmlModel.append(item) + else if (item.groupName === "Javascript") + javascriptModel.append(item) + else if (item.groupName === "Images") + imagesModel.append(item) + else if (item.groupName === "Styles") + stylesModel.append(item) } - onDocumentOpened: { - if (projectList.currentItem.documentId !== document.documentId) - projectList.currentIndex = projectModel.getDocumentIndex(document.documentId); + onProjectLoaded: { + projectModel.openDocument(projectModel.listModel.get(0).documentId); + ctrModel.clear(); + htmlModel.clear(); + javascriptModel.clear(); + imgModel.clear(); + styleModel.clear(); + for (var k = 0; k < projectModel.listModel.count; k++) + addDocToSubModel(k); + projectFilesLoaded(); + } + onDocumentAdded: + { + addDocToSubModel(projectModel.getDocumentIndex(documentId)); } } } diff --git a/mix/qml/Style.qml b/mix/qml/Style.qml new file mode 100644 index 000000000..30be8fcc3 --- /dev/null +++ b/mix/qml/Style.qml @@ -0,0 +1,26 @@ +pragma Singleton +import QtQuick 2.0 + +/* + * Project Files + */ +QtObject { + property QtObject general: QtObject { + property int leftMargin: 30 + } + + property QtObject title: QtObject { + property string color: "#878787" + property string background: "#f0f0f0" + property int height: 40 + } + + property QtObject documentsList: QtObject { + property string background: "#f7f7f7" + property string color: "#4d4d4d" + property string selectedColor: "white" + property string highlightColor: "#4a90e2" + property int height: 30 + property int fontSize: 12 + } +} diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 4d501ffca..7ba02bc90 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -89,6 +89,7 @@ function addFile(fileName) { var isCss = extension === ".css"; var isJs = extension === ".js"; var syntaxMode = isContract ? "solidity" : isJs ? "javascript" : isHtml ? "htmlmixed" : isCss ? "css" : ""; + var groupName = isContract ? "Contracts" : isJs ? "Javascript" : isHtml ? "HTML" : isCss ? "Styles" : ""; var docData = { contract: false, path: p, @@ -99,6 +100,7 @@ function addFile(fileName) { isText: isContract || isHtml || isCss || isJs, isContract: isContract, isHtml: isHtml, + groupName: groupName }; projectListModel.append(docData); @@ -172,8 +174,8 @@ function doCreateProject(title, path) { files: [ contractsFile, indexFile ] }; //TODO: copy from template - fileIo.writeFile(dirPath + indexFile, "\n\n\n\n\n\n\n"); - fileIo.writeFile(dirPath + contractsFile, "contract Contract {\n}\n"); + fileIo.writeFile(dirPath + indexFile, "\n\n\n\n\n\n\n"); + fileIo.writeFile(dirPath + contractsFile, "contract Contract {\n}\n"); newProject(projectData); var json = JSON.stringify(projectData, null, "\t"); fileIo.writeFile(projectFile, json); diff --git a/mix/qml/qmldir b/mix/qml/qmldir new file mode 100644 index 000000000..819842274 --- /dev/null +++ b/mix/qml/qmldir @@ -0,0 +1 @@ +singleton Style 1.0 Style.qml diff --git a/mix/res.qrc b/mix/res.qrc index d73635f9d..cc8225f84 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -63,5 +63,8 @@ res/mix_256x256x32.png qml/CallStack.qml qml/QVariableDeclaration.qml + qml/Style.qml + qml/qmldir + qml/FilesSection.qml