diff --git a/components/kube/qml/Kube.qml b/components/kube/qml/Kube.qml index b158e1e8..8cbe8691 100644 --- a/components/kube/qml/Kube.qml +++ b/components/kube/qml/Kube.qml @@ -1,331 +1,331 @@ /* * Copyright (C) 2017 Michael Bohlender, * Copyright (C) 2017 Christian Mollekopf, * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.7 import QtQuick.Layouts 1.3 import QtQuick.Window 2.0 import QtQuick.Controls 2.0 as Controls2 import org.kube.framework 1.0 as Kube Controls2.ApplicationWindow { id: app property int sidebarWidth: Kube.Units.gridUnit + Kube.Units.largeSpacing height: Screen.desktopAvailableHeight * 0.8 width: Screen.desktopAvailableWidth * 0.8 visible: true //Application default font font.family: Kube.Font.fontFamily //Application context property variant currentFolder onCurrentFolderChanged: { if (!!currentFolder) { Kube.Fabric.postMessage(Kube.Messages.synchronize, {"folder": currentFolder}) } } property variant currentAccount onCurrentAccountChanged: { if (!!currentAccount) { Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": currentAccount}) } } //Interval sync Timer { id: intervalSync //5min interval: 300000 running: !!app.currentFolder repeat: true onTriggered: { Kube.Fabric.postMessage(Kube.Messages.synchronize, {"folder": app.currentFolder}) Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": app.currentAccount, "type": "folder"}) } } Kube.StartupCheck { id: startupCheck } Accounts { } //Listener Kube.Listener { filter: Kube.Messages.accountSelection onMessageReceived: app.currentAccount = message.accountId } Kube.Listener { filter: Kube.Messages.folderSelection onMessageReceived: app.currentFolder = message.folder } Kube.Listener { filter: Kube.Messages.notification onMessageReceived: { if (message.message) { notificationPopup.notify(message.message); } } } //BEGIN Shortcuts Shortcut { sequence: StandardKey.Quit onActivated: Qt.quit() } Shortcut { onActivated: Kube.Fabric.postMessage(Kube.Messages.search, {}) sequence: StandardKey.Find } Shortcut { id: syncShortcut sequence: StandardKey.Refresh onActivated: { if (!!app.currentFolder) { Kube.Fabric.postMessage(Kube.Messages.synchronize, {"folder": app.currentFolder}); Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": app.currentAccount, "type": "folder"}) } else { Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": app.currentAccount}) } } } //END Shortcuts //BEGIN background Rectangle { anchors.fill: parent color: Kube.Colors.backgroundColor } //END background //BEGIN Main content RowLayout { id: mainContent spacing: 0 anchors.fill: parent Rectangle { id: sideBar anchors { top: mainContent.top bottom: mainContent.bottom } width: app.sidebarWidth - color: Kube.Colors.textColor + color: Kube.Colors.darkBackgroundColor Rectangle { anchors.right: parent.right width: 1 height: parent.height color: Kube.Colors.viewBackgroundColor opacity: 0.3 } Controls2.ButtonGroup { id: viewButtonGroup } Column { anchors { top: parent.top topMargin: Kube.Units.smallSpacing horizontalCenter: parent.horizontalCenter } spacing: Kube.Units.largeSpacing - Kube.Units.smallSpacing Repeater { model: Kube.ExtensionModel { id: extensionModel extensionPoint: "views" sortOrder: ["composer", "conversation", "people"] } Kube.IconButton { id: button iconName: model.icon onClicked: kubeViews.showView(model.name) activeFocusOnTab: true checkable: true Controls2.ButtonGroup.group: viewButtonGroup tooltip: model.tooltip checked: kubeViews.currentViewName == model.name } } } Column { anchors { bottom: parent.bottom bottomMargin: Kube.Units.smallSpacing horizontalCenter: parent.horizontalCenter } spacing: Kube.Units.largeSpacing - Kube.Units.smallSpacing Kube.Outbox { height: Kube.Units.gridUnit * 1.5 width: height Kube.ToolTip { text: qsTr("Outbox") visible: parent.hovered } } Kube.IconButton { id: logButton iconName: Kube.Icons.info_inverted onClicked: kubeViews.showView("log") activeFocusOnTab: true checkable: true visible: false Kube.Listener { filter: Kube.Messages.errorPending onMessageReceived: logButton.alert = message.errorPending } Kube.Listener { filter: Kube.Messages.notificationPending onMessageReceived: logButton.visible = true } checked: kubeViews.currentViewName == "log" Controls2.ButtonGroup.group: viewButtonGroup tooltip: qsTr("Notification View") } Kube.IconButton { id: accountsButton iconName: Kube.Icons.menu_inverted onClicked: kubeViews.showView("accounts") activeFocusOnTab: true checkable: true checked: kubeViews.currentViewName == "accounts" Controls2.ButtonGroup.group: viewButtonGroup tooltip: qsTr("Settings") } } } ViewManager { id: kubeViews anchors { top: mainContent.top bottom: mainContent.bottom } Layout.fillWidth: true extensionModel: extensionModel Component.onCompleted: { dontFocus = true prepareViewInBackground("log", {}) showView("conversation") if (startupCheck.noAccount) { showView("accounts") } dontFocus = false } Kube.Listener { filter: Kube.Messages.reply onMessageReceived: kubeViews.replaceView("composer", {message: message.mail, loadType: Kube.ComposerController.Reply}) } Kube.Listener { filter: Kube.Messages.forward onMessageReceived: kubeViews.replaceView("composer", {message: message.mail, loadType: Kube.ComposerController.Forward}) } Kube.Listener { filter: Kube.Messages.edit onMessageReceived: kubeViews.replaceView("composer", {message: message.mail, loadType: Kube.ComposerController.Draft}) } Kube.Listener { filter: Kube.Messages.compose onMessageReceived: kubeViews.replaceView("composer", {newMessage: true, recipients: message.recipients}) } Kube.Listener { filter: Kube.Messages.requestAccountsConfiguration onMessageReceived: kubeViews.showView("accounts") } Kube.Listener { filter: Kube.Messages.componentDone onMessageReceived: { kubeViews.closeView() } } Kube.Listener { filter: Kube.Messages.requestLogin onMessageReceived: { var view = loginView.createObject(kubeViews, {accountId: message.accountId}) view.forceActiveFocus() } } Component { id: loginView Kube.Popup { id: popup property alias accountId: login.accountId visible: true parent: Controls2.ApplicationWindow.overlay height: app.height width: app.width - app.sidebarWidth x: app.sidebarWidth y: 0 modal: true closePolicy: Controls2.Popup.NoAutoClose Kube.LoginAccount { id: login anchors { fill: parent bottomMargin: Kube.Units.largeSpacing } onDone: { kubeViews.currentItem.forceActiveFocus() popup.destroy() } } } } } } //END Main content //BEGIN Notification Kube.NotificationPopup { id: notificationPopup anchors { left: parent.left leftMargin: app.sidebarWidth - 3 // so it does not align with the border bottom: parent.bottom bottomMargin: Kube.Units.gridUnit * 4 } } //END Notification } diff --git a/framework/qml/TreeView.qml b/framework/qml/TreeView.qml index c4a1a2ab..3f30959f 100644 --- a/framework/qml/TreeView.qml +++ b/framework/qml/TreeView.qml @@ -1,183 +1,183 @@ /* Copyright (C) 2016 Michael Bohlender, Copyright (C) 2017 Christian Mollekopf, This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.4 import QtQuick.Controls 1.4 as Controls1 import QtQuick.Controls 2 as Controls2 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.1 import QtQml.Models 2.2 import org.kube.framework 1.0 as Kube FocusScope { id: root default property alias __columns: treeView.__columns property alias model: treeView.model property alias currentIndex: treeView.currentIndex /* * Because active focus is useless in list/treeviews we use the concept of an activeIndex. * The current selection represents the focused index. The activeIndex represents the selected index. * FIXME: This is what QItemSelectionModel selection vs current selection are for. Try to use that instead. */ property var activeIndex: null signal activated(var index) onActivated: { activeIndex = index } function indexFromRow(row) { //FIXME Uses internal API to get to the model index return treeView.__model.mapRowToModelIndex(row) } function selectNext() { treeView.__listView.incrementCurrentIndexBlocking() treeView.__mouseArea.keySelect(Qt.NoModifier) activated(treeView.selection.currentIndex) } function selectPrevious() { treeView.__listView.decrementCurrentIndexBlocking() treeView.__mouseArea.keySelect(Qt.NoModifier) activated(treeView.selection.currentIndex) } function selectRootIndex() { treeView.selection.setCurrentIndex(model.index(0, 0), ItemSelectionModel.ClearAndSelect) activated(treeView.selection.currentIndex) } Flickable { id: flickableItem anchors.fill: parent Controls2.ScrollBar.vertical: Kube.ScrollBar { invertedColors: true } clip: true contentWidth: root.width contentHeight: treeView.implicitHeight Kube.ScrollHelper { id: scrollHelper flickable: flickableItem } Controls1.TreeView { id: treeView anchors { left: parent.left right: parent.right } implicitHeight: __listView.contentItem.height + 2 height: implicitHeight focus: true verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff Kube.MouseProxy { anchors.fill: parent target: scrollHelper forwardWheelEvents: true } flickableItem.boundsBehavior: Flickable.StopAtBounds selection: ItemSelectionModel { model: treeView.model //TODO once we don't loose focus to the next view // onCurrentChanged: { // treeView.activated(selection.currentIndex) // } //TODO scroll view so the current index is always visible } onActiveFocusChanged: { //Set an initially focused item when the list view receives focus if (activeFocus) { //If there is a selected index, reset to selected index. if (root.activeIndex) { treeView.selection.setCurrentIndex(root.activeIndex, ItemSelectionModel.Current) } else { treeView.selection.setCurrentIndex(model.index(0, 0), ItemSelectionModel.ClearAndSelect) } } else { selection.clearCurrentIndex() } } Keys.onReturnPressed: treeView.activated(selection.currentIndex) //Forward the signal because on a desktopsystem activated is only triggerd by double clicks onClicked: treeView.activated(index) onActivated: root.activated(index) //Select the initial index when the folder list is loaded Connections { target: treeView.__listView onCountChanged: { root.selectRootIndex() //Only do this initially enabled = false } } alternatingRowColors: false headerVisible: false style: TreeViewStyle { rowDelegate: Controls2.Control { id: delegateRoot property bool isActive: root.activeIndex === indexFromRow(styleData.row) height: Kube.Units.gridUnit * 1.5 //FIXME This is the only way I could find to get the correct width. parent.width is way to wide width: parent.parent.parent ? parent.parent.parent.width : 0 focus: false hoverEnabled: true Kube.DelegateBackground { anchors.fill: parent color: Kube.Colors.textColor focused: styleData.selected || delegateRoot.hovered selected: isActive } } frame: Rectangle { color: Kube.Colors.textColor } branchDelegate: Kube.Label { width: 16 height: width anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: Kube.Units.smallSpacing color: Kube.Colors.viewBackgroundColor text: styleData.isExpanded ? "-" : "+" } - backgroundColor: Kube.Colors.textColor + backgroundColor: Kube.Colors.darkBackgroundColor highlightedTextColor: Kube.Colors.highlightedTextColor } } } } diff --git a/framework/qml/View.qml b/framework/qml/View.qml index 2cc8663f..9daa76a8 100644 --- a/framework/qml/View.qml +++ b/framework/qml/View.qml @@ -1,107 +1,107 @@ /* * Copyright (C) 2017 Michael Bohlender, * Copyright (C) 2017 Christian Mollekopf, * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.7 import QtQuick.Controls 2.0 as Controls2 import QtQuick.Layouts 1.1 import org.kube.framework 1.0 as Kube FocusScope { id: container property int visibleViews: 2 property int currentIndex: 0 property int count: contentItems.length default property alias contentItems: content.data property bool __aborted: false //This signal will be emitted once all initial properties have been set and the view is ready to load signal setup() Controls2.StackView.onActivated: { root.setup() } //This signal will be emitted before destruction if the view was not done signal aborted() onAborted: { __aborted = true } //This signal will be emitted when the view is done signal done() onDone: { if (!__aborted) { Kube.Fabric.postMessage(Kube.Messages.componentDone, {}) } } onCurrentIndexChanged: showRelevantSplits() Component.onCompleted: showRelevantSplits() function incrementCurrentIndex() { if (currentIndex < count) { currentIndex = currentIndex + 1 } } function decrementCurrentIndex() { if (currentIndex > 0) { currentIndex = currentIndex - 1 } } function showRelevantSplits() { var i; for (i = 0; i < count; i++) { if (i < currentIndex) { contentItems[i].visible = false; } else if (i > (currentIndex + visibleViews - 1)) { contentItems[i].visible = false; } else { contentItems[i].visible = true; } } } Kube.IconButton { anchors { top: container.top left: container.left } z: 1 - color: Kube.Colors.textColor + color: Kube.Colors.darkBackgroundColor iconName: Kube.Icons.goBack_inverted visible: currentIndex > 0 onClicked: decrementCurrentIndex() } Keys.onEscapePressed: { if (currentIndex > 0) { decrementCurrentIndex() } } RowLayout { id: content anchors.fill: parent } } diff --git a/views/calendar/qml/View.qml b/views/calendar/qml/View.qml index f870a850..c46b9480 100644 --- a/views/calendar/qml/View.qml +++ b/views/calendar/qml/View.qml @@ -1,110 +1,110 @@ /* * Copyright (C) 2018 Michael Bohlender, * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Controls 1.3 as Controls1 import QtQuick.Layouts 1.2 import org.kube.framework 1.0 as Kube RowLayout { id: root //TODO update every second property date currentDate: new Date() anchors.fill: parent Rectangle { width: Kube.Units.gridUnit * 10 Layout.fillHeight: parent.height - color: Kube.Colors.textColor + color: Kube.Colors.darkBackgroundColor Kube.PositiveButton { id: newEventButton objectName: "newEventButton" anchors { top: parent.top left: parent.left right: parent.right margins: Kube.Units.largeSpacing } focus: true text: qsTr("New Event") onClicked: {} } Column { anchors { top: newEventButton.bottom left: newEventButton.left topMargin: Kube.Units.largeSpacing } width: parent.width spacing: Kube.Units.smallSpacing Kube.Label { text: "Week" color: Kube.Colors.highlightedTextColor } Kube.Label { text: "Month" color: Kube.Colors.highlightedTextColor } Kube.Label { text: "Agenda" color: Kube.Colors.highlightedTextColor } } Column { anchors { bottom: parent.bottom left: newEventButton.left bottomMargin: Kube.Units.largeSpacing } spacing: Kube.Units.smallSpacing Repeater { model: ["calendar_1","calendar_2","calendar_3"] delegate: Row { spacing: Kube.Units.smallSpacing Kube.CheckBox { opacity: 0.9 } Kube.Label { text: modelData color: Kube.Colors.highlightedTextColor } } } } } WeekView { Layout.fillHeight: true Layout.fillWidth: true currentDate: root.currentDate } } diff --git a/views/composer/qml/View.qml b/views/composer/qml/View.qml index babe5f47..97604456 100644 --- a/views/composer/qml/View.qml +++ b/views/composer/qml/View.qml @@ -1,560 +1,560 @@ /* * Copyright (C) 2017 Michael Bohlender, * Copyright (C) 2017 Christian Mollekopf, * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.7 import QtQuick.Controls 2.0 as Controls2 import QtQuick.Layouts 1.1 import QtQuick.Dialogs 1.0 as Dialogs import org.kube.framework 1.0 as Kube Kube.View { id: root property bool newMessage: false property int loadType: Kube.ComposerController.Draft property variant message: {} property variant recipients: [] resources: [ Kube.ComposerController { id: composerController sign: signCheckbox.checked encrypt: encryptCheckbox.checked onDone: root.done() property bool foundAllKeys: composerController.to.foundAllKeys && composerController.cc.foundAllKeys && composerController.bcc.foundAllKeys sendAction.enabled: composerController.accountId && composerController.subject && (!composerController.encrypt || composerController.foundAllKeys) && (!composerController.sign && !composerController.encrypt || composerController.foundPersonalKeys) && !composerController.to.empty saveAsDraftAction.enabled: composerController.accountId onMessageLoaded: { textEditor.initialText = body } onCleared: { textEditor.initialText = "" } } ] onSetup: { loadMessage(root.message, root.loadType) Kube.Fabric.postMessage(Kube.Messages.synchronize, {"type": "mail", "specialPurpose": "drafts"}) //For autocompletion Kube.Fabric.postMessage(Kube.Messages.synchronize, {"type": "contacts"}) } onAborted: { //Avoid loosing the message if (composerController.saveAsDraftAction.enabled) { composerController.saveAsDraftAction.execute() } } function loadMessage(message, loadType) { if (message) { switch(loadType) { case Kube.ComposerController.Draft: composerController.loadDraft(message) break; case Kube.ComposerController.Reply: composerController.loadReply(message) subject.forceActiveFocus() break; case Kube.ComposerController.Forward: composerController.loadForward(message) subject.forceActiveFocus() break; } } else if (newMessage) { composerController.clear() if (root.recipients) { for (var i = 0; i < root.recipients.length; ++i) { composerController.to.add({name: root.recipients[i]}) } } subject.forceActiveFocus() } } function closeFirstSplitIfNecessary() { //Move the view forward if (root.currentIndex == 0) { root.incrementCurrentIndex() } } //Drafts Rectangle { anchors { top: parent.top bottom: parent.bottom } width: Kube.Units.gridUnit * 15 Layout.minimumWidth: Kube.Units.gridUnit * 5 - color: Kube.Colors.textColor + color: Kube.Colors.darkBackgroundColor ColumnLayout { anchors { fill: parent topMargin: Kube.Units.largeSpacing leftMargin: Kube.Units.largeSpacing } spacing: Kube.Units.largeSpacing Kube.PositiveButton { objectName: "newMailButton" width: parent.width - Kube.Units.largeSpacing focus: true text: qsTr("New Email") onClicked: { listView.currentIndex = -1 composerController.clear() subject.forceActiveFocus() } } Kube.Label{ text: qsTr("Drafts") color: Kube.Colors.highlightedTextColor font.weight: Font.Bold } Kube.ListView { id: listView activeFocusOnTab: true anchors { left: parent.left right: parent.right } Layout.fillHeight: true clip: true currentIndex: -1 highlightFollowsCurrentItem: false //BEGIN keyboard nav onActiveFocusChanged: { if (activeFocus && currentIndex < 0) { currentIndex = 0 } } Keys.onDownPressed: { listView.incrementCurrentIndex() } Keys.onUpPressed: { listView.decrementCurrentIndex() } //END keyboard nav onCurrentItemChanged: { if (currentItem) { root.loadMessage(currentItem.currentData.domainObject, Kube.ComposerController.Draft) } } model: Kube.MailListModel { id: mailListModel showDrafts: true } delegate: Kube.ListDelegate { id: delegateRoot - color: Kube.Colors.textColor + color: Kube.Colors.darkBackgroundColor border.width: 0 Item { id: content anchors { fill: parent margins: Kube.Units.smallSpacing } Kube.Label { width: content.width - Kube.Units.largeSpacing text: model.subject == "" ? "no subject" : model.subject color: Kube.Colors.highlightedTextColor maximumLineCount: 2 wrapMode: Text.WrapAnywhere elide: Text.ElideRight } Kube.Label { anchors { right: parent.right rightMargin: Kube.Units.largeSpacing bottom: parent.bottom } text: Qt.formatDateTime(model.date, "dd MMM yyyy") font.italic: true color: Kube.Colors.disabledTextColor font.pointSize: Kube.Units.smallFontSize visible: !delegateRoot.hovered } } Row { id: buttons anchors { right: parent.right bottom: parent.bottom bottomMargin: Kube.Units.smallSpacing rightMargin: Kube.Units.largeSpacing } visible: delegateRoot.hovered spacing: Kube.Units.smallSpacing opacity: 0.7 Kube.IconButton { id: deleteButton activeFocusOnTab: true iconName: Kube.Icons.moveToTrash visible: enabled enabled: !!model.mail onClicked: Kube.Fabric.postMessage(Kube.Messages.moveToTrash, {"mail": model.mail}) } } } } } } //Content Rectangle { Layout.fillWidth: true Layout.minimumWidth: Kube.Units.gridUnit * 5 anchors { top: parent.top bottom: parent.bottom } color: Kube.Colors.backgroundColor ColumnLayout { anchors { fill: parent margins: Kube.Units.largeSpacing leftMargin: Kube.Units.largeSpacing + Kube.Units.gridUnit * 2 rightMargin: Kube.Units.largeSpacing + Kube.Units.gridUnit * 2 } spacing: Kube.Units.smallSpacing Kube.TextField { id: subject objectName: "subject" Layout.fillWidth: true activeFocusOnTab: true placeholderText: qsTr("Enter Subject...") text: composerController.subject onTextChanged: composerController.subject = text; onActiveFocusChanged: { if (activeFocus) { closeFirstSplitIfNecessary() } } } Flow { id: attachments Layout.fillWidth: true layoutDirection: Qt.RightToLeft spacing: Kube.Units.smallSpacing clip: true Repeater { model: composerController.attachments.model delegate: Kube.AttachmentDelegate { name: model.filename icon: model.iconname clip: true actionIcon: Kube.Icons.remove onExecute: composerController.attachments.remove(model.id) } } } RowLayout { spacing: Kube.Units.largeSpacing Kube.Switch { id: html text: checked ? qsTr("plain") : qsTr("html") focusPolicy: Qt.TabFocus focus: false checked: false onCheckedChanged: { textEditor.htmlEnabled = checked } } Row { visible: html.checked spacing: 1 Kube.IconButton { iconName: Kube.Icons.bold checkable: true checked: textEditor.bold onClicked: textEditor.bold = !textEditor.bold focusPolicy: Qt.TabFocus focus: false } Kube.IconButton { iconName: Kube.Icons.italic checkable: true checked: textEditor.italic onClicked: textEditor.italic = !textEditor.italic focusPolicy: Qt.TabFocus focus: false } Kube.IconButton { iconName: Kube.Icons.underline checkable: true checked: textEditor.underline onClicked: textEditor.underline = !textEditor.underline focusPolicy: Qt.TabFocus focus: false } } Item { height: 1 Layout.fillWidth: true } Kube.Button { text: qsTr("Attach file") onClicked: { fileDialogComponent.createObject(parent) } Component { id: fileDialogComponent Dialogs.FileDialog { id: fileDialog visible: true title: "Choose a file to attach" selectFolder: false onAccepted: { composerController.attachments.add({url: fileDialog.fileUrl}) } } } } } Kube.TextEditor { id: textEditor objectName: "textEditor" activeFocusOnTab: true Layout.fillWidth: true Layout.fillHeight: true onHtmlEnabledChanged: { html.checked = htmlEnabled composerController.htmlBody = htmlEnabled; } onActiveFocusChanged: closeFirstSplitIfNecessary() Keys.onEscapePressed: recipients.forceActiveFocus(Qt.TabFocusReason) onTextChanged: { composerController.body = text; } } } } //Recepients FocusScope { id: recipients anchors { top: parent.top bottom: parent.bottom } width: Kube.Units.gridUnit * 15 activeFocusOnTab: true //background Rectangle { anchors.fill: parent color: Kube.Colors.backgroundColor Rectangle { height: parent.height width: 1 color: Kube.Colors.buttonColor } } //Content ColumnLayout { anchors { fill: parent margins: Kube.Units.largeSpacing } spacing: Kube.Units.largeSpacing ColumnLayout { Layout.maximumWidth: parent.width Layout.fillWidth: true Layout.fillHeight: true Kube.Label { text: qsTr("Sending Email to:") } AddresseeListEditor { Layout.preferredHeight: implicitHeight Layout.fillWidth: true focus: true activeFocusOnTab: true encrypt: composerController.encrypt controller: composerController.to completer: composerController.recipientCompleter } Kube.Label { text: qsTr("Sending Copy to (CC):") } AddresseeListEditor { id: cc Layout.preferredHeight: cc.implicitHeight Layout.fillWidth: true activeFocusOnTab: true encrypt: composerController.encrypt controller: composerController.cc completer: composerController.recipientCompleter } Kube.Label { text: qsTr("Sending Secret Copy to (Bcc):") } AddresseeListEditor { id: bcc Layout.preferredHeight: bcc.implicitHeight Layout.fillWidth: true activeFocusOnTab: true encrypt: composerController.encrypt controller: composerController.bcc completer: composerController.recipientCompleter } Item { width: parent.width Layout.fillHeight: true } } RowLayout { enabled: composerController.foundPersonalKeys Kube.CheckBox { id: encryptCheckbox checked: false } Kube.Label { text: qsTr("encrypt") } } RowLayout { enabled: composerController.foundPersonalKeys Kube.CheckBox { id: signCheckbox checked: false } Kube.Label { text: qsTr("sign") } } Kube.Label { visible: !composerController.foundPersonalKeys Layout.maximumWidth: parent.width text: qsTr("Encryption is not available because your personal key has not been found.") wrapMode: Text.Wrap } RowLayout { Layout.maximumWidth: parent.width width: parent.width height: Kube.Units.gridUnit Kube.Button { width: saveDraftButton.width text: qsTr("Discard") onClicked: root.done() } Kube.Button { id: saveDraftButton text: qsTr("Save as Draft") enabled: composerController.saveAsDraftAction.enabled onClicked: { composerController.saveAsDraftAction.execute() } } } ColumnLayout { Layout.maximumWidth: parent.width Layout.fillWidth: true Kube.Label { id: fromLabel text: qsTr("You are sending this from:") } Kube.ComboBox { id: identityCombo width: parent.width - Kube.Units.largeSpacing * 2 model: composerController.identitySelector.model textRole: "address" Layout.fillWidth: true onCurrentIndexChanged: { composerController.identitySelector.currentIndex = currentIndex } } } Kube.PositiveButton { objectName: "sendButton" id: sendButton width: parent.width text: qsTr("Send") enabled: composerController.sendAction.enabled onClicked: { composerController.sendAction.execute() } } } }//FocusScope } diff --git a/views/search/qml/View.qml b/views/search/qml/View.qml index d63f6d1f..63e56e44 100644 --- a/views/search/qml/View.qml +++ b/views/search/qml/View.qml @@ -1,84 +1,84 @@ /* * Copyright (C) 2017 Michael Bohlender, * Copyright (C) 2017 Christian Mollekopf, * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.7 import QtQuick.Controls 1.3 as Controls1 import QtQuick.Controls 2.0 as Controls2 import QtQuick.Layouts 1.1 import org.kube.framework 1.0 as Kube FocusScope { Controls1.SplitView { anchors.fill: parent ColumnLayout { width: Kube.Units.gridUnit * 18 Layout.minimumWidth: Kube.Units.gridUnit * 10 Rectangle { id: filterField Layout.fillWidth: true height: Kube.Units.gridUnit * 2 - color: Kube.Colors.textColor + color: Kube.Colors.darkBackgroundColor function clearSearch() { find.text = "" mailListView.filter = "" } RowLayout { anchors { verticalCenter: parent.verticalCenter } width: parent.width - Kube.Units.smallSpacing spacing: 0 Kube.IconButton { iconName: Kube.Icons.remove onClicked: filterField.clearSearch() } Kube.TextField { id: find Layout.fillWidth: true placeholderText: qsTr("Search...") onTextChanged: mailListView.filter = text focus: true Keys.onEscapePressed: filterField.clearSearch() } } } Kube.MailListView { id: mailListView showFilter: false Layout.fillWidth: true Layout.fillHeight: true } } Kube.ConversationView { id: mailView objectName: "mailView" Layout.fillWidth: true Layout.fillHeight: parent.height activeFocusOnTab: true mail: mailListView.currentMail } } } diff --git a/views/todo/qml/View.qml b/views/todo/qml/View.qml index bf7b7dd6..ca2bacc1 100644 --- a/views/todo/qml/View.qml +++ b/views/todo/qml/View.qml @@ -1,99 +1,99 @@ /* * Copyright (C) 2017 Christian Mollekopf, * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Layouts 1.2 import org.kube.framework 1.0 as Kube FocusScope { id: root RowLayout { anchors.fill: parent spacing: 0 Rectangle { width: Kube.Units.gridUnit * 10 Layout.fillHeight: parent.height - color: Kube.Colors.textColor + color: Kube.Colors.darkBackgroundColor Kube.PositiveButton { id: newTaskButton objectName: "newTaskButton" anchors { top: parent.top left: parent.left right: parent.right margins: Kube.Units.largeSpacing } focus: true text: qsTr("New Task") onClicked: {} } } Rectangle { Layout.fillWidth: true Layout.fillHeight: true color: Kube.Colors.backgroundColor Kube.ListView { anchors.fill: parent model: 5 delegate: Kube.ListDelegate { Kube.Label { anchors { verticalCenter: parent.verticalCenter left: parent.left leftMargin: Kube.Units.largeSpacing } text: "tilte" } Row { anchors { verticalCenter: parent.verticalCenter right: parent.right rightMargin: Kube.Units.largeSpacing } Kube.IconButton { iconName: Kube.Icons.listRemove } } } } } } }