Continue development of Qt Quick GUI

* Add view (written in QML, based on Qt Quick Controls 2
  and Kirigami 2)
* Add controller (written in C++)
* Use existing models (written in C++)
This commit is contained in:
Marius Kittler 2018-05-20 01:54:08 +02:00
parent 22fb061686
commit bea4533133
30 changed files with 684 additions and 1069 deletions

View File

@ -61,12 +61,11 @@ set(WIDGETS_UI_FILES
)
set(QML_HEADER_FILES
quickgui/applicationinfo.h
quickgui/applicationpaths.h
quickgui/controller.h
quickgui/initiatequick.h
)
set(QML_SRC_FILES
quickgui/applicationinfo.cpp
quickgui/controller.cpp
quickgui/initiatequick.cpp
resources/icons.qrc
resources/qml.qrc

12
qml/BasicDialog.qml Normal file
View File

@ -0,0 +1,12 @@
import QtQuick 2.7
import QtQuick.Controls 2.1 as Controls
import org.kde.kirigami 2.4 as Kirigami
Controls.Dialog {
modal: true
focus: true
parent: applicationWindow().overlay
x: (parent.width - width) / 2
y: (parent.height - height) / 2
width: Math.min(parent.width, Kirigami.Units.gridUnit * 30)
}

146
qml/EntriesPage.qml Normal file
View File

@ -0,0 +1,146 @@
import QtQuick 2.4
import QtQuick.Layouts 1.2
import QtQml.Models 2.2
import QtQuick.Controls 2.0 as Controls
import org.kde.kirigami 2.4 as Kirigami
Kirigami.ScrollablePage {
id: page
property alias model: delegateModel.model
property alias rootIndex: delegateModel.rootIndex
Layout.fillWidth: true
title: "?"
actions {
main: Kirigami.Action {
iconName: "list-add"
text: qsTr("Add account")
onTriggered: {
model.setInsertTypeToAccount()
model.insertRows(model.rowCount(rootIndex), 1, rootIndex)
}
}
left: Kirigami.Action {
iconName: "edit-paste"
text: qsTr("Paste account")
onTriggered: {
// TODO
}
}
right: Kirigami.Action {
iconName: "folder-add"
text: qsTr("Add category")
onTriggered: {
model.setInsertTypeToNode()
model.insertRows(model.rowCount(rootIndex), 1, rootIndex)
}
}
}
onBackRequested: {
if (fieldsSheet.sheetOpen) {
event.accepted = true
fieldsSheet.close()
}
}
background: Rectangle {
color: Kirigami.Theme.backgroundColor
}
// "sheet" to display field model
Kirigami.OverlaySheet {
id: fieldsSheet
parent: applicationWindow().overlay
header: Kirigami.Heading {
text: qsTr("Edit account ") + nativeInterface.currentAccountName
}
ListView {
id: fieldsListView
implicitWidth: Kirigami.Units.gridUnit * 30
model: nativeInterface.fieldModel
delegate: RowLayout {
Controls.TextField {
text: key ? key : ""
onEditingFinished: fieldsListView.model.setData(
fieldsListView.model.index(index,
0), text)
}
Controls.TextField {
text: value ? value : ""
echoMode: isPassword ? TextInput.PasswordEchoOnEdit : TextInput.Normal
onEditingFinished: fieldsListView.model.setData(
fieldsListView.model.index(index,
1), text)
}
}
}
}
// list view to display one hierarchy level of entry model
ListView {
id: listView
model: DelegateModel {
id: delegateModel
function isNode(rowNumber) {
return model.isNode(model.index(rowNumber, 0, rootIndex))
}
function handleEntryClicked(rowNumber, entryName) {
var modelIndex = model.index(rowNumber, 0, rootIndex)
if (model.isNode(modelIndex)) {
root.pushStackEntry(model, modelIndex)
} else {
nativeInterface.currentAccountIndex = modelIndex
fieldsSheet.open()
}
}
delegate: Kirigami.SwipeListItem {
id: listItem
contentItem: RowLayout {
Kirigami.Icon {
width: Kirigami.Units.iconSizes.smallMedium
height: Kirigami.Units.iconSizes.smallMedium
Layout.fillHeight: true
source: delegateModel.isNode(
index) ? "folder-symbolic" : "story-editor"
}
Controls.Label {
Layout.fillWidth: true
Layout.fillHeight: true
height: Math.max(implicitHeight,
Kirigami.Units.iconSizes.smallMedium)
anchors.verticalCenter: parent.verticalCenter
text: name
MouseArea {
anchors.fill: parent
onClicked: delegateModel.handleEntryClicked(index,
name)
}
}
}
actions: [
Kirigami.Action {
iconName: "edit-cut"
text: qsTr("Cut")
onTriggered: showPassiveNotification(text + " " + name)
},
Kirigami.Action {
iconName: "edit-delete"
text: qsTr("Delete")
onTriggered: showPassiveNotification(text + " " + name)
},
Kirigami.Action {
iconName: "edit-rename"
text: qsTr("Rename")
onTriggered: showPassiveNotification(text + " " + name)
}
]
}
}
}
}

89
qml/PasswordDialog.qml Normal file
View File

@ -0,0 +1,89 @@
import QtQuick 2.7
import QtQuick.Controls 2.1 as Controls
import QtQuick.Layouts 1.2
import org.kde.kirigami 2.4 as Kirigami
BasicDialog {
id: passwordDialog
property alias instruction: instructionLabel.text
property alias password: passwordTextField.text
property bool newPassword: false
readonly property bool canAccept: !newPassword
|| showCharactersCheckBox.checked
|| passwordTextField.text === repeatPasswordTextField.text
standardButtons: canAccept ? Controls.Dialog.Ok
| Controls.Dialog.Cancel : Controls.Dialog.Cancel
title: qsTr("Enter password")
ColumnLayout {
Controls.Label {
id: instructionLabel
Layout.preferredWidth: passwordDialog.availableWidth
wrapMode: Controls.Label.Wrap
}
Controls.TextField {
id: passwordTextField
Layout.preferredWidth: passwordDialog.availableWidth
echoMode: showCharactersCheckBox.checked ? TextInput.Normal : TextInput.Password
placeholderText: qsTr("enter password here, leave empty for no encryption")
background: Rectangle {
border.color: "#5d5e6d"
}
}
Controls.TextField {
id: repeatPasswordTextField
Layout.preferredWidth: passwordDialog.availableWidth
visible: passwordDialog.newPassword
&& !showCharactersCheckBox.checked
echoMode: TextInput.Password
placeholderText: qsTr("repeat password")
background: Rectangle {
border.color: passwordDialog.canAccept ? "#089900" : "#ff0000"
}
}
Controls.CheckBox {
id: showCharactersCheckBox
text: qsTr("Show characters")
checked: false
}
}
onAccepted: {
nativeInterface.password = password
if (newPassword) {
showPassiveNotification(
qsTr("The new password will be used when saving next time."))
} else {
nativeInterface.load()
}
}
onRejected: {
if (newPassword) {
showPassiveNotification(
qsTr("You aborted. The password has not been altered."))
}
}
function clear() {
passwordTextField.text = ""
repeatPasswordTextField.text = ""
}
function askForPassword(instruction, newPassword) {
this.newPassword = newPassword
this.instruction = instruction
this.clear()
this.open()
}
function askForExistingPassword(instruction) {
this.askForPassword(instruction, false)
}
function askForNewPassword(instruction) {
this.askForPassword(instruction, true)
}
}

BIN
qml/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

View File

@ -1,176 +1,154 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import martchus.passwordmanager 2.0
import QtQuick 2.7
import QtQuick.Controls 2.1 as Controls
import QtQuick.Layouts 1.2
import QtQuick.Dialogs 1.3
import org.kde.kirigami 2.4 as Kirigami
import "./pages" as Pages
import "./touch" as Touch
ApplicationWindow {
Kirigami.ApplicationWindow {
id: root
width: 700
height: 800
title: qsTr("Password Manager")
visible: true
property string statusBarMessage
property Component startPage: Pages.StartPage {
onUpdateStatusBar: statusBarMessage = message
onNextPage: if (!isLocked) {
pageView.push(accountsPage)
clearSearchBox()
}
function clearStack() {
pageStack.pop(root.pageStack.initialPage, Controls.StackView.Immediate)
}
property Component accountsPage: Pages.AccountsPage {
onUpdateStatusBar: statusBarMessage = message
onNextPage: if (!isLocked) {
pageView.push(fieldsPage)
}
onPreviousPage: {
pageView.pop()
function pushStackEntry(entryModel, rootIndex) {
var title = entryModel.data(rootIndex)
var entriesComponent = Qt.createComponent("EntriesPage.qml")
if (entriesComponent.status !== Component.Ready) {
var errorMessage = "Unable to load EntriesPage.qml: " + entriesComponent.errorString()
showPassiveNotification(errorMessage)
console.error(errorMessage)
return
}
var entriesPage = entriesComponent.createObject(root, {
model: entryModel,
rootIndex: rootIndex,
title: title
})
pageStack.push(entriesPage)
}
property Component fieldsPage: Pages.FieldsPage {
onUpdateStatusBar: statusBarMessage = message
onNextPage: if (!isLocked) {
pageView.pop()
}
onPreviousPage: {
pageView.pop()
PasswordDialog {
id: enterPasswordDialog
}
FileDialog {
id: fileDialog
title: selectExisting ? qsTr("Select an existing file") : qsTr(
"Select path for new file")
onAccepted: {
if (fileUrls.length < 1) {
return
}
nativeInterface.filePath = fileUrls[0]
if (selectExisting) {
nativeInterface.load()
} else {
nativeInterface.create()
}
}
onRejected: {
showPassiveNotification("Canceled file selection")
}
function openExisting() {
this.selectExisting = true
this.open()
}
function createNew() {
this.selectExisting = false
this.open()
}
}
StackView {
id: pageView
anchors.fill: parent
focus: true
Keys.onReleased: {
if (event.key === Qt.Key_Back ||
(event.key === Qt.Key_Left && (event.modifiers & Qt.AltModifier))) {
if (pageView.depth > 1) {
event.accepted = true
if (!currentItem.isLocked)
currentItem.previousPage()
} else {
if (!currentItem.hasNoSearchText) {
event.accepted = true
currentItem.clearSearchBox()
Connections {
target: nativeInterface
onFileError: {
showPassiveNotification(errorMessage)
}
onPasswordRequired: {
enterPasswordDialog.askForExistingPassword(
qsTr("Password required to open ") + filePath)
leftMenu.resetMenu()
}
onFileOpenChanged: {
clearStack()
if (!fileOpen) {
return
}
var entryModel = nativeInterface.entryModel
var rootIndex = entryModel.index(0, 0)
pushStackEntry(entryModel, rootIndex)
}
}
header: Kirigami.ApplicationHeader {
}
globalDrawer: Kirigami.GlobalDrawer {
id: leftMenu
title: qsTr("Password manager")
titleIcon: "passwordmanager"
bannerImageSource: "banner.png"
actions: [
Kirigami.Action {
text: qsTr("Create new file")
iconName: "document-new"
onTriggered: fileDialog.createNew()
},
Kirigami.Action {
text: qsTr("Open existing file")
iconName: "document-open"
onTriggered: fileDialog.openExisting()
},
Kirigami.Action {
text: "Save modifications"
enabled: nativeInterface.fileOpen
iconName: "document-save"
onTriggered: nativeInterface.save()
},
Kirigami.Action {
text: "Change password"
enabled: nativeInterface.fileOpen
iconName: "dialog-password"
onTriggered: enterPasswordDialog.askForNewPassword(
"Change password for " + nativeInterface.filePath)
},
Kirigami.Action {
text: "Close file"
enabled: nativeInterface.fileOpen
iconName: "document-close"
onTriggered: nativeInterface.close()
}
]
}
contextDrawer: Kirigami.ContextDrawer {
id: contextDrawer
}
pageStack.initialPage: mainPageComponent
// main app content
Component {
id: mainPageComponent
RowLayout {
spacing: 5
Controls.Label {
text: {
if (nativeInterface.fileOpen) {
return qsTr("The file %1 has been opened.").arg(
nativeInterface.filePath)
} else {
return qsTr("No file has been opened.")
}
}
}
}
initialItem: startPage
delegate: StackViewDelegate {
pushTransition: StackViewTransition {
function transitionFinished(properties) {
properties.exitItem.opacity = 1
}
PropertyAnimation {
target: enterItem
property: "x"
from: target.width
to: 0
duration: 500
easing.type: Easing.OutSine
}
PropertyAnimation {
target: exitItem
property: "x"
from: 0
to: -target.width
duration: 500
easing.type: Easing.OutSine
}
}
popTransition: StackViewTransition {
function transitionFinished(properties)
{
properties.exitItem.opacity = 1
}
PropertyAnimation {
target: enterItem
property: "x"
from: -target.width
to: 0
duration: 500
easing.type: Easing.OutSine
}
PropertyAnimation {
target: exitItem
property: "x"
from: 0
to: target.width
duration: 500
easing.type: Easing.OutSine
}
}
property Component replaceTransition: pushTransition
}
}
statusBar: StatusBar {
id: statusbar
width: parent.width
opacity: label.text !== "" ? 1 : 0
property real statusBarHeight: 65 * ApplicationInfo.ratio
height: label.text !== "" ? statusBarHeight : 0
Behavior on height { NumberAnimation {easing.type: Easing.OutSine}}
Behavior on opacity { NumberAnimation {}}
style: StatusBarStyle {
padding { left: 0; right: 0 ; top: 0 ; bottom: 0}
property Component background: Rectangle {
implicitHeight: 65 * ApplicationInfo.ratio
implicitWidth: root.width
color: ApplicationInfo.colors.smokeGray
Rectangle {
width: parent.width
height: 1
color: Qt.darker(parent.color, 1.5)
}
Rectangle {
y: 1
width: parent.width
height: 1
color: "white"
}
}
}
Touch.TouchLabel {
id: label
y: 32 * ApplicationInfo.ratio - height / 2
width: parent.width // The text will only wrap if an explicit width has been set
text: statusBarMessage
textFormat: Text.RichText
onLinkActivated: Qt.openUrlExternally(link)
wrapMode: Text.Wrap
pixelSize: 18
letterSpacing: -0.15
color: ApplicationInfo.colors.mediumGray
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
function decreaseFontSizeOnNarrowScreen() {
if (label.implicitHeight > statusbar.statusBarHeight) {
pixelSize = Math.floor(pixelSize * statusbar.statusBarHeight / label.implicitHeight)
}
}
onTextChanged: {
if (text === "") {
pixelSize = 18
} else {
decreaseFontSizeOnNarrowScreen()
}
}
onWidthChanged: decreaseFontSizeOnNarrowScreen()
}
}
menuBar: MenuBar {
Menu {
title: qsTr("Application")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
Component.onCompleted: {
// load file if one has been specified via CLI argument
if (nativeInterface.filePath.length) {
nativeInterface.load()
}
}
}

View File

@ -1,13 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import martchus.passwordmanager 2.0
BasicPage {
id: accountsPage
title1: qsTr("Accounts")
pageComponent: Item {
}
}

View File

@ -1,182 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Layouts 1.1
import martchus.passwordmanager 2.0
import "../touch" as Touch
Item {
id: page
signal updateStatusBar(string message)
signal nextPage
signal previousPage
signal clearSearchBox
property Component pageComponent
property bool isLocked: Stack.status !== Stack.Active
property string title1
property string title2
property string title3
property alias searchText: searchField.text
property alias hasNoSearchText: searchField.isEmpty
signal searchBoxReturn
property string statusBarMessageDefault
property alias topRect: topRect
property color topRectColor: ApplicationInfo.colors.yetAnotherBlue
property bool searchFieldVisisble: false
Binding {
target: ApplicationInfo
property: "isPortraitMode"
value: page.height > page.width
when: !ApplicationInfo.isMobile
}
Binding {
target: ApplicationInfo
property: "applicationWidth"
value: page.width
}
Rectangle {
id: topRect
z: 2 // so flickable doesn't draw on top
anchors.top: parent.top
height: 80 * ApplicationInfo.ratio
width: parent.width
color: page.Stack.index !== 0 && mouseBack.pressed ?
Qt.lighter(topRectColor, 1.2) : topRectColor
Rectangle {
color: Qt.lighter(parent.color, 1.2)
height: 1
anchors.bottom: parent.bottom
anchors.bottomMargin: 1
width: parent.width
}
Rectangle {
z: 2 // so flickable doesn't draw on top
height: 1
width: parent.width
color: Qt.darker(ApplicationInfo.colors.blue, 1.6)
anchors.bottom: parent.bottom
}
RowLayout {
id: titleRow
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
anchors.verticalCenter: parent.verticalCenter
Separator {
Layout.fillWidth: false
Layout.preferredWidth: ApplicationInfo.hMargin
}
Image {
source: ApplicationInfo.imagePath("backarrow.png")
Layout.preferredWidth: 22 * ApplicationInfo.ratio
Layout.preferredHeight: 35 * ApplicationInfo.ratio
visible: page.Stack.index > 0
Accessible.role: Accessible.Button
Accessible.name: qsTr("Back")
function accessiblePressAction () { backPressed() }
}
Rectangle {
opacity: 0
Layout.preferredWidth: 20 * ApplicationInfo.ratio
Layout.fillHeight: true
visible: page.Stack.index > 0
}
Touch.TouchLabel {
id: t1
text: title1 + " "
color: ApplicationInfo.colors.white
pixelSize: 30
font.weight: Font.Bold
Layout.maximumWidth: ApplicationInfo.applicationWidth - t3.implicitWidth - 2 * ApplicationInfo.hMargin - 5 * ApplicationInfo.ratio - 42 * ApplicationInfo.ratio
Layout.alignment: Qt.AlignBaseline
}
Touch.TouchLabel {
text: "- " + title2
color: ApplicationInfo.colors.white
visible: title2 !== ""
pixelSize: 22
letterSpacing: -0.15
Layout.alignment: Qt.AlignBaseline
Layout.maximumWidth: freeSpace > implicitWidth ? freeSpace : 0
property real freeSpace: ApplicationInfo.applicationWidth - t1.width - t3.implicitWidth - 2 * ApplicationInfo.hMargin - 5 * ApplicationInfo.ratio - 42 * ApplicationInfo.ratio
}
Item {
Layout.fillWidth: true
height: 0
}
Touch.TouchLabel {
id: t3
text: title3
color: ApplicationInfo.colors.white
visible: title3 !== ""
pixelSize: 22
letterSpacing: -0.15
Layout.alignment: Qt.AlignBaseline
}
Separator {
Layout.fillWidth: false
Layout.preferredWidth: ApplicationInfo.hMargin
}
}
Rectangle {
width: parent.width
height: 5
anchors.top: parent.bottom
gradient: Gradient {
GradientStop {position: 0 ; color: "#40000000"}
GradientStop {position: 1 ; color: "#00000000"}
}
}
MouseArea {
id: mouseBack
anchors.fill: parent
onClicked: backPressed()
}
}
function backPressed() {
if (!isLocked) page.previousPage()
}
Touch.TouchTextField {
id: searchField
z: 2
visible: searchFieldVisisble
anchors.right: topRect.right
anchors.top: topRect.top
anchors.bottom: topRect.bottom
width: ApplicationInfo.isPortraitMode ?
parent.width - t1.implicitWidth - ApplicationInfo.ratio * 50 :
parent.width/2.5
anchors.leftMargin: topRect.width/2
anchors.rightMargin: 20 * ApplicationInfo.ratio
anchors.margins: 12 * ApplicationInfo.ratio
placeholderText: qsTr("filter")
Layout.fillWidth: true
Keys.onReturnPressed: page.searchBoxReturn()
Keys.onEnterPressed: page.searchBoxReturn()
onClearButtonClicked: page.clearSearchBox()
}
Loader {
sourceComponent: pageComponent
anchors.top: topRect.bottom
anchors.bottom: parent.bottom
width: parent.width
Rectangle {
z: -1
anchors.fill: parent
color: ApplicationInfo.colors.white
}
}
}

View File

@ -1,14 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import martchus.passwordmanager 2.0
BasicPage {
id : fieldsPage
title1: ApplicationInfo.currentAccountName
title3: qsTr("Fields")
pageComponent: Item {
}
}

View File

@ -1,12 +0,0 @@
import QtQuick 2.1
import QtQuick.Layouts 1.0
import martchus.passwordmanager 2.0
Item {
implicitHeight: ApplicationInfo.hMargin
implicitWidth: ApplicationInfo.hMargin
Layout.minimumHeight: 0
Layout.minimumWidth: 0
Layout.fillHeight: true
Layout.fillWidth: true
}

View File

@ -1,66 +0,0 @@
import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.2
import martchus.passwordmanager 2.0
import "../touch" as Touch
BasicPage {
id: startPage
title1: qsTr("Password Manager")
searchFieldVisisble: true
FileDialog {
id: fileDialog
title: qsTr("Select a password file")
selectExisting: true
onAccepted: {
ApplicationInfo.currentFile = fileUrl
nextPage()
}
}
ColumnLayout {
anchors.top: topRect.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 5
Touch.TouchButton {
text: qsTr("Create a new password file")
Layout.fillWidth: true
}
Touch.TouchButton {
text: qsTr("Open an existing password file")
onClicked: {
ApplicationInfo.currentFile = "./test"
nextPage() // fileDialog.visible = true
}
Layout.fillWidth: true
}
Touch.TouchLabel {
text: qsTr("Recently opened files")
}
Touch.TouchLabel {
text: qsTr("Test 1")
//Layout.fillWidth: true
color: ApplicationInfo.colors.lightGray
}
Touch.TouchLabel {
text: qsTr("Test 2")
//Layout.fillWidth: true
color: ApplicationInfo.colors.lightGray
}
Touch.TouchLabel {
text: qsTr("Test 3")
//Layout.fillWidth: true
color: ApplicationInfo.colors.lightGray
}
}
}

View File

@ -1,52 +0,0 @@
import QtQuick 2.1
import QtQuick.Layouts 1.0
import martchus.passwordmanager 2.0
Rectangle {
id: rect
height: ApplicationInfo.constants.rowDelegateHeight
width: parent.width
signal clicked
signal deleteEntry
color: mouseNext.pressed ? ApplicationInfo.colors.smokeGray : ApplicationInfo.colors.white
GridLayout {
id: _grid
anchors.fill: parent
flow: Qt.LeftToRight
rowSpacing: 4 * ApplicationInfo.ratio
columnSpacing: 0
columns: 2
Rectangle {
Layout.preferredWidth: ApplicationInfo.hMargin
Layout.fillHeight: true
opacity: 0
}
Loader {
// sourceComponent:
Layout.fillHeight: true
Layout.fillWidth: true
}
Rectangle {
id: separator
Layout.fillWidth: true
Layout.fillHeight: true
Layout.columnSpan: 2
}
}
Rectangle {
z: 1
height: 1
anchors.bottom: parent.bottom
width: parent.width
color: ApplicationInfo.colors.paleGray
}
MouseArea {
id: mouseNext
anchors.left: parent.left
width: parent.width - 80 * ApplicationInfo.ratio - ApplicationInfo.hMargin
height: parent.height
onClicked: rect.clicked()
}
}

View File

@ -1,43 +0,0 @@
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.0
import martchus.passwordmanager 2.0
Button {
id: button
property int pixelSize: 34
property real letterSpacing: -0.25
property string text: ""
style: ButtonStyle {
label: Label {
id: label
font.family: "Open Sans"
font.pixelSize: pixelSize * ApplicationInfo.ratio * 1.1 // increasing fonts
font.letterSpacing: letterSpacing * ApplicationInfo.ratio
color: ApplicationInfo.colors.doubleDarkGray
verticalAlignment: Text.AlignBottom
horizontalAlignment: Text.AlignLeft
elide: Text.ElideRight
linkColor: ApplicationInfo.colors.blue
renderType: ApplicationInfo.isMobile ? Text.QtRendering : Text.NativeRendering
text: button.text
Text {
id: text
visible: false
font.family: label.font.family
font.pixelSize: label.font.pixelSize
font.letterSpacing: label.font.letterSpacing
wrapMode: label.wrapMode
elide: label.elide
text: label.text
}
}
}
property int maximumWidth: (ApplicationInfo.constants.isMobile ? ApplicationInfo.applicationWidth : 1120) / 4
Layout.minimumWidth: Math.min(Layout.maximumWidth, implicitWidth + 1)
}

View File

@ -1,35 +0,0 @@
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0
import martchus.passwordmanager 2.0
Label {
id: label
property int pixelSize: 34
property real letterSpacing: -0.25
font.family: "Open Sans"
font.pixelSize: pixelSize * ApplicationInfo.ratio * 1.1 // increasing fonts
font.letterSpacing: letterSpacing * ApplicationInfo.ratio
color: ApplicationInfo.colors.doubleDarkGray
verticalAlignment: Text.AlignBottom
horizontalAlignment: Text.AlignLeft
elide: Text.ElideRight
linkColor: ApplicationInfo.colors.blue
renderType: ApplicationInfo.isMobile ? Text.QtRendering : Text.NativeRendering
function expectedTextWidth(value)
{
text.text = value
return text.width
}
property int maximumWidth: (ApplicationInfo.constants.isMobile ? ApplicationInfo.applicationWidth : 1120) / 4
Layout.minimumWidth: Math.min(Layout.maximumWidth, implicitWidth + 1)
Text {
id: text
visible: false
font.family: label.font.family
font.pixelSize: label.font.pixelSize
font.letterSpacing: label.font.letterSpacing
wrapMode: label.wrapMode
elide: label.elide
}
}

View File

@ -1,18 +0,0 @@
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.0
import martchus.passwordmanager 2.0
ScrollView {
frameVisible: false
style: ScrollViewStyle {
property int handleWidth: 20 * ApplicationInfo.ratio
transientScrollBars: true
padding{ top: 4 ; bottom: 4 ; right: 4}
property bool hovered: false
}
Rectangle {
anchors.fill: parent
color: ApplicationInfo.colors.white
}
}

View File

@ -1,42 +0,0 @@
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.0
import martchus.passwordmanager 2.0
Slider {
id: slider
property real sliderHandleHeight: 0.
property real sliderHandleWidth: 0.
implicitHeight: sliderHandleHeight + ApplicationInfo.ratio * 25
style: SliderStyle {
groove: Rectangle {
Rectangle {
id: beforeHandle
width: styleData.handlePosition
height: 20 * ApplicationInfo.ratio
color: ApplicationInfo.colors.blue
radius: 90
z: -1
}
Rectangle {
id: afterHandle
anchors.left: beforeHandle.right
anchors.right: parent.right
height: 20 * ApplicationInfo.ratio
color: ApplicationInfo.colors.darkGray
radius: 90
z: -1
}
}
handle: Item {
width: sliderHandleWidth
height: sliderHandleHeight
Image {
anchors.centerIn: parent
source: ApplicationInfo.imagePath(control.pressed ? "Pointer_pressed.png" : "Pointer.png")
width: sliderHandleWidth + 16 * ApplicationInfo.ratio
height: sliderHandleHeight + 16 * ApplicationInfo.ratio
}
}
}
}

View File

@ -1,75 +0,0 @@
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.0
import martchus.passwordmanager 2.0
TextField {
id: textfield
signal clearButtonClicked
implicitWidth: parent.width
property bool isEmpty: true
style: TextFieldStyle {
renderType: ApplicationInfo.isMobile ? Text.QtRendering : Text.NativeRendering
background: Rectangle {
radius: 8
border.width: 1
border.color: Qt.darker(ApplicationInfo.colors.blue, 1.6)
color: ApplicationInfo.colors.white
gradient: Gradient {
GradientStop { position: 0 ; color: "#ddd"}
GradientStop { position: 0.05 ; color: "#fff"}
}
implicitHeight: 60 * ApplicationInfo.ratio
opacity: 1
}
padding.left : (12 + 50) * ApplicationInfo.ratio
padding.right: (12 + 50) * ApplicationInfo.ratio
font.pixelSize: 28 * ApplicationInfo.ratio
font.family: "Open Sans"
font.letterSpacing: -0.25 * ApplicationInfo.ratio
selectedTextColor : ApplicationInfo.colors.lightGray
selectionColor : ApplicationInfo.colors.darkBlue
textColor : ApplicationInfo.colors.mediumGray
}
onClearButtonClicked: text = ""
Item {
id: item
anchors.left: parent.left
anchors.top: parent.top
height: parent.height
width: parent.height
Image {
opacity: 0.9
anchors.centerIn: item
height: iconSize
width: iconSize
source: ApplicationInfo.imagePath("magnifier.png")
property int iconSize: 50 * ApplicationInfo.ratio
}
}
onTextChanged: isEmpty = (text === "")
inputMethodHints: Qt.ImhNoPredictiveText
MouseArea {
z: 2
opacity: !textfield.isEmpty ? 1 : 0
Behavior on opacity {NumberAnimation{}}
anchors.right: parent.right
anchors.rightMargin: 4 * ApplicationInfo.ratio
anchors.top: parent.top
height: parent.height
width: parent.height
Image {
anchors.centerIn: parent
source: ApplicationInfo.imagePath("clear.png")
property int iconSize: 40 * ApplicationInfo.ratio
opacity: parent.pressed ? 1 : 0.9
width: iconSize
height: iconSize
}
onClicked: textfield.clearButtonClicked()
}
}

View File

@ -1,93 +0,0 @@
#include "./applicationinfo.h"
#include <qmath.h>
#include <QDebug>
#include <QFile>
#include <QGuiApplication>
#include <QRegExp>
#include <QScreen>
#include <QUrl>
#include <QUrlQuery>
using namespace Io;
namespace QtGui {
ApplicationInfo::ApplicationInfo()
{
m_colors = new QQmlPropertyMap(this);
m_colors->insert(QLatin1String("white"), QVariant("#ffffff"));
m_colors->insert(QLatin1String("smokeGray"), QVariant("#eeeeee"));
m_colors->insert(QLatin1String("paleGray"), QVariant("#d7d6d5"));
m_colors->insert(QLatin1String("lightGray"), QVariant("#aeadac"));
m_colors->insert(QLatin1String("darkGray"), QVariant("#35322f"));
m_colors->insert(QLatin1String("mediumGray"), QVariant("#5d5b59"));
m_colors->insert(QLatin1String("doubleDarkGray"), QVariant("#1e1b18"));
m_colors->insert(QLatin1String("blue"), QVariant("#14aaff"));
m_colors->insert(QLatin1String("yetAnotherBlue"), QVariant("#428bca"));
m_colors->insert(QLatin1String("darkBlue"), QVariant("#14148c"));
m_colors->insert(QLatin1String("darkYellow"), QVariant("#dfdc00"));
m_colors->insert(QLatin1String("darkYellow"), QVariant("#eb881c"));
m_colors->insert(QLatin1String("almostBlack"), QVariant("#222222"));
m_constants = new QQmlPropertyMap(this);
m_constants->insert(QLatin1String("isMobile"), QVariant(isMobile()));
QRect rect = QGuiApplication::primaryScreen()->geometry();
m_ratio = isMobile() ? qMin(qMax(rect.width(), rect.height()) / 1136., qMin(rect.width(), rect.height()) / 640.) : .5;
m_sliderHandleWidth = sizeWithRatio(70);
m_sliderHandleHeight = sizeWithRatio(87);
m_sliderGapWidth = sizeWithRatio(100);
m_isPortraitMode = isMobile() ? rect.height() > rect.width() : false;
m_hMargin = m_isPortraitMode ? 20 * ratio() : 50 * ratio();
m_applicationWidth = isMobile() ? rect.width() : 1120;
m_constants->insert(QLatin1String("rowDelegateHeight"), QVariant(sizeWithRatio(118)));
m_fieldModel = new FieldModel(this);
if (isMobile()) {
connect(QGuiApplication::primaryScreen(), &QScreen::orientationChanged, this, &ApplicationInfo::notifyPortraitMode);
}
}
void ApplicationInfo::setApplicationWidth(const int newWidth)
{
if (newWidth != m_applicationWidth) {
m_applicationWidth = newWidth;
emit applicationWidthChanged();
}
}
QString ApplicationInfo::imagePath(const QString image)
{
return QStringLiteral("qrc:/qml/images/%1").arg(image);
}
void ApplicationInfo::notifyPortraitMode(Qt::ScreenOrientation orientation)
{
switch (orientation) {
case Qt::LandscapeOrientation:
case Qt::InvertedLandscapeOrientation:
setIsPortraitMode(false);
break;
case Qt::PortraitOrientation:
case Qt::InvertedPortraitOrientation:
setIsPortraitMode(true);
break;
default:
break;
}
}
void ApplicationInfo::setIsPortraitMode(const bool newMode)
{
if (m_isPortraitMode != newMode) {
m_isPortraitMode = newMode;
m_hMargin = m_isPortraitMode ? 20 * ratio() : 50 * ratio();
emit portraitModeChanged();
emit hMarginChanged();
}
}
} // namespace QtGui

View File

@ -1,176 +0,0 @@
#ifndef APPLICATIONINFO_H
#define APPLICATIONINFO_H
#include "../model/fieldmodel.h"
#include <QObject>
#include <QQmlPropertyMap>
namespace QtGui {
class ApplicationInfo : public QObject {
Q_OBJECT
Q_PROPERTY(int applicationWidth READ applicationWidth WRITE setApplicationWidth NOTIFY applicationWidthChanged)
Q_PROPERTY(bool isMobile READ isMobile CONSTANT)
Q_PROPERTY(QObject *colors READ colors CONSTANT)
Q_PROPERTY(QObject *constants READ constants CONSTANT)
Q_PROPERTY(bool isPortraitMode READ isPortraitMode WRITE setIsPortraitMode NOTIFY portraitModeChanged)
Q_PROPERTY(const QString &currenfFile READ currentFile WRITE setCurrentFile NOTIFY currentFileChanged)
Q_PROPERTY(FieldModel *fieldModel READ fieldModel)
Q_PROPERTY(Io::AccountEntry *currentAccountEntry READ currentAccountEntry WRITE setCurrentAccountEntry)
Q_PROPERTY(QString currentAccountName READ currentAccountName)
Q_PROPERTY(qreal ratio READ ratio CONSTANT)
Q_PROPERTY(qreal hMargin READ hMargin NOTIFY hMarginChanged)
Q_PROPERTY(qreal sliderHandleWidth READ sliderHandleWidth CONSTANT)
Q_PROPERTY(qreal sliderHandleHeight READ sliderHandleHeight CONSTANT)
Q_PROPERTY(qreal sliderGapWidth READ sliderGapWidth CONSTANT)
public:
ApplicationInfo();
static constexpr bool isMobile();
QQmlPropertyMap *colors() const;
QQmlPropertyMap *constants() const;
int applicationWidth() const;
void setApplicationWidth(const int newWidth);
bool isPortraitMode() const;
void setIsPortraitMode(const bool newMode);
const QString &currentFile() const;
void setCurrentFile(const QString &currentFile);
FieldModel *fieldModel();
Io::AccountEntry *currentAccountEntry();
QString currentAccountName() const;
void setCurrentAccountEntry(Io::AccountEntry *entry);
qreal hMargin() const;
qreal ratio() const;
qreal sliderHandleHeight();
qreal sliderGapWidth();
qreal sliderHandleWidth();
Q_INVOKABLE QString imagePath(const QString image);
protected Q_SLOTS:
void notifyPortraitMode(Qt::ScreenOrientation);
protected:
qreal sizeWithRatio(const qreal height);
Q_SIGNALS:
void currentFileChanged();
void applicationWidthChanged();
void portraitModeChanged();
void hMarginChanged();
private:
int m_applicationWidth;
QQmlPropertyMap *m_colors;
QQmlPropertyMap *m_constants;
bool m_isPortraitMode;
QString m_currentFile;
FieldModel *m_fieldModel;
qreal m_ratio;
qreal m_hMargin;
qreal m_sliderHandleHeight, m_sliderHandleWidth, m_sliderGapWidth;
};
constexpr bool ApplicationInfo::isMobile()
{
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_BLACKBERRY)
return true;
#else
return false;
#endif
}
inline QQmlPropertyMap *ApplicationInfo::colors() const
{
return m_colors;
}
inline QQmlPropertyMap *ApplicationInfo::constants() const
{
return m_constants;
}
inline int ApplicationInfo::applicationWidth() const
{
return m_applicationWidth;
}
inline bool ApplicationInfo::isPortraitMode() const
{
return m_isPortraitMode;
}
inline const QString &ApplicationInfo::currentFile() const
{
return m_currentFile;
}
inline void ApplicationInfo::setCurrentFile(const QString &currentFile)
{
if (m_currentFile != currentFile) {
m_currentFile = currentFile;
emit currentFileChanged();
}
}
inline FieldModel *ApplicationInfo::fieldModel()
{
return m_fieldModel;
}
inline Io::AccountEntry *ApplicationInfo::currentAccountEntry()
{
return m_fieldModel->accountEntry();
}
inline QString ApplicationInfo::currentAccountName() const
{
if (m_fieldModel->accountEntry()) {
return QString::fromStdString(m_fieldModel->accountEntry()->label());
}
return QString();
}
inline void ApplicationInfo::setCurrentAccountEntry(Io::AccountEntry *entry)
{
m_fieldModel->setAccountEntry(entry);
}
inline qreal ApplicationInfo::hMargin() const
{
return m_hMargin;
}
inline qreal ApplicationInfo::ratio() const
{
return m_ratio;
}
inline qreal ApplicationInfo::sliderHandleHeight()
{
return m_sliderHandleHeight;
}
inline qreal ApplicationInfo::sliderGapWidth()
{
return m_sliderGapWidth;
}
inline qreal ApplicationInfo::sliderHandleWidth()
{
return m_sliderHandleWidth;
}
inline qreal ApplicationInfo::sizeWithRatio(const qreal height)
{
return ratio() * height;
}
} // namespace QtGui
#endif // APPLICATIONINFO_H

View File

@ -1,43 +0,0 @@
#ifndef APPLICATIONPATHS_H
#define APPLICATIONPATHS_H
#include <QDir>
#include <QStandardPaths>
#include <QStringList>
namespace QtGui {
class ApplicationPaths {
public:
static QString settingsPath();
static QString dowloadedFilesPath();
protected:
static QString path(QStandardPaths::StandardLocation location);
};
inline QString ApplicationPaths::settingsPath()
{
return path(QStandardPaths::DataLocation);
}
inline QString ApplicationPaths::dowloadedFilesPath()
{
return path(QStandardPaths::CacheLocation);
}
inline QString ApplicationPaths::path(QStandardPaths::StandardLocation location)
{
QString path = QStandardPaths::standardLocations(location).value(0);
QDir dir(path);
if (!dir.exists()) {
dir.mkpath(path);
}
if (!path.isEmpty() && !path.endsWith("/")) {
path += "/";
}
return path;
}
} // namespace QtGui
#endif // APPLICATIONPATHS_H

145
quickgui/controller.cpp Normal file
View File

@ -0,0 +1,145 @@
#include "./controller.h"
#include <passwordfile/io/cryptoexception.h>
#include <passwordfile/io/parsingexception.h>
#include <qtutilities/misc/dialogutils.h>
#include <c++utilities/io/catchiofailure.h>
#include <QDir>
#include <QFileInfo>
#include <QIcon>
#include <QStringBuilder>
#include <stdexcept>
using namespace std;
using namespace Io;
using namespace IoUtilities;
using namespace Dialogs;
namespace QtGui {
Controller::Controller(const QString &filePath, QObject *parent)
: QObject(parent)
, m_fileOpen(false)
, m_fileModified(false)
{
setFilePath(filePath);
m_entryFilterModel.setSourceModel(&m_entryModel);
}
void Controller::setFilePath(const QString &filePath)
{
if (m_filePath == filePath) {
return;
}
m_file.clear();
m_file.setPath(filePath.toLocal8Bit().data());
emit filePathChanged(m_filePath = filePath);
}
void Controller::setPassword(const QString &password)
{
if (m_password == password) {
return;
}
m_file.setPassword(password.toUtf8().data());
emit passwordChanged(m_password = password);
}
void Controller::load()
{
resetFileStatus();
try {
m_file.load();
m_entryModel.setRootEntry(m_file.rootEntry());
setFileOpen(true);
updateWindowTitle();
} catch (const CryptoException &e) {
if (m_file.isEncryptionUsed() && m_password.isEmpty()) {
emit passwordRequired(m_filePath);
} else {
emit fileError(tr("A crypto error occured when opening the file: ") + QString::fromLocal8Bit(e.what()));
}
} catch (const runtime_error &e) {
emit fileError(tr("A parsing error occured when opening the file: ") + QString::fromLocal8Bit(e.what()));
} catch (...) {
emitIoError(tr("loading"));
}
}
void Controller::create()
{
resetFileStatus();
try {
m_file.create();
m_entryModel.setRootEntry(m_file.rootEntry());
setFileOpen(true);
updateWindowTitle();
} catch (...) {
emitIoError(tr("creating"));
}
}
void Controller::close()
{
try {
m_file.close();
resetFileStatus();
} catch (...) {
emitIoError(tr("closing"));
}
}
void Controller::save()
{
try {
if (!m_password.isEmpty()) {
const auto passwordUtf8(m_password.toUtf8());
m_file.setPassword(string(passwordUtf8.data(), static_cast<size_t>(passwordUtf8.size())));
} else {
m_file.clearPassword();
}
m_file.save(!m_password.isEmpty());
} catch (const CryptoException &e) {
emit fileError(tr("A crypto error occured when saving the file: ") + QString::fromLocal8Bit(e.what()));
} catch (const runtime_error &e) {
emit fileError(tr("An internal error occured when saving the file: ") + QString::fromLocal8Bit(e.what()));
} catch (...) {
emitIoError(tr("saving"));
}
}
void Controller::resetFileStatus()
{
setFileOpen(false);
m_entryModel.reset();
m_fieldModel.reset();
}
void Controller::updateWindowTitle()
{
if (m_fileOpen) {
const QFileInfo file(m_filePath);
emit windowTitleChanged(m_windowTitle = file.fileName() % QStringLiteral(" - ") % file.dir().path());
} else {
emit windowTitleChanged(tr("No file opened."));
}
}
void Controller::setFileOpen(bool fileOpen)
{
if (fileOpen != m_fileOpen) {
emit fileOpenChanged(m_fileOpen = fileOpen);
}
}
void Controller::emitIoError(const QString &when)
{
const auto *const msg = catchIoFailure();
emit fileError(tr("An IO error occured when %1 the file: ").arg(when) + QString::fromLocal8Bit(msg));
}
} // namespace QtGui

130
quickgui/controller.h Normal file
View File

@ -0,0 +1,130 @@
#ifndef QT_QUICK_GUI_CONTROLLER_H
#define QT_QUICK_GUI_CONTROLLER_H
#include "../model/entryfiltermodel.h"
#include "../model/entrymodel.h"
#include "../model/fieldmodel.h"
#include <passwordfile/io/passwordfile.h>
#include <QObject>
namespace QtGui {
class Controller : public QObject {
Q_OBJECT
Q_PROPERTY(QString filePath READ filePath WRITE setFilePath NOTIFY filePathChanged)
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
Q_PROPERTY(QString windowTitle READ windowTitle NOTIFY windowTitleChanged)
Q_PROPERTY(bool fileOpen READ isFileOpen NOTIFY fileOpenChanged)
Q_PROPERTY(EntryModel *entryModel READ entryModel NOTIFY entryModelChanged)
Q_PROPERTY(EntryFilterModel *entryFilterModel READ entryFilterModel NOTIFY entryFilterModelChanged)
Q_PROPERTY(FieldModel *fieldModel READ fieldModel NOTIFY fieldModelChanged)
Q_PROPERTY(QModelIndex currentAccountIndex READ currentAccountIndex WRITE setCurrentAccountIndex NOTIFY currentAccountChanged)
Q_PROPERTY(QString currentAccountName READ currentAccountName NOTIFY currentAccountChanged)
public:
explicit Controller(const QString &filePath = QString(), QObject *parent = nullptr);
const QString &filePath() const;
void setFilePath(const QString &filePath);
const QString &password() const;
void setPassword(const QString &password);
const QString &windowTitle() const;
bool isFileOpen() const;
EntryModel *entryModel();
EntryFilterModel *entryFilterModel();
FieldModel *fieldModel();
QModelIndex currentAccountIndex() const;
void setCurrentAccountIndex(const QModelIndex &accountIndex);
QString currentAccountName() const;
public slots:
void load();
void create();
void close();
void save();
signals:
void filePathChanged(const QString &newFilePath);
void passwordChanged(const QString &newPassword);
void passwordRequired(const QString &filePath);
void windowTitleChanged(const QString &windowTitle);
void fileOpenChanged(bool fileOpen);
void fileError(const QString &errorMessage);
void entryModelChanged();
void entryFilterModelChanged();
void fieldModelChanged();
void currentAccountChanged();
private:
void resetFileStatus();
void updateWindowTitle();
void setFileOpen(bool fileOpen);
void emitIoError(const QString &when);
QString m_filePath;
QString m_password;
QString m_windowTitle;
Io::PasswordFile m_file;
EntryModel m_entryModel;
EntryFilterModel m_entryFilterModel;
FieldModel m_fieldModel;
bool m_fileOpen;
bool m_fileModified;
};
inline const QString &Controller::filePath() const
{
return m_filePath;
}
inline const QString &Controller::password() const
{
return m_password;
}
inline const QString &Controller::windowTitle() const
{
return m_windowTitle;
}
inline bool Controller::isFileOpen() const
{
return m_fileOpen;
}
inline EntryModel *Controller::entryModel()
{
return &m_entryModel;
}
inline EntryFilterModel *Controller::entryFilterModel()
{
return &m_entryFilterModel;
}
inline FieldModel *Controller::fieldModel()
{
return &m_fieldModel;
}
inline QModelIndex Controller::currentAccountIndex() const
{
return m_fieldModel.accountEntry() ? m_entryModel.index(const_cast<Io::AccountEntry *>(m_fieldModel.accountEntry())) : QModelIndex();
}
inline void Controller::setCurrentAccountIndex(const QModelIndex &accountIndex)
{
m_fieldModel.setAccountEntry(m_entryModel.isNode(accountIndex) ? nullptr : static_cast<Io::AccountEntry *>(m_entryModel.entry(accountIndex)));
emit currentAccountChanged();
}
inline QString Controller::currentAccountName() const
{
return m_fieldModel.accountEntry() ? QString::fromStdString(m_fieldModel.accountEntry()->label()) : QStringLiteral("?");
}
} // namespace QtGui
#endif // QT_QUICK_GUI_CONTROLLER_H

View File

@ -1,37 +1,25 @@
#include "./initiatequick.h"
#include "./applicationinfo.h"
#include "../model/entryfiltermodel.h"
#include "../model/entrymodel.h"
#include "../model/fieldmodel.h"
#include "./controller.h"
#include "resources/config.h"
#include <qtutilities/resources/qtconfigarguments.h>
#include <qtutilities/resources/resources.h>
#if defined(GUI_QTWIDGETS)
#include <QApplication>
#else
#include <QGuiApplication>
#endif
#include <QDebug>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QTextCodec>
#include <QtQml>
#ifdef PASSWORD_MANAGER_GUI_QTWIDGETS
#include <QApplication>
#endif
using namespace ApplicationUtilities;
namespace QtGui {
static QObject *applicationInfo(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return new ApplicationInfo();
}
int runQuickGui(int argc, char *argv[], const QtConfigArguments &qtConfigArgs, const QString &file)
{
// init application
@ -40,7 +28,7 @@ int runQuickGui(int argc, char *argv[], const QtConfigArguments &qtConfigArgs, c
#endif
SET_QT_APPLICATION_INFO;
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#if defined(GUI_QTWIDGETS)
#ifdef PASSWORD_MANAGER_GUI_QTWIDGETS
QApplication a(argc, argv);
#else
QGuiApplication a(argc, argv);
@ -64,16 +52,19 @@ int runQuickGui(int argc, char *argv[], const QtConfigArguments &qtConfigArgs, c
};
// init Quick GUI
qmlRegisterSingletonType<QtGui::ApplicationInfo>("martchus.passwordmanager", 2, 0, "ApplicationInfo", applicationInfo);
qmlRegisterType<QtGui::EntryFilterModel>("martchus.passwordmanager", 2, 0, "EntryFilterModel");
qmlRegisterType<QtGui::EntryModel>("martchus.passwordmanager", 2, 0, "EntryModel");
qmlRegisterType<QtGui::FieldModel>("martchus.passwordmanager", 2, 0, "FieldModel");
QQmlApplicationEngine engine(QUrl("qrc:/qml/main.qml"));
engine.rootContext()->setContextProperty(QStringLiteral("userPaths"), userPaths);
engine.rootContext()->setContextProperty(QStringLiteral("file"), file);
//qmlRegisterType<QtGui::EntryFilterModel>("martchus.passwordmanager", 2, 0, "EntryFilterModel");
//qmlRegisterType<QtGui::EntryModel>("martchus.passwordmanager", 2, 0, "EntryModel");
//qmlRegisterType<QtGui::FieldModel>("martchus.passwordmanager", 2, 0, "FieldModel");
//qmlRegisterType<Io::AccountEntry>("martchus.passwordmanager", 2, 1, "AccountEntry");
// start event loop
int res = a.exec();
return res;
QQmlApplicationEngine engine;
Controller controller(file);
QQmlContext *const context(engine.rootContext());
context->setContextProperty(QStringLiteral("userPaths"), userPaths);
context->setContextProperty(QStringLiteral("nativeInterface"), &controller);
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
// run event loop
return a.exec();
}
} // namespace QtGui

View File

@ -1,20 +1,9 @@
<RCC>
<qresource prefix="/qml">
<file alias="main.qml">../qml/main.qml</file>
<file alias="pages/AccountsPage.qml">../qml/pages/AccountsPage.qml</file>
<file alias="pages/BasicPage.qml">../qml/pages/BasicPage.qml</file>
<file alias="pages/FieldsPage.qml">../qml/pages/FieldsPage.qml</file>
<file alias="pages/StartPage.qml">../qml/pages/StartPage.qml</file>
<file alias="pages/Separator.qml">../qml/pages/Separator.qml</file>
<file alias="touch/TouchButton.qml">../qml/touch/TouchButton.qml</file>
<file alias="touch/TouchLabel.qml">../qml/touch/TouchLabel.qml</file>
<file alias="touch/TouchTextField.qml">../qml/touch/TouchTextField.qml</file>
<file alias="touch/TouchSlider.qml">../qml/touch/TouchSlider.qml</file>
<file alias="touch/TouchScrollView.qml">../qml/touch/TouchScrollView.qml</file>
<file alias="touch/ListViewDelegate.qml">../qml/touch/ListViewDelegate.qml</file>
<file alias="images/clear.png">../qml/images/clear.png</file>
<file alias="images/magnifier.png">../qml/images/magnifier.png</file>
<file alias="images/backarrow.png">../qml/images/backarrow.png</file>
<file alias="images/close.png">../qml/images/close.png</file>
<file alias="BasicDialog.qml">../qml/BasicDialog.qml</file>
<file alias="PasswordDialog.qml">../qml/PasswordDialog.qml</file>
<file alias="EntriesPage.qml">../qml/EntriesPage.qml</file>
<file alias="banner.png">../qml/banner.png</file>
</qresource>
</RCC>

View File

Before

Width:  |  Height:  |  Size: 376 B

After

Width:  |  Height:  |  Size: 376 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 KiB

BIN
testfiles/test.pwmgr Normal file

Binary file not shown.