Import/Export GUI

This commit is contained in:
Pavel Škoda
2020-06-23 15:35:54 +02:00
committed by Michal Horejsek
parent 1c10cc5065
commit 7e5e3d3dd4
50 changed files with 1793 additions and 692 deletions

View File

@ -38,7 +38,7 @@ Item {
property var allMonths : getMonthList(1,12)
property var allDays : getDayList(1,31)
property var enums : JSON.parse('{"pathOK":1,"pathEmptyPath":2,"pathWrongPath":4,"pathNotADir":8,"pathWrongPermissions":16,"pathDirEmpty":32,"errUnknownError":0,"errEventAPILogout":1,"errUpdateAPI":2,"errUpdateJSON":3,"errUserAuth":4,"errQApplication":18,"errEmailExportFailed":6,"errEmailExportMissing":7,"errNothingToImport":8,"errEmailImportFailed":12,"errDraftImportFailed":13,"errDraftLabelFailed":14,"errEncryptMessageAttachment":15,"errEncryptMessage":16,"errNoInternetWhileImport":17,"errUnlockUser":5,"errSourceMessageNotSelected":19,"errCannotParseMail":5000,"errWrongLoginOrPassword":5001,"errWrongServerPathOrPort":5002,"errWrongAuthMethod":5003,"errIMAPFetchFailed":5004,"errLocalSourceLoadFailed":1000,"errPMLoadFailed":1001,"errRemoteSourceLoadFailed":1002,"errLoadAccountList":1005,"errExit":1006,"errRetry":1007,"errAsk":1008,"errImportFailed":1009,"errCreateLabelFailed":1010,"errCreateFolderFailed":1011,"errUpdateLabelFailed":1012,"errUpdateFolderFailed":1013,"errFillFolderName":1014,"errSelectFolderColor":1015,"errNoInternet":1016,"folderTypeSystem":"","folderTypeLabel":"label","folderTypeFolder":"folder","folderTypeExternal":"external","progressInit":"init","progressLooping":"looping","statusNoInternet":"noInternet","statusCheckingInternet":"internetCheck","statusNewVersionAvailable":"oldVersion","statusUpToDate":"upToDate","statusForceUpdate":"forceupdate"}')
property var enums : JSON.parse('{"pathOK":1,"pathEmptyPath":2,"pathWrongPath":4,"pathNotADir":8,"pathWrongPermissions":16,"pathDirEmpty":32,"errUnknownError":0,"errEventAPILogout":1,"errUpdateAPI":2,"errUpdateJSON":3,"errUserAuth":4,"errQApplication":18,"errEmailExportFailed":6,"errEmailExportMissing":7,"errNothingToImport":8,"errEmailImportFailed":12,"errDraftImportFailed":13,"errDraftLabelFailed":14,"errEncryptMessageAttachment":15,"errEncryptMessage":16,"errNoInternetWhileImport":17,"errUnlockUser":5,"errSourceMessageNotSelected":19,"errCannotParseMail":5000,"errWrongLoginOrPassword":5001,"errWrongServerPathOrPort":5002,"errWrongAuthMethod":5003,"errIMAPFetchFailed":5004,"errLocalSourceLoadFailed":1000,"errPMLoadFailed":1001,"errRemoteSourceLoadFailed":1002,"errLoadAccountList":1005,"errExit":1006,"errRetry":1007,"errAsk":1008,"errImportFailed":1009,"errCreateLabelFailed":1010,"errCreateFolderFailed":1011,"errUpdateLabelFailed":1012,"errUpdateFolderFailed":1013,"errFillFolderName":1014,"errSelectFolderColor":1015,"errNoInternet":1016,"folderTypeSystem":"system","folderTypeLabel":"label","folderTypeFolder":"folder","folderTypeExternal":"external","progressInit":"init","progressLooping":"looping","statusNoInternet":"noInternet","statusCheckingInternet":"internetCheck","statusNewVersionAvailable":"oldVersion","statusUpToDate":"upToDate","statusForceUpdate":"forceupdate"}')
IEStyle{}
@ -396,7 +396,7 @@ Item {
onTriggered : go.runCheckVersion(false)
}
property string areYouSureYouWantToQuit : qsTr("Tool does not finished all the jobs. Do you really want to quit?")
property string areYouSureYouWantToQuit : qsTr("There are incomplete processes - some items are not yet transferred. Do you really want to stop and quit?")
// On start
Component.onCompleted : {
// set spell messages

View File

@ -25,14 +25,15 @@ import ImportExportUI 1.0
Column {
id: dateRange
property var structure : structureExternal
property string sourceID : structureExternal.getID ( -1 )
property var structure : transferRules
property string sourceID : "-1"
property alias allDates : allDatesBox.checked
property alias inputDateFrom : inputDateFrom
property alias inputDateTo : inputDateTo
function setRange() {common.setRange()}
function getRange() {common.getRange()}
function setRangeFromTo(from, to) {common.setRangeFromTo(from, to)}
function applyRange() {common.applyRange()}
property var dropDownStyle : Style.dropDownLight

View File

@ -34,7 +34,7 @@ Item {
property alias inputDateFrom : inputDateFrom
property alias inputDateTo : inputDateTo
function setRange() {common.setRange()}
function getRange() {common.getRange()}
function applyRange() {common.applyRange()}
*/
@ -43,11 +43,7 @@ Item {
inputDateTo.setDate((new Date()).getTime())
}
function setRange(){ // unix time in seconds
var folderFrom = dateRange.structure.getFrom(dateRange.sourceID)
if (folderFrom===undefined) folderFrom = 0
var folderTo = dateRange.structure.getTo(dateRange.sourceID)
if (folderTo===undefined) folderTo = 0
function setRangeFromTo(folderFrom, folderTo){ // unix time in seconds
if ( folderFrom == 0 && folderTo ==0 ) {
dateRange.allDates = true
} else {
@ -57,6 +53,15 @@ Item {
}
}
function getRange(){ // unix time in seconds
//console.log(" ==== GET RANGE === ")
//console.trace()
var folderFrom = dateRange.structure.globalFromDate
var folderTo = dateRange.structure.globalToDate
root.setRangeFromTo(folderFrom, folderTo)
}
function applyRange(){ // unix time is seconds
if (dateRange.allDates) structure.setFromToDate(dateRange.sourceID, 0, 0)
else {
@ -67,15 +72,10 @@ Item {
}
}
Connections {
target: dateRange
onStructureChanged: setRange()
}
Component.onCompleted: {
inputDateFrom.updateRange(gui.netBday)
inputDateTo.updateRange(new Date())
setRange()
//getRange()
}
}

View File

@ -31,8 +31,10 @@ Rectangle {
property real padding : Style.dialog.spacing
property bool down : popup.visible
property var structure : structureExternal
property string sourceID : structureExternal.getID(-1)
property var structure : transferRules
property string sourceID : ""
property int sourceFromDate : 0
property int sourceToDate : 0
color: Style.transparent
@ -145,7 +147,17 @@ Rectangle {
}
}
onAboutToShow : dateRangeInput.setRange()
onAboutToShow : updateRange()
onAboutToHide : dateRangeInput.applyRange()
}
function updateRange() {
dateRangeInput.setRangeFromTo(root.sourceFromDate, root.sourceToDate)
}
Connections {
target:root
onSourceFromDateChanged: root.updateRange()
onSourceToDateChanged: root.updateRange()
}
}

View File

@ -91,8 +91,6 @@ Dialog {
DateRange{
id: dateRangeInput
structure: structurePM
sourceID: structurePM.getID(-1)
}
OutputFormat {
@ -142,7 +140,7 @@ Dialog {
id: buttonNext
fa_icon: Style.fa.check
text: qsTr("Export","todo")
enabled: structurePM != 0
enabled: transferRules != 0
color_main: Style.dialog.background
color_minor: enabled ? Style.dialog.textBlue : Style.main.textDisabled
isOpaque: true
@ -168,13 +166,17 @@ Dialog {
spacing: Style.main.rightMargin
AccessibleText {
id: statusLabel
text : qsTr("Exporting to:")
text : qsTr("Status:")
font.pointSize: Style.main.iconSize * Style.pt
color : Style.main.text
}
AccessibleText {
anchors.baseline: statusLabel.baseline
text : go.progressDescription == gui.enums.progressInit ? outputPathInput.path : go.progressDescription
text : {
if (progressbarExport.isFinished) return qsTr("finished")
if (go.progressDescription == "") return qsTr("exporting")
return go.progressDescription
}
elide: Text.ElideMiddle
width: progressbarExport.width - parent.spacing - statusLabel.width
font.pointSize: Style.dialog.textSize * Style.pt
@ -310,15 +312,17 @@ Dialog {
function check_inputs() {
if (currentIndex == 1) {
// at least one email to export
if (structurePM.rowCount() == 0){
if (transferRules.rowCount() == 0){
errorPopup.show(qsTr("No emails found to export. Please try another address.", "todo"))
return false
}
// at least one source selected
if (!structurePM.atLeastOneSelected) {
errorPopup.show(qsTr("Please select at least one item to export.", "todo"))
return false
}
/*
if (!transferRules.atLeastOneSelected) {
errorPopup.show(qsTr("Please select at least one item to export.", "todo"))
return false
}
*/
// check path
var folderCheck = go.checkPathStatus(outputPathInput.path)
switch (folderCheck) {
@ -364,7 +368,6 @@ Dialog {
errorPopup.buttonYes.visible = true
errorPopup.buttonNo.visible = true
errorPopup.buttonOkay.visible = false
errorPopup.checkbox.text = root.msgClearUnfished
errorPopup.show ("Are you sure you want to cancel this export?")
}
@ -374,10 +377,7 @@ Dialog {
case 0 :
case 1 : root.hide(); break;
case 2 : // progress bar
go.cancelProcess (
errorPopup.checkbox.text == root.msgClearUnfished &&
errorPopup.checkbox.checked
);
go.cancelProcess();
// no break
default:
root.clear_status()
@ -395,7 +395,7 @@ Dialog {
root.hide()
break
case 0: // loading structure
dateRangeInput.setRange()
dateRangeInput.getRange()
//no break
default:
incrementCurrentIndex()
@ -426,7 +426,7 @@ Dialog {
switch (currentIndex) {
case 0:
go.loadStructureForExport(root.address)
sourceFoldersInput.hasItems = (structurePM.rowCount() > 0)
sourceFoldersInput.hasItems = (transferRules.rowCount() > 0)
break
case 2:
dateRangeInput.applyRange()

View File

@ -327,6 +327,7 @@ Dialog {
iconText: Style.fa.refresh
textColor: Style.main.textBlue
onClicked: {
go.resetSource()
root.decrementCurrentIndex()
timer.start()
}
@ -408,20 +409,13 @@ Dialog {
spacing: Style.main.rightMargin
AccessibleText {
id: statusLabel
text : qsTr("Importing from:")
text : qsTr("Status:")
font.pointSize: Style.main.iconSize * Style.pt
color : Style.main.text
}
AccessibleText {
anchors.baseline: statusLabel.baseline
text : {
var sourceFolder = root.isFromFile ? root.inputPath : inputEmail.text
if (go.progressDescription != gui.enums.progressInit && go.progress!=0) {
sourceFolder += "/"
sourceFolder += go.progressDescription
}
return sourceFolder
}
text : go.progressDescription == "" ? qsTr("importing") : go.progressDescription
elide: Text.ElideMiddle
width: progressbarImport.width - parent.spacing - statusLabel.width
font.pointSize: Style.dialog.textSize * Style.pt
@ -582,9 +576,9 @@ Dialog {
spacing : Style.dialog.heightSeparator
Text {
text: Style.fa.check_circle + " " + qsTr("Import completed successfully")
text: go.progressDescription!="" ? qsTr("Import failed: %1").arg(go.progressDescription) : Style.fa.check_circle + " " + qsTr("Import completed successfully")
anchors.horizontalCenter: parent.horizontalCenter
color: Style.main.textGreen
color: go.progressDescription!="" ? Style.main.textRed : Style.main.textGreen
font.bold : true
font.family: Style.fontawesome.name
}
@ -605,11 +599,7 @@ Dialog {
text : qsTr("View errors")
color_main : Style.dialog.textBlue
onClicked : {
if (go.importLogFileName=="") {
console.log("onViewErrors: missing import log file name")
return
}
go.loadImportReports(go.importLogFileName)
go.loadImportReports()
reportList.show()
}
}
@ -619,10 +609,6 @@ Dialog {
text : qsTr("Report files")
color_main : Style.dialog.textBlue
onClicked : {
if (go.importLogFileName=="") {
console.log("onReportError: missing import log file name")
return
}
root.ask_send_report()
}
}
@ -755,7 +741,6 @@ Dialog {
}
function clear() {
go.resetSource()
root.inputPath = ""
clear_status()
inputEmail.clear()
@ -781,7 +766,7 @@ Dialog {
onClickedYes : {
if (errorPopup.msgID == "ask_send_report") {
errorPopup.hide()
root.report_sent(go.sendImportReport(root.address,go.importLogFileName))
root.report_sent(go.sendImportReport(root.address))
return
}
root.cancel()
@ -857,10 +842,13 @@ Dialog {
}
break
case 3: // import insturctions
if (!structureExternal.hasTarget()) {
errorPopup.show(qsTr("Nothing selected for import."))
return false
}
/*
console.log(" ====== TODO ======== ")
if (!structureExternal.hasTarget()) {
errorPopup.show(qsTr("Nothing selected for import."))
return false
}
*/
break
case 4: // import status
}
@ -880,7 +868,7 @@ Dialog {
root.hide()
break
case DialogImport.Page.Progress:
go.cancelProcess(false)
go.cancelProcess()
root.currentIndex=3
root.clear_status()
globalLabels.reset()
@ -905,7 +893,7 @@ Dialog {
globalLabels.labelName,
globalLabels.labelColor,
true,
structureExternal.getID(-1)
"-1"
)
if (!isOK) return
}
@ -919,7 +907,8 @@ Dialog {
case DialogImport.Page.LoadingStructure:
globalLabels.reset()
importInstructions.hasItems = (structureExternal.rowCount() > 0)
// TODO_: importInstructions.hasItems = (structureExternal.rowCount() > 0)
importInstructions.hasItems = true
case DialogImport.Page.ImapSource:
default:
incrementCurrentIndex()
@ -1008,7 +997,7 @@ Dialog {
case DialogImport.Page.SelectSourceType:
case DialogImport.Page.ImapSource:
case DialogImport.Page.SourceToTarget:
globalDateRange.setRange()
globalDateRange.getRange()
break
case DialogImport.Page.LoadingStructure:
go.setupAndLoadForImport(

View File

@ -92,7 +92,7 @@ Rectangle {
clip : true
orientation : ListView.Vertical
boundsBehavior : Flickable.StopAtBounds
model : structurePM
model : transferRules
cacheBuffer : 10000
anchors {
@ -125,27 +125,25 @@ Rectangle {
}
delegate: FolderRowButton {
property variant modelData: model
width : root.width - 5*root.border.width
type : folderType
color : folderColor
title : folderName
isSelected : isFolderSelected
type : modelData.type
folderIconColor : modelData.iconColor
title : modelData.name
isSelected : modelData.isActive
onClicked : {
//console.log("Clicked", folderId, isSelected)
structurePM.setFolderSelection(folderId,!isSelected)
transferRules.setIsRuleActive(modelData.mboxID,!model.isActive)
}
}
section.property: "folderType"
section.property: "type"
section.delegate: FolderRowButton {
isSection : true
width : root.width - 5*root.border.width
title : gui.folderTypeTitle(section)
isSelected : {
//console.log("section selected changed: ", section)
return section == gui.enums.folderTypeLabel ? structurePM.selectedLabels : structurePM.selectedFolders
}
onClicked : structurePM.selectType(section,!isSelected)
isSelected : section == gui.enums.folderTypeLabel ? transferRules.isLabelGroupSelected : transferRules.isFolderGroupSelected
onClicked : transferRules.setIsGroupActive(section,!isSelected)
}
}
}

View File

@ -26,9 +26,9 @@ AccessibleButton {
property bool isSection : false
property bool isSelected : false
property string title : "N/A"
property string type : ""
property color color : "black"
property string title : "N/A"
property string type : ""
property string folderIconColor : Style.main.textBlue
height : Style.exporting.rowHeight
padding : 0.0
@ -72,7 +72,7 @@ AccessibleButton {
left : checkbox.left
leftMargin : Style.dialog.fontSize + Style.exporting.leftMargin
}
color : root.type==gui.enums.folderTypeSystem ? Style.main.textBlue : root.color
color : root.type=="" ? Style.main.textBlue : root.folderIconColor
font {
family : Style.fontawesome.name
pointSize : Style.dialog.fontSize * Style.pt

View File

@ -39,7 +39,7 @@ Rectangle {
}
property real iconWidth : nameWidth*0.3
property bool isSourceSelected: targetFolderID!=""
property bool isSourceSelected: isActive
property string lastTargetFolder: "6" // Archive
property string lastTargetLabels: "" // no flag by default
@ -71,7 +71,7 @@ Rectangle {
Text {
id: folderIcon
text : gui.folderIcon(folderName, gui.enums.folderTypeFolder)
text : gui.folderIcon(name, gui.enums.folderTypeFolder)
anchors.verticalCenter : parent.verticalCenter
color: root.isSourceSelected ? Style.main.text : Style.main.textDisabled
font {
@ -81,7 +81,7 @@ Rectangle {
}
Text {
text : folderName
text : name
width: nameWidth
elide: Text.ElideRight
anchors.verticalCenter : parent.verticalCenter
@ -102,24 +102,27 @@ Rectangle {
SelectFolderMenu {
id: selectFolder
sourceID: folderId
selectedIDs: targetFolderID
sourceID: mboxID
targets: transferRules.targetFolders(mboxID)
width: nameWidth
anchors.verticalCenter : parent.verticalCenter
enabled: root.isSourceSelected
onDoNotImport: root.toggleImport()
onImportToFolder: root.importToFolder(newTargetID)
}
SelectLabelsMenu {
sourceID: folderId
selectedIDs: targetLabelIDs
sourceID: mboxID
targets: transferRules.targetLabels(mboxID)
width: nameWidth
anchors.verticalCenter : parent.verticalCenter
enabled: root.isSourceSelected
onAddTargetLabel: { transferRules.addTargetID(sourceID, newTargetID) }
onRemoveTargetLabel: { transferRules.removeTargetID(sourceID, newTargetID) }
}
LabelIconList {
selectedIDs: targetLabelIDs
colorList: labelColors=="" ? [] : labelColors.split(";")
width: iconWidth
anchors.verticalCenter : parent.verticalCenter
enabled: root.isSourceSelected
@ -127,38 +130,23 @@ Rectangle {
DateRangeMenu {
id: dateRangeMenu
sourceID: folderId
sourceID: mboxID
sourceFromDate: fromDate
sourceToDate: toDate
enabled: root.isSourceSelected
anchors.verticalCenter : parent.verticalCenter
Component.onCompleted : dateRangeMenu.updateRange()
}
}
function importToFolder(newTargetID) {
if (root.isSourceSelected) {
structureExternal.setTargetFolderID(folderId,newTargetID)
} else {
lastTargetFolder = newTargetID
toggleImport()
}
transferRules.addTargetID(mboxID,newTargetID)
}
function toggleImport() {
if (root.isSourceSelected) {
lastTargetFolder = targetFolderID
lastTargetLabels = targetLabelIDs
structureExternal.setTargetFolderID(folderId,"")
return Qt.Unchecked
} else {
structureExternal.setTargetFolderID(folderId,lastTargetFolder)
var labelsSplit = lastTargetLabels.split(";")
for (var labelIndex in labelsSplit) {
var labelID = labelsSplit[labelIndex]
structureExternal.addTargetLabelID(folderId,labelID)
}
return Qt.Checked
}
transferRules.setIsRuleActive(mboxID, !root.isSourceSelected)
}
}

View File

@ -50,7 +50,6 @@ Rectangle {
verticalAlignment: Text.AlignVCenter
text: qsTr("No emails found for this source.","todo")
}
}
anchors {
@ -70,7 +69,7 @@ Rectangle {
clip : true
orientation : ListView.Vertical
boundsBehavior : Flickable.StopAtBounds
model : structureExternal
model : transferRules
cacheBuffer : 10000
delegate : ImportDelegate {
width: root.width

View File

@ -25,8 +25,8 @@ import ImportExportUI 1.0
Row {
id: dateRange
property var structure : structureExternal
property string sourceID : structureExternal.getID ( -1 )
property var structure : transferRules
property string sourceID : "-1"
property alias allDates : allDatesBox.checked
property alias inputDateFrom : inputDateFrom
@ -34,7 +34,7 @@ Row {
property alias labelWidth: label.width
function setRange() {common.setRange()}
function getRange() {common.getRange()}
function applyRange() {common.applyRange()}
DateRangeFunctions {id:common}

View File

@ -26,42 +26,16 @@ Rectangle {
id: root
width: Style.main.fontSize * 2
height: metrics.height
property string selectedIDs : ""
property var colorList
color: "transparent"
DelegateModel {
id: selectedLabels
filterOnGroup: "selected"
groups: DelegateModelGroup {
id: selected
name: "selected"
includeByDefault: true
}
model : structurePM
model : colorList
delegate : Text {
text : metrics.text
font : metrics.font
color : folderColor===undefined ? "#000": folderColor
}
}
function updateFilter() {
var selected = root.selectedIDs.split(";")
var rowCount = selectedLabels.items.count
//console.log(" log ::", root.selectedIDs, rowCount, selectedLabels.model)
// filter
for (var iItem = 0; iItem < rowCount; iItem++) {
var entry = selectedLabels.items.get(iItem);
//console.log(" log filter ", iItem, rowCount, entry.model.folderId, entry.model.folderType, selected[iSel], entry.inSelected )
for (var iSel in selected) {
entry.inSelected = (
entry.model.folderType == gui.enums.folderTypeLabel &&
entry.model.folderId == selected[iSel]
)
if (entry.inSelected) break // found match, skip rest
}
color : modelData
}
}
@ -77,7 +51,7 @@ Rectangle {
Row {
anchors.left : root.left
spacing : {
var n = Math.max(2,selectedLabels.count)
var n = Math.max(2,root.colorList.length)
var tagWidth = Math.max(1.0,metrics.width)
var space = Math.min(1*Style.px, (root.width - n*tagWidth)/(n-1)) // not more than 1px
space = Math.max(space,-tagWidth) // not less than tag width
@ -88,9 +62,4 @@ Rectangle {
model: selectedLabels
}
}
Component.onCompleted: root.updateFilter()
onSelectedIDsChanged: root.updateFilter()
Connections { target: structurePM; onDataChanged:root.updateFilter() }
}

View File

@ -26,19 +26,19 @@ ComboBox {
//fixme rounded
height: Style.main.fontSize*2 //fixme
property string folderType: gui.enums.folderTypeFolder
property string selectedIDs
property string sourceID
property var targets
property bool isFolderType: root.folderType == gui.enums.folderTypeFolder
property bool hasTarget: root.selectedIDs != ""
property bool below: true
signal doNotImport()
signal importToFolder(string newTargetID)
signal addTargetLabel(string newTargetID)
signal removeTargetLabel(string newTargetID)
leftPadding: Style.dialog.spacing
onDownChanged : {
if (root.down) view.model.updateFilter()
root.below = popup.y>0
}
@ -58,30 +58,22 @@ ComboBox {
}
displayText: {
//console.trace()
//console.log("updatebox", view.currentIndex, root.hasTarget, root.selectedIDs, root.sourceID, root.folderType)
if (!root.hasTarget) {
if (root.isFolderType) return qsTr("Do not import")
return qsTr("No labels selected")
}
if (!root.isFolderType) return Style.fa.tags + " " + qsTr("Add/Remove labels")
console.log("Target Menu current", view.currentItem, view.currentIndex)
if (view.currentIndex >= 0) {
if (!root.isFolderType) return Style.fa.tags + " " + qsTr("Add/Remove labels")
// We know here that it has a target and this is folder dropdown so we must find the first folder
var selSplit = root.selectedIDs.split(";")
for (var selIndex in selSplit) {
var selectedID = selSplit[selIndex]
var selectedType = structurePM.getType(selectedID)
if (selectedType == gui.enums.folderTypeLabel) continue; // skip type::labele
var selectedName = structurePM.getName(selectedID)
if (selectedName == "") continue; // empty name seems like wrong ID
var icon = gui.folderIcon(selectedName, selectedType)
if (selectedType == gui.enums.folderTypeSystem) {
return icon + " " + selectedName
var tgtName = view.currentItem.folderName
var tgtIcon = view.currentItem.folderIcon
var tgtColor = view.currentItem.folderColor
if (tgtIcon != Style.fa.folder_open) {
return tgtIcon + " " + tgtName
}
var iconColor = structurePM.getColor(selectedID)
return '<font color="'+iconColor+'">'+ icon + "</font> " + selectedName
return '<font color="'+tgtColor+'">'+ tgtIcon + "</font> " + tgtName
}
return ""
if (root.isFolderType) return qsTr("No folder selected")
return qsTr("No labels selected")
}
@ -116,7 +108,7 @@ ComboBox {
color: root.enabled && !root.down ? Style.main.textBlue : root.contentItem.color
}
// Popup objects
// Popup row
delegate: Rectangle {
id: thisDelegate
@ -127,22 +119,15 @@ ComboBox {
color: isHovered ? root.popup.hoverColor : root.popup.backColor
property bool isSelected : {
var selected = root.selectedIDs.split(";")
for (var iSel in selected) {
var sel = selected[iSel]
if (folderId == sel){
return true
}
}
return false
}
property bool isSelected : isActive
property string folderName: name
property string folderIcon: gui.folderIcon(name,type)
property string folderColor: (type == gui.enums.folderTypeLabel || type == gui.enums.folderTypeFolder) ? iconColor : root.popup.textColor
Text {
id: targetIcon
text: gui.folderIcon(folderName,folderType)
color : folderType != gui.enums.folderTypeSystem ? folderColor : root.popup.textColor
text: thisDelegate.folderIcon
color : thisDelegate.folderColor
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
@ -157,6 +142,7 @@ ComboBox {
Text {
id: targetName
anchors {
verticalCenter: parent.verticalCenter
left: targetIcon.right
@ -165,7 +151,7 @@ ComboBox {
rightMargin: Style.dialog.spacing
}
text: folderName
text: thisDelegate.folderName
color : root.popup.textColor
elide: Text.ElideRight
@ -209,16 +195,15 @@ ComboBox {
onClicked: {
//console.log(" click delegate")
if (root.isFolderType) { // don't update if selected
if (!thisDelegate.isSelected) {
root.importToFolder(folderId)
}
root.popup.close()
}
if (root.folderType==gui.enums.folderTypeLabel) {
if (thisDelegate.isSelected) {
structureExternal.removeTargetLabelID(sourceID,folderId)
if (!isActive) {
root.importToFolder(mboxID)
}
} else {
if (isActive) {
root.removeTargetLabel(mboxID)
} else {
structureExternal.addTargetLabelID(sourceID,folderId)
root.addTargetLabel(mboxID)
}
}
}
@ -295,14 +280,10 @@ ComboBox {
clip : true
anchors.fill : parent
model : root.targets
delegate : root.delegate
section.property : "sectionName"
section.delegate : Text{text: sectionName}
model : FilterStructure {
filterOnGroup : root.folderType
delegate : root.delegate
}
currentIndex: view.model.selectedIndex
}
}
@ -338,10 +319,7 @@ ComboBox {
onClicked : {
//console.log("click", addButton.text)
var newName = ""
if ( typeof folderName !== 'undefined' && !structurePM.hasFolderWithName (folderName) ) {
newName = folderName
}
var newName = name
winMain.popupFolderEdit.show(newName, "", "", root.folderType, sourceID)
root.popup.close()
}

View File

@ -210,7 +210,7 @@ Window {
Component.onCompleted : {
testgui.winMain.x = 150
testgui.winMain.x = 350
testgui.winMain.y = 100
}
@ -230,7 +230,7 @@ Window {
}
ListModel{
id: structureExternal
id: structureExternalOFF
property var globalOptions: JSON.parse('{ "folderId" : "global--uniq" , "folderName" : "" , "folderColor" : "" , "folderType" : "" , "folderEntries" : 0, "fromDate": 0, "toDate": 0, "isFolderSelected" : false , "targetFolderID": "14" , "targetLabelIDs": ";20;29" }')
@ -265,7 +265,7 @@ Window {
}
ListModel{
id: structurePM
id: structurePMOFF
// group selectors
property bool selectedLabels : false
@ -328,6 +328,7 @@ Window {
}
}
function setTypeSelected (model, folderType , toSelect ) {
console.log(" select type ", folderType, toSelect)
for (var i= -1; i<model.count; i++) {
@ -457,6 +458,355 @@ Window {
ListElement{ mailSubject : "Pop art is cool again" ; mailDate : "March 2 , 2019 12 : 00 : 22" ; inputFolder : "Archive" ; mailFrom : "me@me.me" ; errorMessage : "Something went wrong and import retry was not successful" ; }
ListElement{ mailSubject : "Check this cute kittens play volleyball on Copacabanana beach" ; mailDate : "March 2 , 2019 12 : 00 : 22" ; inputFolder : "Archive" ; mailFrom : "me@me.me" ; errorMessage : "Something went wrong and import retry was not successful" ; }
}
// Transfer rules
ListModel {
id: transferRules
property var targets : new Object();
// test data for import
property var importRules : JSON.parse('[
{"isActive" : true , "mboxID" : "src1" , "fromDate" : 0 , "toDate" : 0 , "targetIDs" : [ "0" , "label1" ] } ,
{"isActive" : true , "mboxID" : "src2" , "fromDate" : 0 , "toDate" : 0 , "targetIDs" : [ "6" , "label2" ] } ,
{"isActive" : true , "mboxID" : "src3" , "fromDate" : 350000 , "toDate" : 5000000 , "targetIDs" : [ "folder1" ] } ,
{"isActive" : true , "mboxID" : "src4" , "fromDate" : 0 , "toDate" : 0 , "targetIDs" : [ "folder2" , "label1" , "label2" ] }
]')
property var selectedForExport : [ "0", "7", "folder1", "folde2", "label1", "label2", "label3"]
property var extMailboxes: JSON.parse('{
"src1": {"name" : "Source Inbox" , "type" : "external" , "color" : "#000"} ,
"src2": {"name" : "Source Sent" , "type" : "external" , "color" : "#000"} ,
"src3": {"name" : "Source Folder" , "type" : "external" , "color" : "#000"} ,
"src4": {"name" : "Source Trash" , "type" : "external" , "color" : "#000"}
}')
property var pmMailboxes : JSON.parse('{
"0": {"name" : "Inbox" , "type" : "system" , "color" : "#000"} ,
"3": {"name" : "Draft" , "type" : "system" , "color" : "#000"} ,
"6": {"name" : "Archive" , "type" : "system" , "color" : "#000"} ,
"5": {"name" : "All Mail" , "type" : "system" , "color" : "#000"} ,
"3": {"name" : "Trash" , "type" : "system" , "color" : "#000"} ,
"7": {"name" : "Sent" , "type" : "system" , "color" : "#000"} ,
"4": {"name" : "Spam" , "type" : "system" , "color" : "#000"} ,
"folder1": {"name": "Folder 1", "type":"folder", "color":"#57c"},
"folder2": {"name": "Folder 2", "type":"folder", "color":"#5c7"},
"folder3": {"name": "Folder 3", "type":"folder", "color":"#c57"},
"label1": {"name": "Label 1", "type":"label", "color":"#a5a"},
"label2": {"name": "Label 2", "type":"label", "color":"#5aa"},
"label3": {"name": "Label 3", "type":"label", "color":"#aa5"}
}')
ListElement{isActive : true ; mboxID : "source1" ; name : "Source folder 1" ; iconColor : "#cccccc" ; type : "external" ; fromDate : 0 ; toDate : 0 ; labelColors : "red ; green ; blue"}
ListElement{isActive : false ; mboxID : "source2" ; name : "Source folder 2" ; iconColor : "#cccccc" ; type : "external" ; fromDate : 300000 ; toDate : 15000000 ; labelColors : "red ; green ; blue"}
ListElement{isActive : true ; mboxID : "source3" ; name : "Source folder 4" ; iconColor : "#cccccc" ; type : "external" ; fromDate : 0 ; toDate : 0 ; labelColors : "red ; green ; blue"}
// TransferRules INTERFACE
// TransferRules properties
property int globalFromDate : 0 // 45000
property int globalToDate : 0 // 120000
property bool isLabelGroupSelected : false
property bool isFolderGroupSelected : false
// TransferRules default getters
// func (*TransferRules) count() int
// func (*TransferRules) roleNames() map[int] QByteArray
// func (*TransferRules) data(index, role) *QVariant
//
// Expected roles for TransferRules
//
// isActive bool
// mboxID string // constant
// name string // constant
// type string // constant, expected values: "label", "folder", ""
// iconColor string // constant
// fromDate int64
// toDate int64
// labelColors string // list of hex RGB strings delimited by `;`
// TransferRules custom getters
function targetFolders(sourceID) {
//ListElement{isActive: true; mboxID: "target1"; name: "Target system folder"; type: "system"; iconColor:"red"}
return getTargets(sourceID, "folder")
}
function targetLabels(sourceID) {
//ListElement{isActive: false; mboxID: "target3"; name: "Target custom label 1"; type: "label"; iconColor:"green"}
return getTargets(sourceID, "label")
}
// For target drop down menu (labels and folders) we need
// additional model TargetList (QAbstractListModel).
//
// func (*TransferRules) targetFolders(sourceID string) * QAbstractListModel
//
// There is no setter functions for this list all actions are
// handled by TransferRules.
//
// The target models have therefore only data functions and one property as interface:
//
// TargetList properties:
// property int selectedIndex : -1
//
// TargetList default getters
// func (*TargetList) count() int
// func (*TargetList) roleNames() map[int] QByteArray
// func (*TargetList) data(index, role) *QVariant
//
// Expected roles for TargetList
//
// isActive bool
// mboxID string // constant
// name string // constant
// type string // constant, expected values: "label", "folder", ""
// iconColor string // constant
//
// The tricky part here is the QAbstractListModel implemetation: it
// needs to return all targets of certain type and their index.
// Setters
function setIsRuleActive(srcID, isActive){
console.log("setIsRuleActive", srcID, isActive)
var groupLabelsSelected = true
var groupFoldersSelected = true
for (var i = 0; i < transferRules.count; i++) {
var rule = transferRules.get(i)
if (rule.mboxID ==srcID) rule.isActive = isActive;
if (!rule.isActive && rule.type == "label") groupLabelsSelected = false
if (!rule.isActive && rule.type == "folder") groupFoldersSelected = false
}
transferRules.isLabelGroupSelected = groupLabelsSelected
transferRules.isFolderGroupSelected = groupFoldersSelected
}
function setIsGroupActive(groupName,isActive){
console.log("setIsGroupActive", groupName, isActive)
var groupLabelsSelected = true
var groupFoldersSelected = true
for (var i = 0; i < transferRules.count; i++) {
var rule = transferRules.get(i)
if (rule.type == groupName) rule.isActive = isActive;
if (!rule.isActive && rule.type == "label") groupLabelsSelected = false
if (!rule.isActive && rule.type == "folder") groupFoldersSelected = false
}
transferRules.isLabelGroupSelected = groupLabelsSelected
transferRules.isFolderGroupSelected = groupFoldersSelected
}
function setFromToDate(srcID, fromDate, toDate){
console.log("setFromToDate", srcID, fromDate, toDate)
for (var i = 0; i < transferRules.count; i++) {
var rule = transferRules.get(i)
if (rule.mboxID ==srcID) {
rule.fromDate = fromDate
rule.toDate = toDate
}
}
}
function addTargetID(srcID, targetID){
console.log("addTargetID", srcID, targetID)
changeTargetID(srcID, targetID, true)
}
function removeTargetID(srcID, targetID){
console.log("removeTargetID", srcID, targetID)
changeTargetID(srcID, targetID, false)
}
// MOCK METHODS: NOT PART OF INTERFACE
Component.onCompleted: prepareImport()
// Fill model with import rules
function prepareImport() {
console.log(" ==== Prepare IMPORT ==== ")
console.trace()
transferRules.clear()
for (var ruleI in transferRules.importRules) {
var rule = transferRules.importRules[ruleI]
var src = transferRules.extMailboxes[rule.mboxID];
var labelColors = [];
for (var tid in rule.targetIDs) {
var targetID = rule.targetIDs[tid]
if (pmMailboxes[targetID].type == "label") {
labelColors.push(pmMailboxes[targetID]["color"])
}
}
transferRules.append({
"isActive" : rule.isActive,
"mboxID" : rule.mboxID,
"name" : src.name,
"type" : src.type,
"iconColor" : src["color"],
"fromDate" : rule.fromDate,
"toDate" : rule.toDate,
"labelColors" : labelColors.join(";"),
});
}
}
// Fill model with export rules
function prepareExport() {
console.log(" ==== Prepare EXPORT ==== ")
console.trace()
transferRules.clear()
var groupLabelsSelected = true
var groupFoldersSelected = true
for (var srcID in transferRules.pmMailboxes) {
var src = transferRules.pmMailboxes[srcID]
var isActive = transferRules.selectedForExport.find(function(mboxID){return mboxID == srcID}) !== undefined
transferRules.append({
"isActive" : isActive,
"mboxID" : srcID,
"name" : src.name,
"type" : (src.type == "system" ? "" : src["type"]),
"iconColor" : src["color"],
"fromDate" : 0,
"toDate" : 0,
"labelColors" : src["color"]
});
if (!isActive) {
if (src.type == "label") {
groupLabelsSelected = false
}
if (src.type == "folder") {
groupFoldersSelected = false
}
}
}
transferRules.isLabelGroupSelected = groupLabelsSelected
transferRules.isFolderGroupSelected = groupFoldersSelected
}
function getTargets(sourceID, type) {
console.log("get targets:", type, sourceID)
if (! (type+sourceID in transferRules.targets)){
var source;
for (var srcI in transferRules.importRules) {
source = transferRules.importRules[srcI]
if (source.mboxID == sourceID ) {
break
}
}
var model = Qt.createQmlObject ('import QtQuick 2.3; ListModel { property int selectedIndex: -1; }', transferRules);
var i = -1
for (var tgtID in transferRules.pmMailboxes) {
var tgt = transferRules.pmMailboxes[tgtID]
if (type == "label" && tgt.type != "label") continue
if (type != "label" && tgt.type == "label") continue
i++;
var isActive = false
for (var tid in source.targetIDs ) {
var selectedID = source.targetIDs[tid]
if (selectedID == tgtID) {
isActive = true
model.selectedIndex=i
break
}
}
var row = {
"isActive" : isActive,
"mboxID" : tgtID,
"name" : tgt.name,
"type" : tgt.type,
"iconColor" : tgt["color"]
};
model.append (row) ;
}
transferRules.targets[type+sourceID] = model;
}
return transferRules.targets[type+sourceID];
}
function changeTargetID(srcID, targetID, add){
console.log("change target ID ", srcID, targetID, add)
for (var targetsName in transferRules.targets) {
var targets = transferRules.targets[targetsName]
var areFolders = targetsName == "folder"+srcID
var areLabels = targetsName == "label"+srcID
if (areFolders || areLabels) {
console.log("matched targets ", targetsName, targets)
var deactivateOthers = false
var colorList = []
for (var i =0; i<targets.count; i++) {
var tgt = targets.get(i)
console.log(" tgt", i, tgt.mboxID, tgt.isActive)
if (tgt.mboxID == targetID) {
console.log(" matched tgt", i, tgt.mboxID)
if (areFolders && !add) {
console.exception("WRONG LOGIC: removing folder")
}
if (add) {
targets.selectedIndex=i
}
tgt.isActive = add
deactivateOthers = add && areFolders
console.log(" active ", tgt.isActive)
}
if (areLabels && tgt.isActive) {
colorList.push(tgt.iconColor)
console.log(" colors", i, colorList)
}
}
if (areLabels) {
if (colorList.length == 0){
targets.selectedIndex = -1
}
for (var i = 0; i<transferRules.count; i++) {
var rule = transferRules.get(i)
console.log (" are labels: color list", i, rule.mboxID )
if (rule.mboxID == srcID) {
rule.labelColors = colorList.join(";")
console.log("updated label color list", rule.labelColors)
break
}
}
}
if (deactivateOthers) {
for (var i =0; i<targets.count; i++) {
var tgt = targets.get(i)
if (tgt.mboxID != targetID) {
tgt.isActive = false
console.log(" deactivate ", tgt.mboxID, tgt.isActive)
}
}
}
}
}
}
}
}
@ -497,6 +847,14 @@ Window {
signal toggleMainWin(int systX, int systY, int systW, int systH)
signal notifyHasNoKeychain()
signal notifyKeychainRebuild()
signal notifyAddressChangedLogout()
signal notifyAddressChanged()
signal notifyUpdate()
signal showWindow()
signal showHelp()
signal showQuit()
@ -692,8 +1050,8 @@ Window {
go.animateProgressBar.resume()
}
function cancelProcess(clearUnfinished) {
console.log("stopped at ", go.progress, " clearing unfinished", clearUnfinished)
function cancelProcess() {
console.log("stopped at ", go.progress)
go.animateProgressBar.stop()
}
@ -718,6 +1076,7 @@ Window {
break;
case "loadStructureForExport" :
transferRules.prepareExport()
go.exportStructureLoadFinished(true)
break;