Warning, /pim/kube/docs/design.md is written in an unsupported language. File is not indexed.
0001 # Architecture / Design 0002 0003 ## Overview 0004 Kube is supposed to be a small and concise codebase that is easy to modify and evolve. 0005 0006 It's following a reactive model, where in one direction we have actions generating modifications, and in the other direction models updating themselves on changes. 0007 0008 The overall architecture is split into three layers; Ui, Domain Logic and Infrastructure. 0009 0010 ``` 0011 +----------------------------+ 0012 | UI Components | 0013 +----------------------------+ 0014 | | 0015 | Domain Logic | 0016 | Fabric/Models | 0017 | | 0018 +--------------+------+------+ 0019 | | | | 0020 | Sink |Config| ... | 0021 | | | | 0022 +--------------+------+------+ 0023 ``` 0024 0025 The UI Layer consists of views (mostly written in QML), view-models (models that are view specific and potentially implement user interaction details), and the glue code to use various models and actions from the interface. Different UI layers may exist for different form factors. 0026 0027 The domain logic layer holds the application state. It povides models to access data and actions to act upon it. The domain logic is by definition Kube specific and not sharable with other applications, as it needs to be taylored exactly according to the requirements of Kube. 0028 0029 The infrastructure layer provides: 0030 0031 * Data access (Sink) 0032 * Configuration (Config files, etc.) 0033 * Various functionality provided by libraries (email sending, ldap, iTip handling, iCal implementation (kcalcore), vCard implementation, ...) 0034 Various bits of the infrastructure layer may be exchanged on different platforms, to i.e. integrate into native infrastructure providers on a platform. 0035 0036 ## UI / Application 0037 The UI / Application layer contains all the view components, and their composition, that make up the application. 0038 All the interactions between the different components are defined here. 0039 0040 ## Components 0041 The application consists of various application components. A component could be a maillist, an event-editor or the complete kube-mail application. Each component is instantiable on it's own, and has an API to interact with it. The API i.e. allows to set a folder for the maillist, or an event for the event-editor. Components can be nested (a component can instantiate another component) 0042 0043 A component primarily is a QML UI. 0044 0045 The QML UI is built on top of: 0046 0047 * One or more models that are instantiated to provide the data. 0048 * The fabric to interconnect the components. 0049 0050 ## Component interaction / Fabric 0051 The application is made up of various nested components that often need to interact with each other. 0052 0053 This interaction is wired up using the Fabric. 0054 0055 The fabric is a pub/sub messagebus that is orthogonal to the visual hierarchy, that can be used to wire up varius parts of the UI 0056 where a regular property binding would become problematic. 0057 0058 For more information see: https://cmollekopf.wordpress.com/2017/06/06/kubefabric/ 0059 0060 If we look at the example of the org.kube.mail component: 0061 1. The folderlist-component posts to the fabric that current folder has changed. The maillist reacts to that change and sets it's parentFolder property to display the mails of the currently selected folder. 0062 2. The "add-note" message might either switch to the org.kube.note application as currently displayed component, or it might just display a quick-note widget directly inline. 0063 0064 This makes it possible for i.e. a maillist to display a note-widget directly inline, or letting the parent component handle the action to show a full note editor. If nothing handles the action, the root component (the shell)can switch to the note application component. 0065 0066 ## Third party users of components 0067 Since components are self contained and made available as QML plugins, external applications can load fully functional Kube components. 0068 0069 For example, the KDE calendar plasmoid could load the Kube Event Viewer component when available, and thus provide Kube's full functionality of that component, including all actions etc, without having to reimplement the Domain Logic (as is the case if only data access is provided through Sink). 0070 0071 ## Domain Logic 0072 0073 ### Models 0074 Self-updating models are used to implement the read-only part of the application. 0075 By using QAbstractItemModels we can reuse the existing update mechanism, have something that works well with QML, and avoid implementing a boatload of boilerplate code for hand-coded domain objects. 0076 0077 Models should always be reactive and configured with a query, so they are asynchronous. 0078 0079 By implementing everything according to that model we can later on achieve lazy-loading of properties and zero-copy (or at least close to zero-copy) directly from storage without modifying anything besides data access. 0080 0081 Models are self contained and have an API to set i.e. a query for what to load. Models can load data from anywhere. Typically models are implemented in C++ to interface with the rest of the system, but some models may also be implemented directly in QML. 0082 0083 ### Controller 0084 Controllers are used to interact with the system. The controller is a QObject with a QObject-property for every property that should be editable, and a QValidator for every property, so editors can easily be built using property binding while providing property-level validation and feedback. 0085 0086 The domain object is exposed as an opaque QVariant. This way details from the infrastructure layer don't leak to the UI layer 0087 0088 Controllers may interact with infrastructure directly or via the fabric. 0089 0090 ### Notifications 0091 The system will provide notifications from various sources. 0092 0093 Notifications could be: 0094 0095 * New mails arrived 0096 * An error occurred 0097 * A synchronization is in progress 0098 * ... 0099 0100 Notifications can be displayed in various places of the application and are transported over the Fabric. 0101 0102 ## Infrastructure 0103 The infrastructure layer interfaces with the rest of the system. It is the place where we can integrate with various native infrastructure parts. 0104 The interface of the infrastructure layer, that is used by the domain logic, may not expose any implementation details of any infrastructure part, to ensure that all infrastructure parts are exchangable. 0105 0106 ### Sink 0107 Sink is used for primary data access and handles all synchronization. 0108 0109 Interactions with Sink involve: 0110 0111 * Adding/removing/configuring resources 0112 * Triggering synchronization 0113 * Querying of data 0114 * Creating/Modifying/Removing entities 0115 0116 ### Configuration 0117 Configuration as traditionally stored in config files in ~/.config 0118 0119 ### Notification 0120 Notifications for the system. 0121 0122 ### Files 0123 Store/Load/Shared stuff (attachments, events, ....) 0124 * Additional to the basic store/load stuff that may need further abstraction for mobile platforms beyond what qt provides. 0125 * Android Intents/Libpurpose (share with various applications etc). 0126 0127 ### Import/Export 0128 Same as files? Import/Export calendar data 0129 0130 ### RFC implementations 0131 * iCal: KCalendarCore 0132 * vCard: KContacts 0133 * iTip: extract from kdepim repo 0134 * SMTP: based on libcurl 0135 0136 ### Cryptography 0137 0138 Encryption is based on GpgME and uses the systems gpg keyring. 0139 Please note that Kube does not currently manage your key, and retrieves a key matching your email address (gpg2 --list-secret-keys youremail@example.com) 0140 0141 ### MIME-Message parsing 0142 * KMime 0143 0144 ## Testing 0145 0146 TBD 0147 0148 ## Configuration and Accounts 0149 Kube is a groupware application, so one of its most important features is being able to work with various remote backends. We live in a world of multiple devies and applications, so it is interesting to share as much state and configuration accross all different devices and applications, which is why we try to store as much of that in the backend. 0150 0151 From the perspective of Kube we are working with different "Accounts". Each account represents a different backend, such as your personal IMAP or Kolab server, or a hosted offering such as GMail or Kolab Now. Each of those accounts may interact with various protocols such as imap, smtp, ldap, caldav etc. 0152 0153 To add support for a new backend thus means that a new account type has to be added to Kube. 0154 0155 An account consists of: 0156 0157 * One or more sink resources to access the remote data 0158 * A configuration UI in QML that can be embedded in the accounts setup 0159 * Potentially custom action handlers if the default action handlers are not sufficient. 0160 * A configuration controller to modify and access the data 0161 * A set of action pre-handler to supply the configuration to actions 0162 0163 ### Configuration Controller 0164 The configuraton controller is not only used in the configuration UI to provide the data, but it is also used by the rest of the system to access configuration of this account. 0165 0166 This allows the account to retrieve configruation data on a property-by-property basis i.e. from Sink or a local config file. 0167 0168 ### Accounts-Plugin 0169 The account is supplied as a plugin. The plugin is loaded into kube directly from QML. The plugin registers it's configuration controller and potentially actions. 0170 0171 Note: We could have a plugin mechanism that discovers account-plugins should that become necessary at some point. 0172 0173 ## Application Context 0174 Various parts of the system are context sensitive. I.e. the currently selected account affects which transport is used to send an email, or which folders are currently visble. 0175 0176 In future iterations that context can be expanded i.e. with projects that affect prioritization of various data items. 0177 0178 The application context is globally available, although it may be altered locally. 0179 0180 ## Focus handling 0181 This section lines out how we deal with focus throughout the application. 0182 The aim is to have consistent behaviour across controls and other elements. 0183 0184 The focus handling needs to take into account: 0185 0186 * Mouse navigation 0187 * Keyboard navigation 0188 * Touch input 0189 0190 The primary indicator for focus is the "activeFocus" property (or if available, "visualFocus"). The "focus" property is used for requesting focus and thus not what should be used for detecting focus. 0191 0192 There are the following different focus states: 0193 * An element can be selected (if selectable). This includes i.e. a text editor that has focus, or a selectable element in a list view. 0194 * An element can be hovered. This is only available with mouse pointers and indicates that the element can be clicked. 0195 * An element can have keyboard focus. This is only available with keyboard navigation and indicates which element currently has keyboard focus. 0196 0197 With touch input only the selected state is relevant. 0198 0199 The following indicators are available to visualize selection: 0200 * Highlight: A overlay over the item in the highlight color. 0201 * Border: A border around the item in highlight color. 0202 * Underlined text 0203 0204 It is important that a selected element can still show focus, otherwise the focus during keyboard navigation simply disappears if it moves to the selected element. 0205 0206 The following controls need to deal with focus: 0207 * Buttons, IconButtons 0208 * ListView, TreeView, GridView 0209 * TextFields 0210 * Copyable elements 0211 0212 We're indicating focus as follows: 0213 * Active focus is indicated with a border. This is used for both hovering and keyboard focus. 0214 * A selected element is highlighted. 0215 0216 ### FocusScope 0217 In order to be able to deal with focus on a local scope (which is important for reusable components), a FocusScope is required to establish a border for focus handling. Internally you can set the focus as required within the focus scope, and externally you can just give focus to the FocusScope, ignoring what's going to happen internally. The FocusScope will automatically forward focus (when it receives it), to whatever element requested focus internally. 0218 0219 ### Tab focus chain 0220 Set "activeFocusOnTab: true" on all elements that should be included in the tab focus chain.