Warning, /pim/kube/framework/qml/MailViewer.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  * Copyright (C) 2016 Michael Bohlender, <michael.bohlender@kdemail.net>
0003  * Copyright (C) 2017 Christian Mollekopf, <mollekopf@kolabsys.com>
0004  *
0005  * This program is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation; either version 2 of the License, or
0008  * (at your option) any later version.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License along
0016  * with this program; if not, write to the Free Software Foundation, Inc.,
0017  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0018  */
0019 
0020 import QtQuick 2.7
0021 import QtQuick.Controls 1.4 as Controls1
0022 import QtQuick.Controls 2
0023 import QtQuick.Layouts 1.1
0024 
0025 import "mailpartview" as MPV
0026 import org.kube.framework 1.0 as Kube
0027 
0028 Rectangle {
0029     id: root
0030 
0031     property var mail
0032     property var message
0033     property string subject
0034     property string sender
0035     property string senderName
0036     property string to
0037     property string cc
0038     property string bcc
0039     property date date
0040     property bool trash
0041     property bool draft
0042     property bool sent
0043     property bool busy: false
0044     property string busyMessage: qsTr("Incomplete body...")
0045     property bool current: false
0046     property bool unread
0047     property alias searchString: mailViewer.searchString
0048     property alias autoLoadImages: mailViewer.autoLoadImages
0049     property alias loaded: messageParser.loaded
0050     property bool collapsed: false
0051 
0052     implicitHeight: mainLayout.height + 2 * Kube.Units.largeSpacing
0053 
0054     Shortcut {
0055         sequence: "V"
0056         onActivated: debugPopupComponent.createObject(root).open()
0057         enabled: root.current
0058     }
0059 
0060     //highlight active mails
0061     border.width: current ? 1 : 0
0062     border.color: Kube.Colors.highlightColor
0063 
0064     color: Kube.Colors.viewBackgroundColor
0065 
0066     Kube.MessageParser {
0067         id: messageParser
0068         message: root.message
0069     }
0070     property var partModel: messageParser.parts
0071     property var attachmentModel: messageParser.attachments
0072 
0073     states: [
0074         State {
0075             name: "busy"; when: root.busy || !root.loaded
0076             PropertyChanges { target: buttonContainer; visible: false}
0077             PropertyChanges { target: body; visible: false}
0078             PropertyChanges { target: footer; visible: false}
0079             PropertyChanges { target: busyBody; visible: true}
0080         },
0081         State {
0082             name: "collapsed"; when: root.collapsed
0083             PropertyChanges { target: buttonContainer; visible: false}
0084             PropertyChanges { target: body; visible: false}
0085             PropertyChanges { target: footer; visible: false}
0086             PropertyChanges { target: collapsedBody; visible: true}
0087         },
0088         State {
0089             name: "full"; when: !root.collapsed && !root.busy && root.loaded
0090             PropertyChanges { target: buttonContainer; visible: true}
0091             PropertyChanges { target: body; visible: true}
0092             PropertyChanges { target: footer; visible: true}
0093             PropertyChanges { target: collapsedBody; visible: false}
0094         }
0095     ]
0096     state: "full"
0097 
0098     //Must be lower in the stacking order than TextContent, otherwise link hovering breaks
0099     MouseArea {
0100         enabled: root.collapsed
0101         hoverEnabled: root.collapsed
0102         anchors.fill: parent
0103         onClicked: {
0104             root.collapsed = !root.collapsed
0105         }
0106 
0107         Rectangle {
0108             anchors.fill: parent
0109             color: Kube.Colors.highlightColor
0110             opacity: 0.4
0111             visible: root.collapsed && parent.containsMouse
0112         }
0113     }
0114 
0115     Column {
0116         id: mainLayout
0117         anchors {
0118             top: parent.top
0119             left: parent.left
0120             right: parent.right
0121             margins: Kube.Units.largeSpacing
0122         }
0123         height: childrenRect.height
0124 
0125         spacing: Kube.Units.smallSpacing
0126 
0127         //BEGIN header
0128         Item {
0129             id: header
0130 
0131             Layout.fillWidth: true
0132             anchors {
0133                 left: parent.left
0134                 right: parent.right
0135             }
0136             height: headerContent.height + Kube.Units.smallSpacing
0137 
0138             states: [
0139                 State {
0140                     name: "small"
0141                     PropertyChanges { target: subject; wrapMode: Text.NoWrap}
0142                     PropertyChanges { target: recipients; visible: true}
0143                     PropertyChanges { target: to; visible: false}
0144                     PropertyChanges { target: cc; visible: false}
0145                     PropertyChanges { target: bcc; visible: false}
0146                 },
0147                 State {
0148                     name: "details"
0149                     PropertyChanges { target: subject; wrapMode: Text.WrapAnywhere}
0150                     PropertyChanges { target: recipients; visible: false}
0151                     PropertyChanges { target: to; visible: true}
0152                     PropertyChanges { target: cc; visible: root.cc}
0153                     PropertyChanges { target: bcc; visible: root.bcc}
0154                 }
0155             ]
0156 
0157             state: "small"
0158 
0159             Kube.Label {
0160                 id: date_label
0161 
0162                 anchors {
0163                     right: seperator.right
0164                     top: parent.top
0165                 }
0166 
0167                 text: Qt.formatDateTime(root.date, "dd MMM yyyy hh:mm")
0168 
0169                 font.pointSize: Kube.Units.tinyFontSize
0170                 opacity: 0.75
0171             }
0172 
0173             Column {
0174                 id: headerContent
0175 
0176                 anchors {
0177                     //left: to_l.right
0178                     horizontalCenter: parent.horizontalCenter
0179                 }
0180 
0181                 //spacing: Kube.Units.smallSpacing
0182 
0183                 width: parent.width
0184 
0185                 Row{
0186                     id: from
0187 
0188                     width: parent.width
0189 
0190                     spacing: Kube.Units.smallSpacing
0191                     clip: true
0192 
0193                     Kube.SelectableLabel {
0194                         id: senderName
0195 
0196                         text: root.senderName
0197                         font.weight: Font.DemiBold
0198                         opacity: 0.75
0199                         states: [
0200                             State {
0201                                 name: "sent"; when: root.sent
0202                                 PropertyChanges { target: senderName; text: qsTr("Sent from") }
0203                             },
0204                             State {
0205                                 name: "draft"; when: root.draft
0206                                 PropertyChanges { target: senderName; text: qsTr("Draft from") }
0207                             }
0208                         ]
0209                     }
0210 
0211                     Kube.SelectableLabel {
0212                         width: parent.width - senderName.width - date_label.width - Kube.Units.largeSpacing
0213 
0214                         text: root.sender
0215                         elide: Text.ElideRight
0216                         opacity: 0.75
0217                         clip: true
0218 
0219                         Kube.TextButton {
0220                             text: qsTr("Send mail to")
0221                             onClicked: Kube.Fabric.postMessage(Kube.Messages.compose, {"recipients": [root.sender]})
0222                         }
0223                     }
0224                 }
0225 
0226                 Kube.SelectableLabel {
0227                     id: subject
0228 
0229                     width: to.width
0230 
0231                     text: root.subject
0232                     elide: Text.ElideRight
0233                     opacity: 0.75
0234                     font.italic: true
0235                     states: [
0236                         State {
0237                             name: "trash"; when: root.trash
0238                             PropertyChanges { target: subject; text: qsTr("Trash: %1").arg(root.subject) }
0239                         }
0240                     ]
0241                 }
0242 
0243                 Kube.SelectableLabel {
0244                     id: recipients
0245 
0246                     width: parent.width - goDown.width - Kube.Units.smallSpacing
0247 
0248                     text: "to: "+ root.to + " "  + root.cc + " " +  root.bcc
0249                     copyText: [root.to, root.cc, root.bcc].filter(s => !!s).join()
0250                     elide: Text.ElideRight
0251                     opacity: 0.75
0252 
0253                     Kube.TextButton {
0254                         text: qsTr("Send mail to")
0255                         onClicked: Kube.Fabric.postMessage(Kube.Messages.compose, {"recipients": [[root.to, root.cc, root.bcc].filter(s => !!s).join()]})
0256                     }
0257                 }
0258 
0259                 Kube.SelectableLabel {
0260                     id: to
0261 
0262                     width: parent.width - goDown.width - Kube.Units.smallSpacing
0263 
0264                     text: "to: " + root.to
0265                     copyText: root.to
0266                     wrapMode: Text.WordWrap
0267                     opacity: 0.75
0268                 }
0269 
0270                 Kube.SelectableLabel {
0271                     id: cc
0272 
0273                     width: parent.width - goDown.width - Kube.Units.smallSpacing
0274 
0275                     text: "cc: " + root.cc
0276                     copyText: root.cc
0277                     wrapMode: Text.WordWrap
0278                     opacity: 0.75
0279                 }
0280 
0281                 Kube.SelectableLabel {
0282                     id: bcc
0283 
0284                     width: parent.width - goDown.width - Kube.Units.smallSpacing
0285 
0286                     text: "bcc: " + root.bcc
0287                     copyText: root.bcc
0288                     wrapMode: Text.WordWrap
0289                     opacity: 0.75
0290                 }
0291 
0292             }
0293 
0294             Rectangle {
0295                 id: goDown
0296                 anchors {
0297                     bottom: seperator.top
0298                     right: seperator.right
0299                 }
0300 
0301                 //Only show the expand button if there is something to expand
0302                 visible: recipients.truncated || root.cc || root.bcc
0303 
0304                 height: Kube.Units.gridUnit
0305                 width: height
0306 
0307                 color: Kube.Colors.backgroundColor
0308 
0309                 Kube.IconButton {
0310                     anchors.fill: parent
0311                     activeFocusOnTab: false
0312 
0313                     iconName: header.state === "details" ? Kube.Icons.goUp : Kube.Icons.goDown
0314 
0315                     onClicked: {
0316                         header.state === "details" ? header.state = "small" : header.state = "details"
0317                     }
0318                 }
0319             }
0320 
0321             Rectangle {
0322                 id: seperator
0323 
0324                 anchors {
0325                     left: parent.left
0326                     right: parent.right
0327                     bottom: parent.bottom
0328                 }
0329 
0330                 height: 1
0331 
0332                 color: Kube.Colors.textColor
0333                 opacity: 0.5
0334             }
0335         }
0336         //END header
0337 
0338         Item {
0339             anchors {
0340                 left: parent.left
0341                 right: parent.right
0342             }
0343             id: buttonContainer
0344             //We're not setting visible, because setting the parent property (of buttonContainer),
0345             //while also depending on the child-property values (htmlButton and attachments) does not work.
0346             height: (attachments.visible || htmlButton.visible) ? Math.max(attachments.height, htmlButton.height) : 0
0347             Kube.TextButton {
0348                 id: htmlButton
0349                 objectName: "htmlButton"
0350                 anchors {
0351                     left: parent.left
0352                     top: parent.top
0353                 }
0354                 opacity: 0.5
0355                 visible: root.partModel ? root.partModel.containsHtml : false
0356                 text: root.partModel ? (root.partModel.showHtml ? "Plain" : "Html") : ""
0357                 onClicked: {
0358                     root.partModel.showHtml = !root.partModel.showHtml
0359                 }
0360             }
0361 
0362             Flow {
0363                 id: attachments
0364 
0365                 anchors {
0366                     left: parent.left
0367                     right: parent.right
0368                 }
0369 
0370                 width: header.width - Kube.Units.largeSpacing
0371                 height: visible ? implicitHeight : 0
0372 
0373                 layoutDirection: Qt.RightToLeft
0374                 spacing: Kube.Units.smallSpacing
0375                 clip: true
0376                 visible: attachmentRepeater.count
0377 
0378                 Repeater {
0379                     id: attachmentRepeater
0380                     model: root.attachmentModel
0381 
0382                     delegate: AttachmentDelegate {
0383                         name: model.name
0384                         type: model.type
0385                         icon: model.iconName
0386 
0387                         clip: true
0388 
0389                         actionIcon: Kube.Icons.save_inverted
0390                         actionTooltip: qsTr("Save attachment")
0391                         onExecute: root.attachmentModel.saveAttachmentToDisk(root.attachmentModel.index(index, 0))
0392                         onClicked: root.attachmentModel.openAttachment(root.attachmentModel.index(index, 0))
0393                         onPublicKeyImport: root.attachmentModel.importPublicKey(root.attachmentModel.index(index, 0))
0394                     }
0395                 }
0396             }
0397         }
0398 
0399         Item {
0400             id: body
0401 
0402             visible: true
0403             anchors {
0404                 left: parent.left
0405                 right: parent.right
0406             }
0407             height: visible ? mailViewer.height + 20 : 0
0408             MPV.MailPartView {
0409                 id: mailViewer
0410                 objectName: "mailViewer"
0411                 anchors.top: body.top
0412                 anchors.left: body.left
0413                 anchors.right: body.right
0414                 model: root.partModel
0415             }
0416 
0417         }
0418 
0419         Kube.Label {
0420             id: busyBody
0421             anchors {
0422                 left: parent.left
0423                 right: parent.right
0424             }
0425             visible: false
0426             height: visible ? implicitHeight : 0
0427             text: root.busyMessage
0428             color: Kube.Colors.textColor
0429             enabled: false
0430         }
0431 
0432         Kube.IconButton {
0433             id: collapsedBody
0434             anchors {
0435                 left: parent.left
0436                 right: parent.right
0437             }
0438             visible: false
0439             enabled: false
0440             iconName: Kube.Icons.goDown
0441         }
0442 
0443         Kube.TextButton {
0444             anchors {
0445                 left: parent.left
0446             }
0447             width: Kube.Units.gridUnit
0448             height: Kube.Units.gridUnit
0449             padding: 0
0450             visible: root.partModel && root.partModel.isTrimmed && !root.collapsed
0451             // Center dots instead of ...
0452             text: "\u00B7\u00B7\u00B7"
0453             opacity: 50
0454             onClicked: {
0455                 root.partModel.trimMail = !root.partModel.trimMail
0456             }
0457         }
0458 
0459         Item {
0460             id: footer
0461             property var mail: root.mail
0462             property string subject: root.subject
0463 
0464             anchors {
0465                 left: parent.left
0466                 right: parent.right
0467             }
0468 
0469             visible: true
0470             height: visible ? Kube.Units.gridUnit : 0
0471             width: parent.width
0472 
0473             Kube.TextButton {
0474                 anchors{
0475                     verticalCenter: parent.verticalCenter
0476                     left: parent.left
0477                 }
0478                 activeFocusOnTab: false
0479 
0480                 text: root.trash ? qsTr("Delete Mail") : root.draft ? qsTr("Discard") : qsTr("Move to trash")
0481                 opacity: 0.5
0482                 onClicked: {
0483                     if (root.trash) {
0484                         Kube.Fabric.postMessage(Kube.Messages.remove, {"mail": root.mail})
0485                     } else {
0486                         Kube.Fabric.postMessage(Kube.Messages.moveToTrash, {"mail": root.mail})
0487                     }
0488                 }
0489             }
0490 
0491             Row {
0492                 anchors {
0493                     verticalCenter: parent.verticalCenter
0494                     right: parent.right
0495                 }
0496                 spacing: Kube.Units.smallSpacing
0497 
0498                 Kube.Button {
0499                     visible: !root.trash && !root.draft
0500                     activeFocusOnTab: false
0501 
0502                     text: qsTr("Share")
0503                     onClicked: {
0504                         Kube.Fabric.postMessage(Kube.Messages.forward, {"mail": root.mail})
0505                     }
0506                 }
0507 
0508                 Kube.Button {
0509                     visible: !root.trash
0510                     activeFocusOnTab: false
0511 
0512                     text: root.draft ? qsTr("Edit") : qsTr("Reply")
0513                     onClicked: {
0514                         if (root.draft) {
0515                             Kube.Fabric.postMessage(Kube.Messages.edit, {"mail": root.mail})
0516                         } else {
0517                             Kube.Fabric.postMessage(Kube.Messages.reply, {"mail": root.mail})
0518                         }
0519                     }
0520                 }
0521                 Row {
0522                     Kube.ExtensionPoint {
0523                         extensionPoint: "extensions/mailview"
0524                         context: {"mail": footer.mail, "subject": footer.subject, "accountId": Kube.Context.currentAccountId}
0525                     }
0526                 }
0527             }
0528         }
0529     } //ColumnLayout
0530 
0531     //Dimm unread messages (but never treat messages as unread that we have sent ourselves)
0532     Rectangle {
0533         anchors.fill: parent
0534         color: Kube.Colors.buttonColor
0535         opacity: 0.4
0536         visible: root.unread && !root.sent
0537     }
0538 
0539     Component {
0540         id: debugPopupComponent
0541         Kube.Popup {
0542             id: debugPopup
0543             modal: true
0544             parent: ApplicationWindow.overlay
0545             closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
0546             x: (parent.width - width)/2
0547             y: Kube.Units.largeSpacing
0548             width: parent.width / 2
0549             height: parent.height - Kube.Units.largeSpacing * 2
0550             clip: true
0551 
0552             Flickable {
0553                 id: flickable
0554                 anchors.fill: parent
0555                 ScrollBar.vertical: Kube.ScrollBar {}
0556                 contentHeight: content.height
0557                 contentWidth: parent.width
0558                 Column {
0559                     id: content
0560                     width: flickable.width
0561                     height: childrenRect.height
0562 
0563                     TextEdit {
0564                         id: structure
0565                         width: parent.width
0566                         readOnly: true
0567                         selectByMouse: true
0568                         textFormat: TextEdit.PlainText
0569                         wrapMode: TextEdit.Wrap
0570                         height: implicitHeight
0571                         text: messageParser.structureAsString
0572                     }
0573 
0574                     TextEdit {
0575                         id: rawContent
0576                         width: parent.width
0577                         readOnly: true
0578                         selectByMouse: true
0579                         textFormat: TextEdit.PlainText
0580                         wrapMode: TextEdit.Wrap
0581                         height: implicitHeight
0582                         text: messageParser.rawContent.substring(0, 100000) //The TextEdit deals poorly with messages that are too large.
0583                     }
0584                     Rectangle {
0585                         color: "black"
0586                         height: 2
0587                     }
0588                     Controls1.TreeView {
0589                         id: mailStructure
0590                         width: parent.width
0591                         height: implicitHeight
0592                         Controls1.TableViewColumn {
0593                             role: "type"
0594                             title: "Type"
0595                         }
0596                         Controls1.TableViewColumn {
0597                             role: "embedded"
0598                             title: "Embedded"
0599                         }
0600                         Controls1.TableViewColumn {
0601                             role: "securityLevel"
0602                             title: "SecurityLevel"
0603                         }
0604                         Controls1.TableViewColumn {
0605                             role: "content"
0606                             title: "Content"
0607                         }
0608                         model: messageParser.parts
0609                         itemDelegate: Item {
0610                             property variant currentData: styleData.value
0611                             Text {
0612                                 anchors.fill: parent
0613                                 color: styleData.textColor
0614                                 elide: Text.ElideRight
0615                                 text: styleData.value ? styleData.value : ""
0616                                 textFormat: Text.PlainText
0617                             }
0618                             MouseArea {
0619                                 anchors.fill: parent
0620                                 onClicked: {
0621                                     textEdit.text = styleData.value
0622                                 }
0623                             }
0624                         }
0625                     }
0626                     Controls1.TreeView {
0627                         id: attachmentsTree
0628                         width: parent.width
0629                         height: implicitHeight
0630                         Controls1.TableViewColumn {
0631                             role: "type"
0632                             title: "Type"
0633                         }
0634                         Controls1.TableViewColumn {
0635                             role: "name"
0636                             title: "Name"
0637                         }
0638                         Controls1.TableViewColumn {
0639                             role: "size"
0640                             title: "Size"
0641                         }
0642                         model: messageParser.attachments
0643                     }
0644                     TextEdit {
0645                         id: textEdit
0646                         width: parent.width
0647                         readOnly: true
0648                         selectByMouse: true
0649                         textFormat: TextEdit.PlainText
0650                         wrapMode: TextEdit.Wrap
0651                         height: implicitHeight
0652                     }
0653                 }
0654             }
0655             Kube.ScrollHelper {
0656                 id: scrollHelper
0657                 flickable: flickable
0658                 anchors.fill: parent
0659             }
0660         }
0661     }
0662 }