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: codeEditorView property string currentDocumentId: "" property string sourceInError property int openDocCount: 0 signal documentEdit(string documentId) signal breakpointsChanged(string documentId) signal isCleanChanged(var isClean, string documentId) signal loadComplete function getDocumentText(documentId) { for (var i = 0; i < openDocCount; i++) { if (editorListModel.get(i).documentId === documentId) { return editors.itemAt(i).item.getText(); } } return ""; } function isDocumentOpen(documentId) { for (var i = 0; i < openDocCount; i++) if (editorListModel.get(i).documentId === documentId && editors.itemAt(i).item) return true; return false; } function openDocument(document) { loadDocument(document); currentDocumentId = document.documentId; } function loadDocument(document) { for (var i = 0; i < openDocCount; i++) if (editorListModel.get(i).documentId === document.documentId) return; //already open if (editorListModel.count <= openDocCount) editorListModel.append(document); else { editorListModel.set(openDocCount, document); doLoadDocument(editors.itemAt(openDocCount).item, editorListModel.get(openDocCount), false) loadComplete(); } openDocCount++; } function doLoadDocument(editor, document, create) { var data = fileIo.readFile(document.path); if (create) { editor.onLoadComplete.connect(function() { codeEditorView.loadComplete(); }); editor.onEditorTextChanged.connect(function() { documentEdit(editor.document.documentId); if (editor.document.isContract) codeModel.registerCodeChange(editor.document.documentId, editor.getText()); }); editor.onBreakpointsChanged.connect(function() { if (editor.document.isContract) breakpointsChanged(editor.document.documentId); }); editor.onIsCleanChanged.connect(function() { isCleanChanged(editor.isClean, editor.document.documentId); }); } editor.document = document; editor.setFontSize(editorSettings.fontSize); editor.sourceName = document.documentId; editor.setText(data, document.syntaxMode); editor.changeGeneration(); } function getEditor(documentId) { for (var i = 0; i < openDocCount; i++) { if (editorListModel.get(i).documentId === documentId) return editors.itemAt(i).item; } return null; } function highlightExecution(documentId, location) { var editor = getEditor(documentId); if (editor) { if (documentId !== location.sourceName) findAndHightlight(location.start, location.end, location.sourceName) else editor.highlightExecution(location); } } // Execution is not in the current document. Try: // Open targeted document and hightlight (TODO) or // Warn user that file is not available function findAndHightlight(start, end, sourceName) { var editor = getEditor(currentDocumentId); if (editor) editor.showWarning(qsTr("Currently debugging in " + sourceName + ". Source not available.")); } function editingContract() { for (var i = 0; i < openDocCount; i++) if (editorListModel.get(i).documentId === currentDocumentId) return editorListModel.get(i).isContract; return false; } function getBreakpoints() { var bpMap = {}; for (var i = 0; i < openDocCount; i++) { var documentId = editorListModel.get(i).documentId; var editor = editors.itemAt(i).item; if (editor) { bpMap[documentId] = editor.getBreakpoints(); } } return bpMap; } function toggleBreakpoint() { var editor = getEditor(currentDocumentId); if (editor) editor.toggleBreakpoint(); } function resetEditStatus(docId) { var editor = getEditor(docId); if (editor) editor.changeGeneration(); } function goToCompilationError() { if (sourceInError === "") return; if (currentDocumentId !== sourceInError) projectModel.openDocument(sourceInError); for (var i = 0; i < openDocCount; i++) { var doc = editorListModel.get(i); if (doc.isContract && doc.documentId === sourceInError) { var editor = editors.itemAt(i).item; if (editor) editor.goToCompilationError(); break; } } } function setFontSize(size) { if (size <= 10 || size >= 48) return; editorSettings.fontSize = size; for (var i = 0; i < editors.count; i++) editors.itemAt(i).item.setFontSize(size); } function displayGasEstimation(checked) { var editor = getEditor(currentDocumentId); if (editor) editor.displayGasEstimation(checked); } Component.onCompleted: projectModel.codeEditor = codeEditorView; Connections { target: codeModel onCompilationError: { sourceInError = _firstErrorLoc.source; } onCompilationComplete: { sourceInError = ""; var gasCosts = codeModel.gasCostByDocumentId(currentDocumentId); var editor = getEditor(currentDocumentId); if (editor) editor.setGasCosts(gasCosts); } } Connections { target: projectModel onDocumentOpened: { openDocument(document); } onProjectSaving: { for (var i = 0; i < openDocCount; i++) { var doc = editorListModel.get(i); if (editors.itemAt(i)) { var editor = editors.itemAt(i).item; if (editor) fileIo.writeFile(doc.path, editor.getText()); } } } onProjectSaved: { if (projectModel.appIsClosing || projectModel.projectIsClosing) return; for (var i = 0; i < openDocCount; i++) { var doc = editorListModel.get(i); resetEditStatus(doc.documentId); } } onProjectClosed: { currentDocumentId = ""; openDocCount = 0; } 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; } } } } CodeEditorStyle { id: style; } 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, false); resetEditStatus(doc.documentId); } } Repeater { id: editors model: editorListModel onItemRemoved: { item.item.unloaded = true; } delegate: Loader { id: loader active: false asynchronous: true anchors.fill: parent source: appService.haveWebEngine ? "WebCodeEditor.qml" : "CodeEditor.qml" visible: (index >= 0 && index < openDocCount && currentDocumentId === editorListModel.get(index).documentId) property bool changed: false onVisibleChanged: { loadIfNotLoaded() if (visible && item) { loader.item.setFocus(); if (changed) { changed = false; messageDialog.item = loader.item; messageDialog.doc = editorListModel.get(index); messageDialog.open(); } loader.item.displayGasEstimation(gasEstimationAction.checked); } } Component.onCompleted: { loadIfNotLoaded() } onLoaded: { doLoadDocument(loader.item, editorListModel.get(index), true) } 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; } } onDocumentRemoved: { for (var i = 0; i < editorListModel.count; i++) if (editorListModel.get(i).documentId === documentId) { editorListModel.remove(i); openDocCount--; break; } } } function loadIfNotLoaded () { if (visible && !active) { active = true; } } } } ListModel { id: editorListModel } Action { id: increaseFontSize text: qsTr("Increase Font Size") shortcut: "Ctrl+=" onTriggered: setFontSize(editorSettings.fontSize + 1) } Action { id: decreaseFontSize text: qsTr("Decrease Font Size") shortcut: "Ctrl+-" onTriggered: setFontSize(editorSettings.fontSize - 1) } Settings { id: editorSettings property int fontSize: 12; } }