Merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/desktop-support2 into lp:ubuntu-docviewer-app
- desktop-support2
- Merge into lo-viewer
| Status: | Rejected |
|---|---|
| Rejected by: | Stefano Verzegnassi |
| Proposed branch: | lp:~verzegnassi-stefano/ubuntu-docviewer-app/desktop-support2 |
| Merge into: | lp:ubuntu-docviewer-app |
| Diff against target: |
2206 lines (+1637/-262) 31 files modified
README-Developers.md (+4/-1) click/docviewer.apparmor (+3/-2) debian/control (+3/-1) src/app/qml/common/ContentHubProxy.qml (+5/-5) src/app/qml/common/DetailsPage.qml (+2/-2) src/app/qml/common/PickImportedDialog.qml (+1/-1) src/app/qml/loView/LOViewDefaultHeader.qml (+1/-1) src/app/qml/loView/LOViewPage.qml (+1/-1) src/app/qml/pdfView/PdfPresentation.qml (+1/-1) src/app/qml/pdfView/PdfView.qml (+1/-1) src/app/qml/textView/TextView.qml (+1/-1) src/app/qml/ubuntu-docviewer-app.qml (+8/-1) src/plugin/file-qml-plugin/CMakeLists.txt (+27/-2) src/plugin/file-qml-plugin/InputInfo/CMakeLists.txt (+39/-0) src/plugin/file-qml-plugin/InputInfo/linux/qinputdeviceinfo_linux.cpp (+288/-0) src/plugin/file-qml-plugin/InputInfo/linux/qinputdeviceinfo_linux_p.h (+98/-0) src/plugin/file-qml-plugin/InputInfo/plugin.cpp (+32/-0) src/plugin/file-qml-plugin/InputInfo/plugin.h (+30/-0) src/plugin/file-qml-plugin/InputInfo/qdeclarativeinputdevicemodel.cpp (+196/-0) src/plugin/file-qml-plugin/InputInfo/qdeclarativeinputdevicemodel_p.h (+102/-0) src/plugin/file-qml-plugin/InputInfo/qinputinfo.cpp (+270/-0) src/plugin/file-qml-plugin/InputInfo/qinputinfo.h (+143/-0) src/plugin/file-qml-plugin/InputInfo/qmldir (+3/-0) src/plugin/file-qml-plugin/backend.cpp (+22/-11) src/plugin/file-qml-plugin/documentmodel.cpp (+2/-2) src/plugin/file-qml-plugin/docviewerutils.cpp (+0/-184) src/plugin/file-qml-plugin/docviewerutils.h (+0/-45) src/plugin/file-qml-plugin/fileutils.cpp (+174/-0) src/plugin/file-qml-plugin/fileutils.h (+42/-0) src/plugin/file-qml-plugin/ubuntuconvergenceutils.cpp (+82/-0) src/plugin/file-qml-plugin/ubuntuconvergenceutils.h (+56/-0) |
| To merge this branch: | bzr merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/desktop-support2 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Alan Pope πΊπ§π± π¦ (community) | Needs Fixing | ||
| Jenkins Bot | continuous-integration | Needs Fixing | |
| Stefano Verzegnassi | Needs Fixing | ||
| Nicholas Skaggs | Pending | ||
|
Review via email:
|
|||
Commit message
Better desktop/
WORKAROUND: This makes new BottomEdge component fully working on desktop
Description of the change
Better desktop/
WORKAROUND: This makes new BottomEdge component fully working on desktop
| Stefano Verzegnassi (verzegnassi-stefano) wrote : | # |
| Jenkins Bot (ubuntu-core-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:289
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 290. By Stefano Verzegnassi
-
Forgot to 'bzr add' new files
- 291. By Stefano Verzegnassi
-
...and again
| Jenkins Bot (ubuntu-core-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:291
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 292. By Stefano Verzegnassi
-
* Updated README
* Use 'unconfined' template. Apparently there's no other way to get this working...
| Stefano Verzegnassi (verzegnassi-stefano) wrote : | # |
Ok, this requires an unconfined AppArmor template.
No urge to add the missing packages to Jenkins, nor to merge this branch. I hope the bottom edge will be fixed upstream, because it's not currently usable with a mouse (unless we decide to run unconfined)
| Jenkins Bot (ubuntu-core-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:292
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
| Alan Pope πΊπ§π± π¦ (popey) wrote : | # |
I'm concerned about the unconfined nature of this. Normally for some core apps where there's no other way, I'd probably be okay with this. However, as we're now carrying all of LibreOffice, I'm concerned that we're opening ourselves up by having an unconfined copy of LibreOffice potentially able to be exploited by a dodgy document. That's quite a significantly sized attack surface. Especially when we don't generally roll out new builds of the docviewer with security updated LibreOffice builds very regularly.
What do you think? Should we push this feature back until we have a non-unconfined solution?
Should we bring this up with platform team to find some other way to do this?
| Stefano Verzegnassi (verzegnassi-stefano) wrote : | # |
I think so too.
To be fair, we shouldn't have exceptions for accessing to the user's folders too, because of this.
Ideally the platform should provide some service that creates a database with a list of documents, and docviewer should be authorized to access only that database, by default.
When the application asks to access to a specific file, content-hub should mediate the request and ensure that only the single file (or a copy of that file) is accessible.
Anyway, I created this branch a month ago because I thought we were able to release a new version in the store earlier. Also, it wasn't meant to require an unconfined template, but then I discovered that it was broken on the UT platform.
So we can reject this merge proposal.
Let's wait for a fix in the ubuntu-sdk project, it should come soon I guess...
https:/
P.S. If you can ask to the platform team when they expect to release the fix, that would be great. Anyway, all the SDK apps (except addressbook-app) are in the same situation, so I'm not that much worried.
Unmerged revisions
- 292. By Stefano Verzegnassi
-
* Updated README
* Use 'unconfined' template. Apparently there's no other way to get this working... - 291. By Stefano Verzegnassi
-
...and again
- 290. By Stefano Verzegnassi
-
Forgot to 'bzr add' new files
- 289. By Stefano Verzegnassi
-
Added ConvergenceUtils singleton. Improved desktop/pocket desktop support.
Preview Diff
| 1 | === modified file 'README-Developers.md' |
| 2 | --- README-Developers.md 2015-12-21 13:06:52 +0000 |
| 3 | +++ README-Developers.md 2016-02-03 14:19:17 +0000 |
| 4 | @@ -19,11 +19,14 @@ |
| 5 | * Install Qt5 private development files: |
| 6 | sudo apt install qtdeclarative5-private-dev qtbase5-private-dev |
| 7 | |
| 8 | +* Install development files for convergence support: |
| 9 | + sudo apt install libudev-dev libevdev-dev |
| 10 | + |
| 11 | * If you want to compile an arm click package, you need to install that package |
| 12 | to the arm compilation environment. For example when using QtCreator for |
| 13 | Ubuntu Touch, open Options -> Ubuntu -> Maintain, and then enter: |
| 14 | |
| 15 | - apt install libpoppler-qt5-dev:armhf qtdeclarative5-private-dev:armhf qtbase5-private-dev:armhf |
| 16 | + apt install libpoppler-qt5-dev:armhf qtdeclarative5-private-dev:armhf qtbase5-private-dev:armhf libudev-dev:armhf libevdev-dev:armhf |
| 17 | |
| 18 | LibreOffice viewer support |
| 19 | ========================== |
| 20 | |
| 21 | === modified file 'click/docviewer.apparmor' |
| 22 | --- click/docviewer.apparmor 2016-01-29 12:23:24 +0000 |
| 23 | +++ click/docviewer.apparmor 2016-02-03 14:19:17 +0000 |
| 24 | @@ -13,5 +13,6 @@ |
| 25 | "@{HOME}/Documents/", |
| 26 | "/media/*/*/[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt][Ss]/" |
| 27 | ], |
| 28 | - "policy_version": 1.3 |
| 29 | -} |
| 30 | \ No newline at end of file |
| 31 | + "policy_version": 1.3, |
| 32 | + "template": "unconfined" |
| 33 | +} |
| 34 | |
| 35 | === modified file 'debian/control' |
| 36 | --- debian/control 2016-01-14 21:33:47 +0000 |
| 37 | +++ debian/control 2016-02-03 14:19:17 +0000 |
| 38 | @@ -17,7 +17,9 @@ |
| 39 | qtdeclarative5-qtquick2-plugin, |
| 40 | qtdeclarative5-private-dev, |
| 41 | qtbase5-private-dev, |
| 42 | - qtdeclarative5-test-plugin |
| 43 | + qtdeclarative5-test-plugin, |
| 44 | + libudev-dev, |
| 45 | + libevdev-dev, |
| 46 | Standards-Version: 3.9.6 |
| 47 | Section: misc |
| 48 | Homepage: https://launchpad.net/ubuntu-docviewer-app |
| 49 | |
| 50 | === modified file 'src/app/qml/common/ContentHubProxy.qml' |
| 51 | --- src/app/qml/common/ContentHubProxy.qml 2015-10-10 12:03:30 +0000 |
| 52 | +++ src/app/qml/common/ContentHubProxy.qml 2016-02-03 14:19:17 +0000 |
| 53 | @@ -53,11 +53,11 @@ |
| 54 | for (var i=0; i<activeTransfer.items.length; i++) { |
| 55 | var sourcePath = internal.getPathFromUrl(activeTransfer.items[i].url) |
| 56 | |
| 57 | - if (DocumentViewer.isFileSupported(sourcePath)) { |
| 58 | - var documentsLocation = DocumentViewer.getXdgDocumentsLocation() |
| 59 | + if (FileUtils.isFileSupported(sourcePath)) { |
| 60 | + var documentsLocation = FileUtils.getXdgDocumentsLocation() |
| 61 | |
| 62 | // Check if we have already imported the same document in the past. |
| 63 | - var earlierImportedFile = DocumentViewer.checkIfFileAlreadyImported(sourcePath, [documentsLocation]) |
| 64 | + var earlierImportedFile = FileUtils.checkIfFileAlreadyImported(sourcePath, [documentsLocation]) |
| 65 | if (earlierImportedFile.length > 0) { |
| 66 | // Document has been already imported in the past. |
| 67 | // Append the path of the earlier copy of the |
| 68 | @@ -65,7 +65,7 @@ |
| 69 | importedDocsModel.append({ path: earlierImportedFile }) |
| 70 | } else { |
| 71 | // No document has been found, so we can safely copy it. |
| 72 | - var destPath = DocumentViewer.buildDestinationPath(documentsLocation, sourcePath); |
| 73 | + var destPath = FileUtils.buildDestinationPath(documentsLocation, sourcePath); |
| 74 | |
| 75 | internal.importDocument(sourcePath, destPath) |
| 76 | } |
| 77 | @@ -120,7 +120,7 @@ |
| 78 | } |
| 79 | |
| 80 | function importDocument(sourcePath, destPath) { |
| 81 | - DocumentViewer.copy(sourcePath, destPath) |
| 82 | + FileUtils.copy(sourcePath, destPath) |
| 83 | importedDocsModel.append({ path: destPath }) |
| 84 | } |
| 85 | |
| 86 | |
| 87 | === modified file 'src/app/qml/common/DetailsPage.qml' |
| 88 | --- src/app/qml/common/DetailsPage.qml 2015-12-27 12:10:06 +0000 |
| 89 | +++ src/app/qml/common/DetailsPage.qml 2016-02-03 14:19:17 +0000 |
| 90 | @@ -40,12 +40,12 @@ |
| 91 | |
| 92 | SubtitledListItem { |
| 93 | text: i18n.tr("File") |
| 94 | - subText: DocumentViewer.getFileNameFromPath(file.path) |
| 95 | + subText: FileUtils.getFileNameFromPath(file.path) |
| 96 | } |
| 97 | |
| 98 | SubtitledListItem { |
| 99 | text: i18n.tr("Location") |
| 100 | - subText: DocumentViewer.getCanonicalPath(file.path) |
| 101 | + subText: FileUtils.getCanonicalPath(file.path) |
| 102 | } |
| 103 | |
| 104 | SubtitledListItem { |
| 105 | |
| 106 | === modified file 'src/app/qml/common/PickImportedDialog.qml' |
| 107 | --- src/app/qml/common/PickImportedDialog.qml 2015-12-26 18:27:13 +0000 |
| 108 | +++ src/app/qml/common/PickImportedDialog.qml 2016-02-03 14:19:17 +0000 |
| 109 | @@ -40,7 +40,7 @@ |
| 110 | } |
| 111 | |
| 112 | Label { |
| 113 | - text: DocumentViewer.getFileBaseNameFromPath(model.path) |
| 114 | + text: FileUtils.getFileBaseNameFromPath(model.path) |
| 115 | anchors { |
| 116 | left: parent.left; right: parent.right |
| 117 | margins: units.gu(2) |
| 118 | |
| 119 | === modified file 'src/app/qml/loView/LOViewDefaultHeader.qml' |
| 120 | --- src/app/qml/loView/LOViewDefaultHeader.qml 2015-11-30 12:12:10 +0000 |
| 121 | +++ src/app/qml/loView/LOViewDefaultHeader.qml 2016-02-03 14:19:17 +0000 |
| 122 | @@ -73,7 +73,7 @@ |
| 123 | Layout.preferredHeight: units.gu(4) |
| 124 | |
| 125 | view: targetPage.contentItem.loView |
| 126 | - visible: targetPage.contentItem && (DocumentViewer.desktopMode || mainView.wideWindow) |
| 127 | + visible: targetPage.contentItem && (ConvergenceUtils.desktopMode || mainView.wideWindow) |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | |
| 132 | === modified file 'src/app/qml/loView/LOViewPage.qml' |
| 133 | --- src/app/qml/loView/LOViewPage.qml 2016-01-29 12:12:54 +0000 |
| 134 | +++ src/app/qml/loView/LOViewPage.qml 2016-02-03 14:19:17 +0000 |
| 135 | @@ -32,7 +32,7 @@ |
| 136 | property bool isTextDocument: loPage.contentItem && (loPage.contentItem.loDocument.documentType === LibreOffice.Document.TextDocument) |
| 137 | property bool isSpreadsheet: loPage.contentItem && (loPage.contentItem.loDocument.documentType === LibreOffice.Document.SpreadsheetDocument) |
| 138 | |
| 139 | - title: DocumentViewer.getFileBaseNameFromPath(file.path); |
| 140 | + title: FileUtils.getFileBaseNameFromPath(file.path); |
| 141 | flickable: isTextDocument ? loPage.contentItem.loView : null |
| 142 | |
| 143 | splashScreen: Splashscreen { } |
| 144 | |
| 145 | === modified file 'src/app/qml/pdfView/PdfPresentation.qml' |
| 146 | --- src/app/qml/pdfView/PdfPresentation.qml 2016-01-23 12:34:25 +0000 |
| 147 | +++ src/app/qml/pdfView/PdfPresentation.qml 2016-02-03 14:19:17 +0000 |
| 148 | @@ -24,7 +24,7 @@ |
| 149 | property var poppler |
| 150 | property bool isPresentation: true |
| 151 | anchors.fill: parent |
| 152 | - title: DocumentViewer.getFileBaseNameFromPath(poppler.path) |
| 153 | + title: FileUtils.getFileBaseNameFromPath(poppler.path) |
| 154 | focus: true |
| 155 | |
| 156 | header: PageHeader { |
| 157 | |
| 158 | === modified file 'src/app/qml/pdfView/PdfView.qml' |
| 159 | --- src/app/qml/pdfView/PdfView.qml 2016-01-29 12:23:24 +0000 |
| 160 | +++ src/app/qml/pdfView/PdfView.qml 2016-02-03 14:19:17 +0000 |
| 161 | @@ -26,7 +26,7 @@ |
| 162 | |
| 163 | Page { |
| 164 | id: pdfPage |
| 165 | - title: DocumentViewer.getFileBaseNameFromPath(file.path) |
| 166 | + title: FileUtils.getFileBaseNameFromPath(file.path) |
| 167 | |
| 168 | header: PageHeader { |
| 169 | flickable: pdfView |
| 170 | |
| 171 | === modified file 'src/app/qml/textView/TextView.qml' |
| 172 | --- src/app/qml/textView/TextView.qml 2015-12-26 18:27:13 +0000 |
| 173 | +++ src/app/qml/textView/TextView.qml 2016-02-03 14:19:17 +0000 |
| 174 | @@ -23,7 +23,7 @@ |
| 175 | |
| 176 | Page { |
| 177 | id: textPage |
| 178 | - title: DocumentViewer.getFileBaseNameFromPath(file.path) |
| 179 | + title: FileUtils.getFileBaseNameFromPath(file.path) |
| 180 | |
| 181 | // Reset night mode shader settings when closing the page |
| 182 | // Component.onDestruction: mainView.nightModeEnabled = false |
| 183 | |
| 184 | === modified file 'src/app/qml/ubuntu-docviewer-app.qml' |
| 185 | --- src/app/qml/ubuntu-docviewer-app.qml 2016-01-14 13:07:09 +0000 |
| 186 | +++ src/app/qml/ubuntu-docviewer-app.qml 2016-02-03 14:19:17 +0000 |
| 187 | @@ -80,7 +80,7 @@ |
| 188 | onIsLandscapeChanged: { |
| 189 | // If device orientation is landscape and screen width is limited, |
| 190 | // force hiding Unity 8 indicators panel. |
| 191 | - if (!DocumentViewer.desktopMode && mainView.isLandscape && |
| 192 | + if (!ConvergenceUtils.desktopMode && mainView.isLandscape && |
| 193 | mainView.width < units.gu(51)) { |
| 194 | mainView.fullscreen = true |
| 195 | return; |
| 196 | @@ -202,6 +202,13 @@ |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | + // WORKAROUND: Not yet implemented in the SDK |
| 201 | + Binding { |
| 202 | + target: QuickUtils |
| 203 | + property: "mouseAttached" |
| 204 | + value: ConvergenceUtils.mouseAttached |
| 205 | + } |
| 206 | + |
| 207 | property bool nightModeEnabled: false |
| 208 | layer.effect: NightModeShader {} |
| 209 | layer.enabled: nightModeEnabled && (pageStack.depth > 1) && !pageStack.currentPage.isPresentation |
| 210 | |
| 211 | === modified file 'src/plugin/file-qml-plugin/CMakeLists.txt' |
| 212 | --- src/plugin/file-qml-plugin/CMakeLists.txt 2015-10-21 13:16:12 +0000 |
| 213 | +++ src/plugin/file-qml-plugin/CMakeLists.txt 2016-02-03 14:19:17 +0000 |
| 214 | @@ -1,23 +1,48 @@ |
| 215 | +# This includes a temporary snapshot of the WIP QInputInfo API as we |
| 216 | +# require this in docviewer now but upstream isn't finished yet. |
| 217 | +# Eventually this should be dropped in favor of the upstream |
| 218 | +# QInputInfo API. |
| 219 | + |
| 220 | set(PLUGIN_DIR DocumentViewer) |
| 221 | -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) |
| 222 | |
| 223 | find_package(Qt5Core) |
| 224 | find_package(Qt5Qml) |
| 225 | find_package(Qt5Quick) |
| 226 | |
| 227 | +pkg_check_modules(LIBUDEV REQUIRED libudev) |
| 228 | +pkg_check_modules(LIBEVDEV REQUIRED libevdev) |
| 229 | + |
| 230 | +include_directories( |
| 231 | + ${CMAKE_CURRENT_SOURCE_DIR} |
| 232 | + ${LIBUDEV_INCLUDE_DIRS} |
| 233 | + ${LIBEVDEV_INCLUDE_DIRS} |
| 234 | + InputInfo/ |
| 235 | +) |
| 236 | + |
| 237 | +# QInputInfo sources |
| 238 | +set(inputinfo_SRCS |
| 239 | + InputInfo/qinputinfo.cpp |
| 240 | + InputInfo/qinputinfo.h |
| 241 | + InputInfo/linux/qinputdeviceinfo_linux.cpp |
| 242 | + InputInfo/linux/qinputdeviceinfo_linux_p.h |
| 243 | +) |
| 244 | + |
| 245 | #add the sources to compile |
| 246 | set(fileqmlplugin_SRCS |
| 247 | backend.cpp |
| 248 | documentmodel.cpp |
| 249 | fswatcher.cpp |
| 250 | docviewerfile.cpp |
| 251 | - docviewerutils.cpp |
| 252 | + fileutils.cpp |
| 253 | + ubuntuconvergenceutils.cpp |
| 254 | ) |
| 255 | |
| 256 | add_library(fileqmlplugin MODULE |
| 257 | + ${inputinfo_SRCS} |
| 258 | ${fileqmlplugin_SRCS} |
| 259 | ) |
| 260 | |
| 261 | +target_link_libraries(fileqmlplugin ${LIBUDEV_LDFLAGS} ${LIBEVDEV_LDFLAGS} ) |
| 262 | qt5_use_modules(fileqmlplugin Qml Quick) |
| 263 | |
| 264 | # Copy the plugin, the qmldir file and other assets to the build dir for running in QtCreator |
| 265 | |
| 266 | === added directory 'src/plugin/file-qml-plugin/InputInfo' |
| 267 | === added file 'src/plugin/file-qml-plugin/InputInfo/CMakeLists.txt' |
| 268 | --- src/plugin/file-qml-plugin/InputInfo/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
| 269 | +++ src/plugin/file-qml-plugin/InputInfo/CMakeLists.txt 2016-02-03 14:19:17 +0000 |
| 270 | @@ -0,0 +1,39 @@ |
| 271 | +# This is a temporary snapshot of the WIP QInputInfo API as we |
| 272 | +# require this in unity now but upstream isn't finished yet. |
| 273 | +# Eventually this should be dropped in favor of the upstream |
| 274 | +# QInputInfo API. |
| 275 | + |
| 276 | +project(InputInfo) |
| 277 | + |
| 278 | +find_package(Qt5Core REQUIRED) |
| 279 | +find_package(Qt5Quick REQUIRED) |
| 280 | + |
| 281 | +pkg_check_modules(LIBUDEV REQUIRED libudev) |
| 282 | +pkg_check_modules(LIBEVDEV REQUIRED libevdev) |
| 283 | + |
| 284 | +include_directories( |
| 285 | + ${CMAKE_CURRENT_SOURCE_DIR} |
| 286 | + ${CMAKE_CURRENT_BINARY_DIR} |
| 287 | + ${LIBUDEV_INCLUDE_DIRS} |
| 288 | + ${LIBEVDEV_INCLUDE_DIRS} |
| 289 | +) |
| 290 | + |
| 291 | +set(InputInfo_SOURCES |
| 292 | + plugin.cpp |
| 293 | + qinputinfo.cpp |
| 294 | + qdeclarativeinputdevicemodel.cpp |
| 295 | + linux/qinputdeviceinfo_linux.cpp |
| 296 | +) |
| 297 | + |
| 298 | +add_library(InputInfo SHARED |
| 299 | + ${InputInfo_SOURCES} |
| 300 | +) |
| 301 | + |
| 302 | +target_link_libraries(InputInfo |
| 303 | + ${LIBUDEV_LDFLAGS} |
| 304 | + ${LIBEVDEV_LDFLAGS} |
| 305 | +) |
| 306 | + |
| 307 | +qt5_use_modules(InputInfo Core Qml Quick) |
| 308 | + |
| 309 | +add_unity8_plugin(Unity.InputInfo 0.1 Unity/InputInfo TARGETS InputInfo) |
| 310 | |
| 311 | === added directory 'src/plugin/file-qml-plugin/InputInfo/linux' |
| 312 | === added file 'src/plugin/file-qml-plugin/InputInfo/linux/qinputdeviceinfo_linux.cpp' |
| 313 | --- src/plugin/file-qml-plugin/InputInfo/linux/qinputdeviceinfo_linux.cpp 1970-01-01 00:00:00 +0000 |
| 314 | +++ src/plugin/file-qml-plugin/InputInfo/linux/qinputdeviceinfo_linux.cpp 2016-02-03 14:19:17 +0000 |
| 315 | @@ -0,0 +1,288 @@ |
| 316 | +/**************************************************************************** |
| 317 | +** |
| 318 | +** Copyright (C) 2014 Canonical, Ltd. and/or its subsidiary(-ies). |
| 319 | +** Contact: http://www.qt-project.org/legal |
| 320 | +** |
| 321 | +** This file is part of the QtSystems module of the Qt Toolkit. |
| 322 | +** |
| 323 | +** $QT_BEGIN_LICENSE:LGPL$ |
| 324 | +** Commercial License Usage |
| 325 | +** Licensees holding valid commercial Qt licenses may use this file in |
| 326 | +** accordance with the commercial license agreement provided with the |
| 327 | +** Software or, alternatively, in accordance with the terms contained in |
| 328 | +** a written agreement between you and Digia. For licensing terms and |
| 329 | +** conditions see http://qt.digia.com/licensing. For further information |
| 330 | +** use the contact form at http://qt.digia.com/contact-us. |
| 331 | +** |
| 332 | +** GNU Lesser General Public License Usage |
| 333 | +** Alternatively, this file may be used under the terms of the GNU Lesser |
| 334 | +** General Public License version 2.1 as published by the Free Software |
| 335 | +** Foundation and appearing in the file LICENSE.LGPL included in the |
| 336 | +** packaging of this file. Please review the following information to |
| 337 | +** ensure the GNU Lesser General Public License version 2.1 requirements |
| 338 | +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 339 | +** |
| 340 | +** In addition, as a special exception, Digia gives you certain additional |
| 341 | +** rights. These rights are described in the Digia Qt LGPL Exception |
| 342 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 343 | +** |
| 344 | +** GNU General Public License Usage |
| 345 | +** Alternatively, this file may be used under the terms of the GNU |
| 346 | +** General Public License version 3.0 as published by the Free Software |
| 347 | +** Foundation and appearing in the file LICENSE.GPL included in the |
| 348 | +** packaging of this file. Please review the following information to |
| 349 | +** ensure the GNU General Public License version 3.0 requirements will be |
| 350 | +** met: http://www.gnu.org/copyleft/gpl.html. |
| 351 | +** |
| 352 | +** |
| 353 | +** $QT_END_LICENSE$ |
| 354 | +** |
| 355 | +****************************************************************************/ |
| 356 | + |
| 357 | +#include "qinputdeviceinfo_linux_p.h" |
| 358 | + |
| 359 | +#include <libudev.h> |
| 360 | +#include <libevdev/libevdev.h> |
| 361 | +#include <fcntl.h> |
| 362 | +#include <QDebug> |
| 363 | +#include <QSocketNotifier> |
| 364 | +#include <QTimer> |
| 365 | +#include <QDir> |
| 366 | + |
| 367 | +QInputDeviceManagerPrivate::QInputDeviceManagerPrivate(QObject *parent) : |
| 368 | + QObject(parent), |
| 369 | + currentFilter(QInputDevice::Unknown), |
| 370 | + udevice(0) |
| 371 | +{ |
| 372 | + QTimer::singleShot(250,this,SLOT(init())); |
| 373 | +} |
| 374 | + |
| 375 | +QInputDeviceManagerPrivate::~QInputDeviceManagerPrivate() |
| 376 | +{ |
| 377 | + udev_unref(udevice); |
| 378 | + udev_monitor_unref(udevMonitor); |
| 379 | +} |
| 380 | + |
| 381 | +void QInputDeviceManagerPrivate::init() |
| 382 | +{ |
| 383 | + if (!udevice) |
| 384 | + udevice = udev_new(); |
| 385 | + |
| 386 | + udev_list_entry *devices; |
| 387 | + udev_list_entry *dev_list_entry; |
| 388 | + udev_device *dev; |
| 389 | + |
| 390 | + QString subsystem = QStringLiteral("input"); |
| 391 | + struct udev_enumerate *enumerate = 0; |
| 392 | + |
| 393 | + if (udevice) { |
| 394 | + |
| 395 | + udevMonitor = udev_monitor_new_from_netlink(udevice, "udev"); |
| 396 | + udev_monitor_filter_add_match_subsystem_devtype(udevMonitor, subsystem.toLatin1(), NULL); |
| 397 | + enumerate = udev_enumerate_new(udevice); |
| 398 | + udev_enumerate_add_match_subsystem(enumerate, subsystem.toLatin1()); |
| 399 | + |
| 400 | + udev_monitor_enable_receiving(udevMonitor); |
| 401 | + notifierFd = udev_monitor_get_fd(udevMonitor); |
| 402 | + |
| 403 | + notifier = new QSocketNotifier(notifierFd, QSocketNotifier::Read, this); |
| 404 | + connect(notifier, SIGNAL(activated(int)), this, SLOT(onUDevChanges())); |
| 405 | + |
| 406 | + udev_enumerate_scan_devices(enumerate); |
| 407 | + devices = udev_enumerate_get_list_entry(enumerate); |
| 408 | + |
| 409 | + udev_list_entry_foreach(dev_list_entry, devices) { |
| 410 | + const char *path; |
| 411 | + path = udev_list_entry_get_name(dev_list_entry); |
| 412 | + |
| 413 | + dev = udev_device_new_from_syspath(udevice, path); |
| 414 | + if (qstrcmp(udev_device_get_subsystem(dev), "input") == 0 ) { |
| 415 | + QInputDevice *iDevice = addDevice(dev); |
| 416 | + if (iDevice && !iDevice->devicePath().isEmpty()) { |
| 417 | + deviceMap.insert(iDevice->devicePath(),iDevice); |
| 418 | + } |
| 419 | + } |
| 420 | + udev_device_unref(dev); |
| 421 | + } |
| 422 | + udev_enumerate_unref(enumerate); |
| 423 | + } |
| 424 | + // udev_unref(udevice); |
| 425 | + Q_FOREACH (const QString &devicePath, deviceMap.keys()) { |
| 426 | + Q_EMIT deviceAdded(devicePath); |
| 427 | + } |
| 428 | + Q_EMIT ready(); |
| 429 | +} |
| 430 | + |
| 431 | +QInputDevice::InputTypeFlags QInputDeviceManagerPrivate::getInputTypeFlags(struct udev_device *dev) |
| 432 | +{ |
| 433 | + QInputDevice::InputTypeFlags flags = QInputDevice::Unknown; |
| 434 | + if (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_KEY"), "1") == 0 ) { |
| 435 | + flags |= QInputDevice::Button; |
| 436 | + } |
| 437 | + if (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_MOUSE"), "1") == 0) { |
| 438 | + flags |= QInputDevice::Mouse; |
| 439 | + } |
| 440 | + if (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD"), "1") == 0) { |
| 441 | + flags |= QInputDevice::TouchPad; |
| 442 | + } |
| 443 | + if (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN"), "1") == 0 |
| 444 | + || qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_TABLET"), "1") == 0) { |
| 445 | + flags |= QInputDevice::TouchScreen; |
| 446 | + } |
| 447 | + if (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD"), "1") == 0 ) { |
| 448 | + flags |= QInputDevice::Keyboard; |
| 449 | + } |
| 450 | + if (!QString::fromLatin1(udev_device_get_property_value(dev, "SW")).isEmpty()) { |
| 451 | + flags |= QInputDevice::Switch; |
| 452 | + } |
| 453 | + |
| 454 | + return flags; |
| 455 | +} |
| 456 | + |
| 457 | +QInputDevice *QInputDeviceManagerPrivate::addDevice(struct udev_device *udev) |
| 458 | +{ |
| 459 | + QString eventPath = QString::fromLatin1(udev_device_get_sysname(udev)); |
| 460 | + |
| 461 | + if (eventPath.contains(QStringLiteral("event"))) |
| 462 | + eventPath.prepend(QStringLiteral("/dev/input/")); |
| 463 | + |
| 464 | + if (deviceMap.contains(eventPath)) { |
| 465 | + return Q_NULLPTR; |
| 466 | + } |
| 467 | + struct libevdev *dev = NULL; |
| 468 | + int fd; |
| 469 | + int rc = 1; |
| 470 | + QInputDevice *inputDevice; |
| 471 | + inputDevice = addUdevDevice(udev); |
| 472 | + if (!inputDevice) { |
| 473 | + return Q_NULLPTR; |
| 474 | + } |
| 475 | + eventPath = inputDevice->devicePath(); |
| 476 | + |
| 477 | + fd = open(eventPath.toLatin1(), O_RDONLY|O_NONBLOCK); |
| 478 | + if (fd == -1) { |
| 479 | + return inputDevice; |
| 480 | + } |
| 481 | + rc = libevdev_new_from_fd(fd, &dev); |
| 482 | + if (rc < 0) { |
| 483 | + qWarning() << "Failed to init libevdev ("<< strerror(-rc) << ")"; |
| 484 | + return Q_NULLPTR; |
| 485 | + } |
| 486 | + |
| 487 | + for (int i = 0; i < EV_MAX; i++) { |
| 488 | + if (i == EV_KEY || i == EV_SW || i == EV_REL |
| 489 | + || i == EV_REL || i == EV_ABS) { |
| 490 | + for (int j = 0; j < libevdev_event_type_get_max(i); j++) { |
| 491 | + if (libevdev_has_event_code(dev, i, j)) { |
| 492 | + switch (i) { |
| 493 | + case EV_KEY: |
| 494 | + inputDevice->addButton(j); |
| 495 | + break; |
| 496 | + case EV_SW: |
| 497 | + inputDevice->addSwitch(j); |
| 498 | + break; |
| 499 | + case EV_REL: |
| 500 | + inputDevice->addRelativeAxis(j); |
| 501 | + break; |
| 502 | + case EV_ABS: |
| 503 | + inputDevice->addAbsoluteAxis(j); |
| 504 | + break; |
| 505 | + }; |
| 506 | + } |
| 507 | + } |
| 508 | + } |
| 509 | + } |
| 510 | + |
| 511 | + return inputDevice; |
| 512 | +} |
| 513 | + |
| 514 | +void QInputDeviceManagerPrivate::addDetails(struct udev_device *) |
| 515 | +{ |
| 516 | +} |
| 517 | + |
| 518 | +void QInputDeviceManagerPrivate::removeDevice(const QString &path) |
| 519 | +{ |
| 520 | + // this path is not a full evdev path |
| 521 | + Q_FOREACH (const QString devicePath, deviceMap.keys()) { |
| 522 | + if (devicePath.contains(path)) { |
| 523 | + deviceMap.remove(devicePath); |
| 524 | + Q_EMIT deviceRemoved(devicePath); |
| 525 | + } |
| 526 | + } |
| 527 | +} |
| 528 | + |
| 529 | +QInputDevice *QInputDeviceManagerPrivate::addUdevDevice(struct udev_device *udev) |
| 530 | +{ |
| 531 | + QInputDevice *iDevice; |
| 532 | + |
| 533 | + struct udev_list_entry *list; |
| 534 | + struct udev_list_entry *node; |
| 535 | + |
| 536 | + list = udev_device_get_properties_list_entry (udev); |
| 537 | + QString syspath = QString::fromLatin1(udev_device_get_syspath(udev)); |
| 538 | + QDir sysdir(syspath); |
| 539 | + |
| 540 | + QStringList infoList = sysdir.entryList(QStringList() << QStringLiteral("event*"),QDir::Dirs); |
| 541 | + |
| 542 | + if (infoList.count() > 0) { |
| 543 | + QString token = infoList.at(0); |
| 544 | + |
| 545 | + token.prepend(QStringLiteral("/dev/input/")); |
| 546 | + iDevice = new QInputDevice(this); |
| 547 | + iDevice->setDevicePath(token); |
| 548 | + } else { |
| 549 | + return Q_NULLPTR; |
| 550 | + } |
| 551 | + udev_list_entry_foreach (node, list) { |
| 552 | + |
| 553 | + QString key = QString::fromLatin1(udev_list_entry_get_name(node)); |
| 554 | + QString value = QString::fromLatin1(udev_list_entry_get_value(node)); |
| 555 | + |
| 556 | + if (key == QStringLiteral("NAME")) { |
| 557 | + iDevice->setName(value.remove(QStringLiteral("\""))); |
| 558 | + } |
| 559 | + } |
| 560 | + iDevice->setType(getInputTypeFlags(udev)); |
| 561 | + return iDevice; |
| 562 | +} |
| 563 | + |
| 564 | +void QInputDeviceManagerPrivate::onUDevChanges() |
| 565 | +{ |
| 566 | + if (!udevMonitor) |
| 567 | + return; |
| 568 | + |
| 569 | + udev_device *dev = udev_monitor_receive_device(udevMonitor); |
| 570 | + |
| 571 | + if (dev) { |
| 572 | + if (qstrcmp(udev_device_get_subsystem(dev), "input") == 0 ) { |
| 573 | + QString eventPath = QString::fromLatin1(udev_device_get_sysname(dev)); |
| 574 | + |
| 575 | + QString action = QString::fromStdString(udev_device_get_action(dev)); |
| 576 | + |
| 577 | + if (!eventPath.contains(QStringLiteral("/dev/input/"))) |
| 578 | + eventPath.prepend(QStringLiteral("/dev/input/")); |
| 579 | + |
| 580 | + if (action == QStringLiteral("add")) { |
| 581 | + if (deviceMap.contains(eventPath)){ |
| 582 | + udev_device_unref(dev); |
| 583 | + return; |
| 584 | + } |
| 585 | + |
| 586 | + QInputDevice *iDevice = addDevice(dev); |
| 587 | + if (!iDevice) { |
| 588 | + delete iDevice; |
| 589 | + return; |
| 590 | + } |
| 591 | + iDevice->setType(getInputTypeFlags(dev)); |
| 592 | + udev_device_unref(dev); |
| 593 | + |
| 594 | + deviceMap.insert(eventPath,iDevice); |
| 595 | + |
| 596 | + Q_EMIT deviceAdded(eventPath); |
| 597 | + |
| 598 | + } else if (action == QStringLiteral("remove")) { |
| 599 | + removeDevice(eventPath); |
| 600 | + } |
| 601 | + } |
| 602 | + } |
| 603 | +} |
| 604 | |
| 605 | === added file 'src/plugin/file-qml-plugin/InputInfo/linux/qinputdeviceinfo_linux_p.h' |
| 606 | --- src/plugin/file-qml-plugin/InputInfo/linux/qinputdeviceinfo_linux_p.h 1970-01-01 00:00:00 +0000 |
| 607 | +++ src/plugin/file-qml-plugin/InputInfo/linux/qinputdeviceinfo_linux_p.h 2016-02-03 14:19:17 +0000 |
| 608 | @@ -0,0 +1,98 @@ |
| 609 | +/**************************************************************************** |
| 610 | +** |
| 611 | +** Copyright (C) 2014 Canonical, Ltd. and/or its subsidiary(-ies). |
| 612 | +** Contact: http://www.qt-project.org/legal |
| 613 | +** |
| 614 | +** This file is part of the QtSystems module of the Qt Toolkit. |
| 615 | +** |
| 616 | +** $QT_BEGIN_LICENSE:LGPL$ |
| 617 | +** Commercial License Usage |
| 618 | +** Licensees holding valid commercial Qt licenses may use this file in |
| 619 | +** accordance with the commercial license agreement provided with the |
| 620 | +** Software or, alternatively, in accordance with the terms contained in |
| 621 | +** a written agreement between you and Digia. For licensing terms and |
| 622 | +** conditions see http://qt.digia.com/licensing. For further information |
| 623 | +** use the contact form at http://qt.digia.com/contact-us. |
| 624 | +** |
| 625 | +** GNU Lesser General Public License Usage |
| 626 | +** Alternatively, this file may be used under the terms of the GNU Lesser |
| 627 | +** General Public License version 2.1 as published by the Free Software |
| 628 | +** Foundation and appearing in the file LICENSE.LGPL included in the |
| 629 | +** packaging of this file. Please review the following information to |
| 630 | +** ensure the GNU Lesser General Public License version 2.1 requirements |
| 631 | +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 632 | +** |
| 633 | +** In addition, as a special exception, Digia gives you certain additional |
| 634 | +** rights. These rights are described in the Digia Qt LGPL Exception |
| 635 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 636 | +** |
| 637 | +** GNU General Public License Usage |
| 638 | +** Alternatively, this file may be used under the terms of the GNU |
| 639 | +** General Public License version 3.0 as published by the Free Software |
| 640 | +** Foundation and appearing in the file LICENSE.GPL included in the |
| 641 | +** packaging of this file. Please review the following information to |
| 642 | +** ensure the GNU General Public License version 3.0 requirements will be |
| 643 | +** met: http://www.gnu.org/copyleft/gpl.html. |
| 644 | +** |
| 645 | +** |
| 646 | +** $QT_END_LICENSE$ |
| 647 | +** |
| 648 | +****************************************************************************/ |
| 649 | + |
| 650 | +#ifndef QINPUTDEVICEINFO_LINUX_P_H |
| 651 | +#define QINPUTDEVICEINFO_LINUX_P_H |
| 652 | + |
| 653 | +#include <QObject> |
| 654 | +#include "qinputinfo.h" |
| 655 | +#include <libudev.h> |
| 656 | + |
| 657 | +class QInputDevicePrivate : public QObject |
| 658 | +{ |
| 659 | + Q_OBJECT |
| 660 | +public: |
| 661 | + explicit QInputDevicePrivate(QObject *parent = 0); |
| 662 | + |
| 663 | + QString name; |
| 664 | + QString devicePath; |
| 665 | + QList <int> buttons; //keys |
| 666 | + QList <int> switches; |
| 667 | + QList <int> relativeAxis; |
| 668 | + QList <int> absoluteAxis; |
| 669 | + QInputDevice::InputTypeFlags type; |
| 670 | +}; |
| 671 | + |
| 672 | +class QInputDeviceManagerPrivate : public QObject |
| 673 | +{ |
| 674 | + Q_OBJECT |
| 675 | +public: |
| 676 | + explicit QInputDeviceManagerPrivate(QObject *parent = 0); |
| 677 | + ~QInputDeviceManagerPrivate(); |
| 678 | + QVector <QInputDevice *> deviceList; |
| 679 | + QMap <QString, QInputDevice *> deviceMap; |
| 680 | + static QInputDeviceManagerPrivate * instance(); |
| 681 | + QInputDevice::InputType currentFilter; |
| 682 | + |
| 683 | +Q_SIGNALS: |
| 684 | + void deviceAdded(const QString &); |
| 685 | + void deviceRemoved(const QString &); |
| 686 | + void ready(); |
| 687 | + |
| 688 | +private: |
| 689 | + QInputDevice *addDevice(struct udev_device *udev); |
| 690 | + QInputDevice *addUdevDevice(struct udev_device *); |
| 691 | + |
| 692 | + QInputDevice *addDevice(const QString &path); |
| 693 | + void removeDevice(const QString &path); |
| 694 | + QSocketNotifier *notifier; |
| 695 | + int notifierFd; |
| 696 | + struct udev_monitor *udevMonitor; |
| 697 | + QInputDevice::InputTypeFlags getInputTypeFlags(struct udev_device *); |
| 698 | + struct udev *udevice; |
| 699 | + void addDetails(struct udev_device *); |
| 700 | + |
| 701 | +private Q_SLOTS: |
| 702 | + void onUDevChanges(); |
| 703 | + void init(); |
| 704 | +}; |
| 705 | + |
| 706 | +#endif // QINPUTDEVICEINFO_LINUX_P_H |
| 707 | |
| 708 | === added file 'src/plugin/file-qml-plugin/InputInfo/plugin.cpp' |
| 709 | --- src/plugin/file-qml-plugin/InputInfo/plugin.cpp 1970-01-01 00:00:00 +0000 |
| 710 | +++ src/plugin/file-qml-plugin/InputInfo/plugin.cpp 2016-02-03 14:19:17 +0000 |
| 711 | @@ -0,0 +1,32 @@ |
| 712 | +/* |
| 713 | + * Copyright 2015 Canonical Ltd. |
| 714 | + * |
| 715 | + * This program is free software; you can redistribute it and/or modify |
| 716 | + * it under the terms of the GNU Lesser General Public License as published by |
| 717 | + * the Free Software Foundation; version 3. |
| 718 | + * |
| 719 | + * This program is distributed in the hope that it will be useful, |
| 720 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 721 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 722 | + * GNU Lesser General Public License for more details. |
| 723 | + * |
| 724 | + * You should have received a copy of the GNU Lesser General Public License |
| 725 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 726 | + */ |
| 727 | + |
| 728 | +// Qt |
| 729 | +#include <QtQml/qqml.h> |
| 730 | + |
| 731 | +// self |
| 732 | +#include "plugin.h" |
| 733 | + |
| 734 | +// local |
| 735 | +#include "qdeclarativeinputdevicemodel_p.h" |
| 736 | + |
| 737 | +void InputInfoPlugin::registerTypes(const char *uri) |
| 738 | +{ |
| 739 | + int major = 0; |
| 740 | + int minor = 1; |
| 741 | + qmlRegisterType<QDeclarativeInputDeviceModel>(uri, major, minor, "InputDeviceModel"); |
| 742 | + qmlRegisterType<QInputDevice>(uri, major, minor, "InputInfo"); |
| 743 | +} |
| 744 | |
| 745 | === added file 'src/plugin/file-qml-plugin/InputInfo/plugin.h' |
| 746 | --- src/plugin/file-qml-plugin/InputInfo/plugin.h 1970-01-01 00:00:00 +0000 |
| 747 | +++ src/plugin/file-qml-plugin/InputInfo/plugin.h 2016-02-03 14:19:17 +0000 |
| 748 | @@ -0,0 +1,30 @@ |
| 749 | +/* |
| 750 | + * Copyright 2015 Canonical Ltd. |
| 751 | + * |
| 752 | + * This program is free software; you can redistribute it and/or modify |
| 753 | + * it under the terms of the GNU Lesser General Public License as published by |
| 754 | + * the Free Software Foundation; version 3. |
| 755 | + * |
| 756 | + * This program is distributed in the hope that it will be useful, |
| 757 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 758 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 759 | + * GNU Lesser General Public License for more details. |
| 760 | + * |
| 761 | + * You should have received a copy of the GNU Lesser General Public License |
| 762 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 763 | + */ |
| 764 | + |
| 765 | +#ifndef INPUTINFO_PLUGIN_H |
| 766 | +#define INPUTINFO_PLUGIN_H |
| 767 | + |
| 768 | +#include <QtQml/QQmlExtensionPlugin> |
| 769 | + |
| 770 | +class InputInfoPlugin : public QQmlExtensionPlugin |
| 771 | +{ |
| 772 | + Q_OBJECT |
| 773 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
| 774 | +public: |
| 775 | + void registerTypes(const char *uri); |
| 776 | +}; |
| 777 | + |
| 778 | +#endif // INPUTINFO_PLUGIN_H |
| 779 | |
| 780 | === added file 'src/plugin/file-qml-plugin/InputInfo/qdeclarativeinputdevicemodel.cpp' |
| 781 | --- src/plugin/file-qml-plugin/InputInfo/qdeclarativeinputdevicemodel.cpp 1970-01-01 00:00:00 +0000 |
| 782 | +++ src/plugin/file-qml-plugin/InputInfo/qdeclarativeinputdevicemodel.cpp 2016-02-03 14:19:17 +0000 |
| 783 | @@ -0,0 +1,196 @@ |
| 784 | +/**************************************************************************** |
| 785 | +** |
| 786 | +** Copyright (C) 2015 Jolla. |
| 787 | +** Contact: http://www.qt-project.org/legal |
| 788 | +** |
| 789 | +** This file is part of the QtSystems module of the Qt Toolkit. |
| 790 | +** |
| 791 | +** $QT_BEGIN_LICENSE:LGPL$ |
| 792 | +** Commercial License Usage |
| 793 | +** Licensees holding valid commercial Qt licenses may use this file in |
| 794 | +** accordance with the commercial license agreement provided with the |
| 795 | +** Software or, alternatively, in accordance with the terms contained in |
| 796 | +** a written agreement between you and Digia. For licensing terms and |
| 797 | +** conditions see http://qt.digia.com/licensing. For further information |
| 798 | +** use the contact form at http://qt.digia.com/contact-us. |
| 799 | +** |
| 800 | +** GNU Lesser General Public License Usage |
| 801 | +** Alternatively, this file may be used under the terms of the GNU Lesser |
| 802 | +** General Public License version 2.1 as published by the Free Software |
| 803 | +** Foundation and appearing in the file LICENSE.LGPL included in the |
| 804 | +** packaging of this file. Please review the following information to |
| 805 | +** ensure the GNU Lesser General Public License version 2.1 requirements |
| 806 | +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 807 | +** |
| 808 | +** In addition, as a special exception, Digia gives you certain additional |
| 809 | +** rights. These rights are described in the Digia Qt LGPL Exception |
| 810 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 811 | +** |
| 812 | +** GNU General Public License Usage |
| 813 | +** Alternatively, this file may be used under the terms of the GNU |
| 814 | +** General Public License version 3.0 as published by the Free Software |
| 815 | +** Foundation and appearing in the file LICENSE.GPL included in the |
| 816 | +** packaging of this file. Please review the following information to |
| 817 | +** ensure the GNU General Public License version 3.0 requirements will be |
| 818 | +** met: http://www.gnu.org/copyleft/gpl.html. |
| 819 | +** |
| 820 | +** |
| 821 | +** $QT_END_LICENSE$ |
| 822 | +** |
| 823 | +****************************************************************************/ |
| 824 | +#include "qdeclarativeinputdevicemodel_p.h" |
| 825 | +#include "qinputinfo.h" |
| 826 | + |
| 827 | +QDeclarativeInputDeviceModel::QDeclarativeInputDeviceModel(QObject *parent) : |
| 828 | + QAbstractListModel(parent), |
| 829 | + deviceInfo(new QInputDeviceManager), |
| 830 | + currentFilter(QInputDevice::Unknown) |
| 831 | +{ |
| 832 | + connect(deviceInfo,SIGNAL(ready()),this,SLOT(updateDeviceList())); |
| 833 | + connect(deviceInfo, &QInputDeviceManager::deviceAdded,this,&QDeclarativeInputDeviceModel::addedDevice); |
| 834 | + connect(deviceInfo, &QInputDeviceManager::deviceRemoved,this,&QDeclarativeInputDeviceModel::removedDevice); |
| 835 | +} |
| 836 | + |
| 837 | +QDeclarativeInputDeviceModel::~QDeclarativeInputDeviceModel() |
| 838 | +{ |
| 839 | + delete deviceInfo; |
| 840 | +} |
| 841 | + |
| 842 | +QVariant QDeclarativeInputDeviceModel::data(const QModelIndex &index, int role) const |
| 843 | +{ |
| 844 | + switch (role) { |
| 845 | + case ServiceRole: |
| 846 | + return QVariant::fromValue(static_cast<QObject *>(inputDevices.value(index.row()))); |
| 847 | + break; |
| 848 | + case NameRole: |
| 849 | + return QVariant::fromValue(static_cast<QString>(inputDevices.value(index.row())->name())); |
| 850 | + break; |
| 851 | + case DevicePathRole: |
| 852 | + return QVariant::fromValue(static_cast<QString>(inputDevices.value(index.row())->devicePath())); |
| 853 | + break; |
| 854 | + case ButtonsRole: |
| 855 | + return QVariant::fromValue(static_cast<QList <int> >(inputDevices.value(index.row())->buttons())); |
| 856 | + break; |
| 857 | + case SwitchesRole: |
| 858 | + return QVariant::fromValue(static_cast<QList <int> >(inputDevices.value(index.row())->switches())); |
| 859 | + break; |
| 860 | + case RelativeAxisRole: |
| 861 | + return QVariant::fromValue(static_cast<QList <int> >(inputDevices.value(index.row())->relativeAxis())); |
| 862 | + break; |
| 863 | + case AbsoluteAxisRole: |
| 864 | + return QVariant::fromValue(static_cast<QList <int> >(inputDevices.value(index.row())->absoluteAxis())); |
| 865 | + break; |
| 866 | + case TypesRole: |
| 867 | + return QVariant::fromValue(static_cast<int>(inputDevices.value(index.row())->type())); |
| 868 | + break; |
| 869 | + }; |
| 870 | + |
| 871 | + return QVariant(); |
| 872 | +} |
| 873 | + |
| 874 | +int QDeclarativeInputDeviceModel::rowCount(const QModelIndex &parent) const |
| 875 | +{ |
| 876 | + Q_UNUSED(parent); |
| 877 | + |
| 878 | + return inputDevices.count(); |
| 879 | +} |
| 880 | + |
| 881 | +int QDeclarativeInputDeviceModel::indexOf(const QString &devicePath) const |
| 882 | +{ |
| 883 | + int idx(-1); |
| 884 | + Q_FOREACH (QInputDevice *device, inputDevices) { |
| 885 | + idx++; |
| 886 | + if (device->devicePath() == devicePath) return idx; |
| 887 | + } |
| 888 | + |
| 889 | + return -1; |
| 890 | +} |
| 891 | + |
| 892 | +QInputDevice *QDeclarativeInputDeviceModel::get(int index) const |
| 893 | +{ |
| 894 | + if (index < 0 || index > inputDevices.count()) |
| 895 | + return 0; |
| 896 | + return inputDevices.value(index); |
| 897 | +} |
| 898 | + |
| 899 | +void QDeclarativeInputDeviceModel::updateDeviceList() |
| 900 | +{ |
| 901 | + QVector <QInputDevice *> newDevices = deviceInfo->deviceListOfType(currentFilter); |
| 902 | + |
| 903 | + int numNew = newDevices.count(); |
| 904 | + |
| 905 | + for (int i = 0; i < numNew; i++) { |
| 906 | + int j = inputDevices.indexOf(newDevices.value(i)); |
| 907 | + |
| 908 | + if (j == -1) { |
| 909 | + beginInsertRows(QModelIndex(), i, i); |
| 910 | + inputDevices.insert(i, newDevices.value(i)); |
| 911 | + endInsertRows(); |
| 912 | + Q_EMIT countChanged(); |
| 913 | + } else if (i != j) { |
| 914 | + // changed its position -> move it |
| 915 | + QInputDevice* device = inputDevices.value(j); |
| 916 | + beginMoveRows(QModelIndex(), j, j, QModelIndex(), i); |
| 917 | + inputDevices.remove(j); |
| 918 | + inputDevices.insert(i, device); |
| 919 | + endMoveRows(); |
| 920 | + Q_EMIT countChanged(); |
| 921 | + } //else { |
| 922 | + QModelIndex changedIndex(this->index(j, 0, QModelIndex())); |
| 923 | + Q_EMIT dataChanged(changedIndex, changedIndex); |
| 924 | + } |
| 925 | + |
| 926 | + int numOld = inputDevices.count(); |
| 927 | + if (numOld > numNew) { |
| 928 | + beginRemoveRows(QModelIndex(), numNew, numOld - 1); |
| 929 | + inputDevices.remove(numNew, numOld - numNew); |
| 930 | + endRemoveRows(); |
| 931 | + Q_EMIT countChanged(); |
| 932 | + } |
| 933 | +} |
| 934 | + |
| 935 | +void QDeclarativeInputDeviceModel::addedDevice(const QString &devicePath) |
| 936 | +{ |
| 937 | + updateDeviceList(); |
| 938 | + Q_EMIT deviceAdded(devicePath); |
| 939 | +} |
| 940 | + |
| 941 | +void QDeclarativeInputDeviceModel::removedDevice(const QString &devicePath) |
| 942 | +{ |
| 943 | + updateDeviceList(); |
| 944 | + Q_EMIT deviceRemoved(devicePath); |
| 945 | +} |
| 946 | + |
| 947 | +QHash<int,QByteArray> QDeclarativeInputDeviceModel::roleNames() const |
| 948 | +{ |
| 949 | + QHash<int, QByteArray> roles; |
| 950 | + roles[NameRole] = "name"; |
| 951 | + roles[DevicePathRole] = "devicePath"; |
| 952 | + roles[ButtonsRole] = "buttons"; |
| 953 | + roles[SwitchesRole] = "switches"; |
| 954 | + roles[RelativeAxisRole] = "rAxis"; |
| 955 | + roles[AbsoluteAxisRole] = "aAxis"; |
| 956 | + roles[TypesRole] = "types"; |
| 957 | + return roles; |
| 958 | +} |
| 959 | + |
| 960 | +/* |
| 961 | + * Returns the currently set device filter. |
| 962 | + * */ |
| 963 | +QInputDevice::InputType QDeclarativeInputDeviceModel::deviceFilter() |
| 964 | +{ |
| 965 | + return currentFilter; |
| 966 | +} |
| 967 | + |
| 968 | +/* |
| 969 | + * Sets the current input device filter to filter. |
| 970 | + * */ |
| 971 | +void QDeclarativeInputDeviceModel::setDeviceFilter(QInputDevice::InputType filter) |
| 972 | +{ |
| 973 | + if (filter != currentFilter) { |
| 974 | + deviceInfo->setDeviceFilter(filter); |
| 975 | + currentFilter = filter; |
| 976 | + updateDeviceList(); |
| 977 | + Q_EMIT deviceFilterChanged(filter); |
| 978 | + } |
| 979 | +} |
| 980 | |
| 981 | === added file 'src/plugin/file-qml-plugin/InputInfo/qdeclarativeinputdevicemodel_p.h' |
| 982 | --- src/plugin/file-qml-plugin/InputInfo/qdeclarativeinputdevicemodel_p.h 1970-01-01 00:00:00 +0000 |
| 983 | +++ src/plugin/file-qml-plugin/InputInfo/qdeclarativeinputdevicemodel_p.h 2016-02-03 14:19:17 +0000 |
| 984 | @@ -0,0 +1,102 @@ |
| 985 | +/**************************************************************************** |
| 986 | +** |
| 987 | +** Copyright (C) 2015 Jolla. |
| 988 | +** Contact: http://www.qt-project.org/legal |
| 989 | +** |
| 990 | +** This file is part of the QtSystems module of the Qt Toolkit. |
| 991 | +** |
| 992 | +** $QT_BEGIN_LICENSE:LGPL$ |
| 993 | +** Commercial License Usage |
| 994 | +** Licensees holding valid commercial Qt licenses may use this file in |
| 995 | +** accordance with the commercial license agreement provided with the |
| 996 | +** Software or, alternatively, in accordance with the terms contained in |
| 997 | +** a written agreement between you and Digia. For licensing terms and |
| 998 | +** conditions see http://qt.digia.com/licensing. For further information |
| 999 | +** use the contact form at http://qt.digia.com/contact-us. |
| 1000 | +** |
| 1001 | +** GNU Lesser General Public License Usage |
| 1002 | +** Alternatively, this file may be used under the terms of the GNU Lesser |
| 1003 | +** General Public License version 2.1 as published by the Free Software |
| 1004 | +** Foundation and appearing in the file LICENSE.LGPL included in the |
| 1005 | +** packaging of this file. Please review the following information to |
| 1006 | +** ensure the GNU Lesser General Public License version 2.1 requirements |
| 1007 | +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 1008 | +** |
| 1009 | +** In addition, as a special exception, Digia gives you certain additional |
| 1010 | +** rights. These rights are described in the Digia Qt LGPL Exception |
| 1011 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 1012 | +** |
| 1013 | +** GNU General Public License Usage |
| 1014 | +** Alternatively, this file may be used under the terms of the GNU |
| 1015 | +** General Public License version 3.0 as published by the Free Software |
| 1016 | +** Foundation and appearing in the file LICENSE.GPL included in the |
| 1017 | +** packaging of this file. Please review the following information to |
| 1018 | +** ensure the GNU General Public License version 3.0 requirements will be |
| 1019 | +** met: http://www.gnu.org/copyleft/gpl.html. |
| 1020 | +** |
| 1021 | +** |
| 1022 | +** $QT_END_LICENSE$ |
| 1023 | +** |
| 1024 | +****************************************************************************/ |
| 1025 | + |
| 1026 | +#ifndef QDECLARATIVEINPUTDEVICEMODEL_H |
| 1027 | +#define QDECLARATIVEINPUTDEVICEMODEL_H |
| 1028 | + |
| 1029 | +#include <QObject> |
| 1030 | +#include <QAbstractListModel> |
| 1031 | +#include "qinputinfo.h" |
| 1032 | + |
| 1033 | +class QDeclarativeInputDeviceModel : public QAbstractListModel |
| 1034 | +{ |
| 1035 | + Q_OBJECT |
| 1036 | + Q_DISABLE_COPY(QDeclarativeInputDeviceModel) |
| 1037 | + Q_PROPERTY(QInputDevice::InputType deviceFilter READ deviceFilter WRITE setDeviceFilter NOTIFY deviceFilterChanged) |
| 1038 | + |
| 1039 | + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) |
| 1040 | + |
| 1041 | +public: |
| 1042 | + enum ItemRoles { |
| 1043 | + ServiceRole = Qt::UserRole + 1, |
| 1044 | + NameRole, |
| 1045 | + DevicePathRole, |
| 1046 | + ButtonsRole, |
| 1047 | + SwitchesRole, |
| 1048 | + RelativeAxisRole, |
| 1049 | + AbsoluteAxisRole, |
| 1050 | + TypesRole |
| 1051 | + }; |
| 1052 | + |
| 1053 | + explicit QDeclarativeInputDeviceModel(QObject *parent = 0); |
| 1054 | + virtual ~QDeclarativeInputDeviceModel(); |
| 1055 | + |
| 1056 | + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; |
| 1057 | + int rowCount(const QModelIndex &parent = QModelIndex()) const; |
| 1058 | + |
| 1059 | + void setDeviceFilter(QInputDevice::InputType filter); |
| 1060 | + QInputDevice::InputType deviceFilter(); |
| 1061 | + |
| 1062 | + Q_INVOKABLE int indexOf(const QString &devicePath) const; |
| 1063 | + |
| 1064 | + Q_INVOKABLE QInputDevice *get(int index) const; |
| 1065 | + QHash<int, QByteArray> roleNames() const; |
| 1066 | + |
| 1067 | +Q_SIGNALS: |
| 1068 | + void deviceAdded(const QString &devicePath); |
| 1069 | + void deviceRemoved(const QString &devicePath); |
| 1070 | + void deviceFilterChanged(const QInputDevice::InputType filter); |
| 1071 | + void countChanged(); |
| 1072 | + |
| 1073 | +public Q_SLOTS: |
| 1074 | + void updateDeviceList(); |
| 1075 | +private: |
| 1076 | + QInputDeviceManager *deviceInfo; |
| 1077 | + QVector<QInputDevice *> inputDevices; |
| 1078 | + QInputDevice::InputType currentFilter; |
| 1079 | + |
| 1080 | +private Q_SLOTS: |
| 1081 | + void addedDevice(const QString &); |
| 1082 | + void removedDevice(const QString &path); |
| 1083 | + |
| 1084 | +}; |
| 1085 | + |
| 1086 | +#endif // QDECLARATIVEINPUTDEVICEMODEL_H |
| 1087 | |
| 1088 | === added file 'src/plugin/file-qml-plugin/InputInfo/qinputinfo.cpp' |
| 1089 | --- src/plugin/file-qml-plugin/InputInfo/qinputinfo.cpp 1970-01-01 00:00:00 +0000 |
| 1090 | +++ src/plugin/file-qml-plugin/InputInfo/qinputinfo.cpp 2016-02-03 14:19:17 +0000 |
| 1091 | @@ -0,0 +1,270 @@ |
| 1092 | +/**************************************************************************** |
| 1093 | +** |
| 1094 | +** Copyright (C) 2014 Canonical, Ltd. and/or its subsidiary(-ies). |
| 1095 | +** Contact: http://www.qt-project.org/legal |
| 1096 | +** |
| 1097 | +** This file is part of the QtSystems module of the Qt Toolkit. |
| 1098 | +** |
| 1099 | +** $QT_BEGIN_LICENSE:LGPL$ |
| 1100 | +** Commercial License Usage |
| 1101 | +** Licensees holding valid commercial Qt licenses may use this file in |
| 1102 | +** accordance with the commercial license agreement provided with the |
| 1103 | +** Software or, alternatively, in accordance with the terms contained in |
| 1104 | +** a written agreement between you and Digia. For licensing terms and |
| 1105 | +** conditions see http://qt.digia.com/licensing. For further information |
| 1106 | +** use the contact form at http://qt.digia.com/contact-us. |
| 1107 | +** |
| 1108 | +** GNU Lesser General Public License Usage |
| 1109 | +** Alternatively, this file may be used under the terms of the GNU Lesser |
| 1110 | +** General Public License version 2.1 as published by the Free Software |
| 1111 | +** Foundation and appearing in the file LICENSE.LGPL included in the |
| 1112 | +** packaging of this file. Please review the following information to |
| 1113 | +** ensure the GNU Lesser General Public License version 2.1 requirements |
| 1114 | +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 1115 | +** |
| 1116 | +** In addition, as a special exception, Digia gives you certain additional |
| 1117 | +** rights. These rights are described in the Digia Qt LGPL Exception |
| 1118 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 1119 | +** |
| 1120 | +** GNU General Public License Usage |
| 1121 | +** Alternatively, this file may be used under the terms of the GNU |
| 1122 | +** General Public License version 3.0 as published by the Free Software |
| 1123 | +** Foundation and appearing in the file LICENSE.GPL included in the |
| 1124 | +** packaging of this file. Please review the following information to |
| 1125 | +** ensure the GNU General Public License version 3.0 requirements will be |
| 1126 | +** met: http://www.gnu.org/copyleft/gpl.html. |
| 1127 | +** |
| 1128 | +** |
| 1129 | +** $QT_END_LICENSE$ |
| 1130 | +** |
| 1131 | +****************************************************************************/ |
| 1132 | + |
| 1133 | +#include "qinputinfo.h" |
| 1134 | + |
| 1135 | +#if defined(UNITY_MOCKS) |
| 1136 | +#include "qinputdeviceinfo_mock_p.h" |
| 1137 | +#elif defined(Q_OS_LINUX) |
| 1138 | +#include "linux/qinputdeviceinfo_linux_p.h" |
| 1139 | +#endif |
| 1140 | + |
| 1141 | +Q_GLOBAL_STATIC(QInputDeviceManagerPrivate, inputDeviceManagerPrivate) |
| 1142 | + |
| 1143 | +QT_BEGIN_NAMESPACE |
| 1144 | + |
| 1145 | +QInputDeviceManagerPrivate * QInputDeviceManagerPrivate::instance() |
| 1146 | +{ |
| 1147 | + QInputDeviceManagerPrivate *priv = inputDeviceManagerPrivate(); |
| 1148 | + return priv; |
| 1149 | +} |
| 1150 | + |
| 1151 | +QInputDevicePrivate::QInputDevicePrivate(QObject *parent) : |
| 1152 | + QObject(parent), |
| 1153 | + type(QInputDevice::Unknown) |
| 1154 | +{ |
| 1155 | +} |
| 1156 | + |
| 1157 | +QInputDevice::QInputDevice(QObject *parent) : |
| 1158 | + QObject(parent), |
| 1159 | + d_ptr(new QInputDevicePrivate(this)) |
| 1160 | +{ |
| 1161 | +} |
| 1162 | + |
| 1163 | +/* |
| 1164 | + * Returns the name of this input device. |
| 1165 | + */ |
| 1166 | +QString QInputDevice::name() const |
| 1167 | +{ |
| 1168 | + return d_ptr->name; |
| 1169 | +} |
| 1170 | + |
| 1171 | +/* |
| 1172 | + * Sets the name of this input device to \b name. |
| 1173 | + */ |
| 1174 | +void QInputDevice::setName(const QString &name) |
| 1175 | +{ |
| 1176 | + d_ptr->name = name; |
| 1177 | +} |
| 1178 | + |
| 1179 | +/* |
| 1180 | + * Returns the device path of this device. |
| 1181 | + */ |
| 1182 | +QString QInputDevice::devicePath() const |
| 1183 | +{ |
| 1184 | + return d_ptr->devicePath; |
| 1185 | +} |
| 1186 | + |
| 1187 | +/* |
| 1188 | + * Sets the device ppath of this device to /b path. |
| 1189 | + */ |
| 1190 | +void QInputDevice::setDevicePath(const QString &path) |
| 1191 | +{ |
| 1192 | + d_ptr->devicePath = path; |
| 1193 | +} |
| 1194 | + |
| 1195 | +/* |
| 1196 | + * Returns the number of buttons this device has. |
| 1197 | + */ |
| 1198 | +QList <int> QInputDevice::buttons() const |
| 1199 | +{ |
| 1200 | + return d_ptr->buttons; |
| 1201 | +} |
| 1202 | + |
| 1203 | +/* |
| 1204 | + * Adds a button |
| 1205 | + */ |
| 1206 | +void QInputDevice::addButton(int buttonCode) |
| 1207 | +{ |
| 1208 | + d_ptr->buttons.append(buttonCode); |
| 1209 | +} |
| 1210 | + |
| 1211 | +/* |
| 1212 | + * Returns the number of switch of this device. |
| 1213 | + */ |
| 1214 | +QList <int> QInputDevice::switches() const |
| 1215 | +{ |
| 1216 | + return d_ptr->switches; |
| 1217 | +} |
| 1218 | + |
| 1219 | +/* |
| 1220 | + * Adds a switch |
| 1221 | + */ |
| 1222 | +void QInputDevice::addSwitch(int switchCode) |
| 1223 | +{ |
| 1224 | + d_ptr->switches.append(switchCode); |
| 1225 | +} |
| 1226 | + |
| 1227 | +/* |
| 1228 | + * Returns a list of the relative axis of this device |
| 1229 | + */ |
| 1230 | +QList <int> QInputDevice::relativeAxis() const |
| 1231 | +{ |
| 1232 | + return d_ptr->relativeAxis; |
| 1233 | +} |
| 1234 | + |
| 1235 | +/* |
| 1236 | + */ |
| 1237 | +void QInputDevice::addRelativeAxis(int axisCode) |
| 1238 | +{ |
| 1239 | + d_ptr->relativeAxis.append(axisCode); |
| 1240 | +} |
| 1241 | + |
| 1242 | +/* |
| 1243 | + * Returns a list of the absolute axis of this device |
| 1244 | + */ |
| 1245 | +QList <int> QInputDevice::absoluteAxis() const |
| 1246 | +{ |
| 1247 | + return d_ptr->absoluteAxis; |
| 1248 | +} |
| 1249 | + |
| 1250 | +/* |
| 1251 | + */ |
| 1252 | +void QInputDevice::addAbsoluteAxis(int axisCode) |
| 1253 | +{ |
| 1254 | + d_ptr->absoluteAxis.append(axisCode); |
| 1255 | +} |
| 1256 | + |
| 1257 | +/* |
| 1258 | + * Returns a QInputDevice::InputTypeFlags of all the types of types. |
| 1259 | + */ |
| 1260 | +QInputDevice::InputTypeFlags QInputDevice::type() const |
| 1261 | +{ |
| 1262 | + return d_ptr->type; |
| 1263 | +} |
| 1264 | + |
| 1265 | +/* |
| 1266 | + */ |
| 1267 | +void QInputDevice::setType(QInputDevice::InputTypeFlags type) //? setTypes? |
| 1268 | +{ |
| 1269 | + d_ptr->type = type; |
| 1270 | +} |
| 1271 | + |
| 1272 | +QInputDeviceManager::QInputDeviceManager(QObject *parent) : |
| 1273 | + QObject(parent), |
| 1274 | + d_ptr(inputDeviceManagerPrivate) |
| 1275 | +{ |
| 1276 | + connect(d_ptr, &QInputDeviceManagerPrivate::deviceAdded,this,&QInputDeviceManager::addedDevice); |
| 1277 | + connect(d_ptr, &QInputDeviceManagerPrivate::deviceRemoved,this,&QInputDeviceManager::deviceRemoved); |
| 1278 | + |
| 1279 | + connect(d_ptr,SIGNAL(ready()),this,SIGNAL(ready())); |
| 1280 | +} |
| 1281 | + |
| 1282 | +/* |
| 1283 | + * Returns a QMap of known input devices. |
| 1284 | + */ |
| 1285 | +QMap <QString, QInputDevice *> QInputDeviceManager::deviceMap() |
| 1286 | +{ |
| 1287 | + return d_ptr->deviceMap; |
| 1288 | +} |
| 1289 | + |
| 1290 | +/* |
| 1291 | + */ |
| 1292 | +void QInputDeviceManager::addedDevice(const QString & devicePath) |
| 1293 | +{ |
| 1294 | + Q_EMIT deviceAdded(devicePath); |
| 1295 | +} |
| 1296 | + |
| 1297 | +/* |
| 1298 | + * Returns a QVector of InputDevices of type filter |
| 1299 | + * */ |
| 1300 | +QVector <QInputDevice *> QInputDeviceManager::deviceListOfType(QInputDevice::InputType filter) |
| 1301 | +{ |
| 1302 | + QVector <QInputDevice *> dList; |
| 1303 | + QMapIterator<QString, QInputDevice *> i(d_ptr->deviceMap); |
| 1304 | + while (i.hasNext()) { |
| 1305 | + i.next(); |
| 1306 | + if (i.value()->type().testFlag(filter) || filter == QInputDevice::Unknown) { |
| 1307 | + dList.append(i.value()); |
| 1308 | + } |
| 1309 | + } |
| 1310 | + return dList; |
| 1311 | +} |
| 1312 | + |
| 1313 | +/* |
| 1314 | + * Returns the number of input devices with the currently set QInputDevice::InputType filter. |
| 1315 | + * If no device filter has been set, returns number of all available input devices. |
| 1316 | + * If filter has not been set, returns all available input devices |
| 1317 | + */ |
| 1318 | +int QInputDeviceManager::deviceCount() const |
| 1319 | +{ |
| 1320 | + return deviceCount(static_cast< QInputDevice::InputType >(d_ptr->currentFilter)); |
| 1321 | +} |
| 1322 | + |
| 1323 | +/* |
| 1324 | + * Returns the number of input devices of the type filter. |
| 1325 | + */ |
| 1326 | +int QInputDeviceManager::deviceCount(const QInputDevice::InputType filter) const |
| 1327 | +{ |
| 1328 | + int dList = 0; |
| 1329 | + QMapIterator<QString, QInputDevice *> i(d_ptr->deviceMap); |
| 1330 | + while (i.hasNext()) { |
| 1331 | + i.next(); |
| 1332 | +// qDebug() << i.value()->name() << i.value()->devicePath(); |
| 1333 | +// qDebug() << i.value()->type() << i.value()->type().testFlag(filter); |
| 1334 | + |
| 1335 | + if (i.value()->type().testFlag(filter)) { |
| 1336 | + dList++; |
| 1337 | + } |
| 1338 | + } |
| 1339 | + return dList; |
| 1340 | +} |
| 1341 | + |
| 1342 | +/* |
| 1343 | + * Returns the currently set device filter. |
| 1344 | + * */ |
| 1345 | +QInputDevice::InputType QInputDeviceManager::deviceFilter() |
| 1346 | +{ |
| 1347 | + return d_ptr->currentFilter; |
| 1348 | +} |
| 1349 | + |
| 1350 | +/* |
| 1351 | + * Sets the current input device filter to filter. |
| 1352 | + * */ |
| 1353 | +void QInputDeviceManager::setDeviceFilter(QInputDevice::InputType filter) |
| 1354 | +{ |
| 1355 | + if (filter != d_ptr->currentFilter) { |
| 1356 | + d_ptr->currentFilter = filter; |
| 1357 | + Q_EMIT deviceFilterChanged(filter); |
| 1358 | + } |
| 1359 | +} |
| 1360 | + |
| 1361 | +QT_END_NAMESPACE |
| 1362 | |
| 1363 | === added file 'src/plugin/file-qml-plugin/InputInfo/qinputinfo.h' |
| 1364 | --- src/plugin/file-qml-plugin/InputInfo/qinputinfo.h 1970-01-01 00:00:00 +0000 |
| 1365 | +++ src/plugin/file-qml-plugin/InputInfo/qinputinfo.h 2016-02-03 14:19:17 +0000 |
| 1366 | @@ -0,0 +1,143 @@ |
| 1367 | +/**************************************************************************** |
| 1368 | +** |
| 1369 | +** Copyright (C) 2014 Canonical, Ltd. and/or its subsidiary(-ies). |
| 1370 | +** Contact: http://www.qt-project.org/legal |
| 1371 | +** |
| 1372 | +** This file is part of the QtSystems module of the Qt Toolkit. |
| 1373 | +** |
| 1374 | +** $QT_BEGIN_LICENSE:LGPL$ |
| 1375 | +** Commercial License Usage |
| 1376 | +** Licensees holding valid commercial Qt licenses may use this file in |
| 1377 | +** accordance with the commercial license agreement provided with the |
| 1378 | +** Software or, alternatively, in accordance with the terms contained in |
| 1379 | +** a written agreement between you and Digia. For licensing terms and |
| 1380 | +** conditions see http://qt.digia.com/licensing. For further information |
| 1381 | +** use the contact form at http://qt.digia.com/contact-us. |
| 1382 | +** |
| 1383 | +** GNU Lesser General Public License Usage |
| 1384 | +** Alternatively, this file may be used under the terms of the GNU Lesser |
| 1385 | +** General Public License version 2.1 as published by the Free Software |
| 1386 | +** Foundation and appearing in the file LICENSE.LGPL included in the |
| 1387 | +** packaging of this file. Please review the following information to |
| 1388 | +** ensure the GNU Lesser General Public License version 2.1 requirements |
| 1389 | +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 1390 | +** |
| 1391 | +** In addition, as a special exception, Digia gives you certain additional |
| 1392 | +** rights. These rights are described in the Digia Qt LGPL Exception |
| 1393 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 1394 | +** |
| 1395 | +** GNU General Public License Usage |
| 1396 | +** Alternatively, this file may be used under the terms of the GNU |
| 1397 | +** General Public License version 3.0 as published by the Free Software |
| 1398 | +** Foundation and appearing in the file LICENSE.GPL included in the |
| 1399 | +** packaging of this file. Please review the following information to |
| 1400 | +** ensure the GNU General Public License version 3.0 requirements will be |
| 1401 | +** met: http://www.gnu.org/copyleft/gpl.html. |
| 1402 | +** |
| 1403 | +** |
| 1404 | +** $QT_END_LICENSE$ |
| 1405 | +** |
| 1406 | +****************************************************************************/ |
| 1407 | + |
| 1408 | +#ifndef QINPUTINFO_H |
| 1409 | +#define QINPUTINFO_H |
| 1410 | + |
| 1411 | +#include <QObject> |
| 1412 | +#include <QVector> |
| 1413 | +#include <QMap> |
| 1414 | +#include <QSocketNotifier> |
| 1415 | +#include <QDebug> |
| 1416 | + |
| 1417 | +class QInputDeviceManagerPrivate; |
| 1418 | +class QInputDevicePrivate; |
| 1419 | +class QInputDevice; |
| 1420 | + |
| 1421 | +class QInputDeviceManager; |
| 1422 | + |
| 1423 | +class QInputDevice : public QObject |
| 1424 | +{ |
| 1425 | + Q_OBJECT |
| 1426 | + Q_ENUMS(InputType) |
| 1427 | + Q_FLAGS(InputType InputTypeFlags) |
| 1428 | + friend class QInputDeviceManagerPrivate; |
| 1429 | + |
| 1430 | +public: |
| 1431 | + |
| 1432 | + enum InputType { |
| 1433 | + Unknown = 0, |
| 1434 | + Button = 1, |
| 1435 | + Mouse = 2, |
| 1436 | + TouchPad = 4, |
| 1437 | + TouchScreen = 8, |
| 1438 | + Keyboard = 16, |
| 1439 | + Switch = 32 |
| 1440 | + }; |
| 1441 | + Q_ENUMS(InputType) |
| 1442 | + Q_DECLARE_FLAGS(InputTypeFlags, InputType) |
| 1443 | + |
| 1444 | + explicit QInputDevice(QObject *parent = 0); |
| 1445 | + QString name() const; |
| 1446 | + QString devicePath() const; |
| 1447 | + QList <int> buttons() const; //keys event code |
| 1448 | + QList <int> switches() const; |
| 1449 | + QList <int> relativeAxis() const; |
| 1450 | + QList <int> absoluteAxis() const; |
| 1451 | + QInputDevice::InputTypeFlags type() const; |
| 1452 | + |
| 1453 | +private: |
| 1454 | + |
| 1455 | + QInputDevicePrivate *d_ptr; |
| 1456 | + void setName(const QString &); |
| 1457 | + void setDevicePath(const QString &); |
| 1458 | + void addButton(int); |
| 1459 | + void addSwitch(int); |
| 1460 | + void addRelativeAxis(int); |
| 1461 | + void addAbsoluteAxis(int); |
| 1462 | + void setType(QInputDevice::InputTypeFlags flags); |
| 1463 | + |
| 1464 | +}; |
| 1465 | + |
| 1466 | +Q_DECLARE_METATYPE(QInputDevice::InputType) |
| 1467 | +Q_DECLARE_METATYPE(QInputDevice::InputTypeFlags) |
| 1468 | + |
| 1469 | +class QInputDeviceManagerPrivate; |
| 1470 | + |
| 1471 | +class QInputDeviceManager : public QObject |
| 1472 | +{ |
| 1473 | + Q_OBJECT |
| 1474 | + Q_PROPERTY(int deviceCount READ deviceCount NOTIFY deviceCountChanged) |
| 1475 | + Q_PROPERTY(QInputDevice::InputType deviceFilter READ deviceFilter WRITE setDeviceFilter NOTIFY deviceFilterChanged) |
| 1476 | +public: |
| 1477 | + |
| 1478 | + explicit QInputDeviceManager(QObject *parent = 0); |
| 1479 | + |
| 1480 | + int deviceCount() const; |
| 1481 | + int deviceCount(const QInputDevice::InputType filter) const; |
| 1482 | + |
| 1483 | + void setDeviceFilter(QInputDevice::InputType filter); |
| 1484 | + QInputDevice::InputType deviceFilter(); |
| 1485 | + |
| 1486 | + QMap <QString, QInputDevice *> deviceMap(); |
| 1487 | + Q_INVOKABLE QVector <QInputDevice *> deviceListOfType(QInputDevice::InputType filter); |
| 1488 | + |
| 1489 | +Q_SIGNALS: |
| 1490 | + |
| 1491 | + void deviceAdded(const QString & devicePath); |
| 1492 | + void deviceRemoved(const QString & devicePath); |
| 1493 | + |
| 1494 | + void ready(); |
| 1495 | + void deviceCountChanged(int count); |
| 1496 | + void deviceFilterChanged(const QInputDevice::InputType filter); |
| 1497 | + |
| 1498 | +public Q_SLOTS: |
| 1499 | + void addedDevice(const QString & devicePath); |
| 1500 | + |
| 1501 | +private: |
| 1502 | + Q_DISABLE_COPY(QInputDeviceManager) |
| 1503 | +#if !defined(QT_SIMULATOR) |
| 1504 | + QInputDeviceManagerPrivate *const d_ptr; |
| 1505 | + Q_DECLARE_PRIVATE(QInputDeviceManager) |
| 1506 | +#endif |
| 1507 | +}; |
| 1508 | + |
| 1509 | +#endif // QINPUTINFO_H |
| 1510 | |
| 1511 | === added file 'src/plugin/file-qml-plugin/InputInfo/qmldir' |
| 1512 | --- src/plugin/file-qml-plugin/InputInfo/qmldir 1970-01-01 00:00:00 +0000 |
| 1513 | +++ src/plugin/file-qml-plugin/InputInfo/qmldir 2016-02-03 14:19:17 +0000 |
| 1514 | @@ -0,0 +1,3 @@ |
| 1515 | +module Unity.InputInfo |
| 1516 | +plugin InputInfo |
| 1517 | +typeinfo InputInfo.qmltypes |
| 1518 | |
| 1519 | === modified file 'src/plugin/file-qml-plugin/backend.cpp' |
| 1520 | --- src/plugin/file-qml-plugin/backend.cpp 2015-09-19 15:40:22 +0000 |
| 1521 | +++ src/plugin/file-qml-plugin/backend.cpp 2016-02-03 14:19:17 +0000 |
| 1522 | @@ -21,27 +21,38 @@ |
| 1523 | #include "backend.h" |
| 1524 | #include "documentmodel.h" |
| 1525 | #include "docviewerfile.h" |
| 1526 | -#include "docviewerutils.h" |
| 1527 | - |
| 1528 | -static QObject *registerDocviewerUtils (QQmlEngine *engine, QJSEngine *scriptEngine) |
| 1529 | -{ |
| 1530 | - Q_UNUSED(engine) |
| 1531 | - Q_UNUSED(scriptEngine) |
| 1532 | - |
| 1533 | - DocviewerUtils *ch = new DocviewerUtils(); |
| 1534 | - return ch; |
| 1535 | +#include "fileutils.h" |
| 1536 | +#include "ubuntuconvergenceutils.h" |
| 1537 | + |
| 1538 | +static QObject *registerFileUtils (QQmlEngine *engine, QJSEngine *scriptEngine) |
| 1539 | +{ |
| 1540 | + Q_UNUSED(engine) |
| 1541 | + Q_UNUSED(scriptEngine) |
| 1542 | + |
| 1543 | + DocviewerFileUtils *f = new DocviewerFileUtils(); |
| 1544 | + return f; |
| 1545 | +} |
| 1546 | + |
| 1547 | +static QObject *registerConvergenceUtils (QQmlEngine *engine, QJSEngine *scriptEngine) |
| 1548 | +{ |
| 1549 | + Q_UNUSED(engine) |
| 1550 | + Q_UNUSED(scriptEngine) |
| 1551 | + |
| 1552 | + UbuntuConvergenceUtils *c = new UbuntuConvergenceUtils(); |
| 1553 | + return c; |
| 1554 | } |
| 1555 | |
| 1556 | void BackendPlugin::registerTypes(const char *uri) |
| 1557 | { |
| 1558 | Q_ASSERT(uri == QLatin1String("DocumentViewer")); |
| 1559 | - |
| 1560 | + |
| 1561 | //@uri DocumentViewer |
| 1562 | |
| 1563 | qmlRegisterType<DocumentModel>(uri, 1, 0, "DocumentsModel"); |
| 1564 | qmlRegisterType<DocviewerFile>(uri, 1, 0, "File"); |
| 1565 | |
| 1566 | - qmlRegisterSingletonType<DocviewerUtils>(uri, 1, 0, "DocumentViewer", registerDocviewerUtils); |
| 1567 | + qmlRegisterSingletonType<DocviewerFileUtils>(uri, 1, 0, "FileUtils", registerFileUtils); |
| 1568 | + qmlRegisterSingletonType<UbuntuConvergenceUtils>(uri, 1, 0, "ConvergenceUtils", registerConvergenceUtils); |
| 1569 | } |
| 1570 | |
| 1571 | void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
| 1572 | |
| 1573 | === modified file 'src/plugin/file-qml-plugin/documentmodel.cpp' |
| 1574 | --- src/plugin/file-qml-plugin/documentmodel.cpp 2015-09-19 15:40:22 +0000 |
| 1575 | +++ src/plugin/file-qml-plugin/documentmodel.cpp 2016-02-03 14:19:17 +0000 |
| 1576 | @@ -17,7 +17,7 @@ |
| 1577 | |
| 1578 | #include "documentmodel.h" |
| 1579 | #include "fswatcher.h" |
| 1580 | -#include "docviewerutils.h" |
| 1581 | +#include "fileutils.h" |
| 1582 | |
| 1583 | #include <QStandardPaths> |
| 1584 | #include <QDir> |
| 1585 | @@ -115,7 +115,7 @@ |
| 1586 | |
| 1587 | bool DocumentModel::isFileSupported(const QString &path) |
| 1588 | { |
| 1589 | - return DocviewerUtils::isFileSupported(path); |
| 1590 | + return DocviewerFileUtils::isFileSupported(path); |
| 1591 | } |
| 1592 | |
| 1593 | QHash<int, QByteArray> DocumentModel::roleNames() const |
| 1594 | |
| 1595 | === removed file 'src/plugin/file-qml-plugin/docviewerutils.cpp' |
| 1596 | --- src/plugin/file-qml-plugin/docviewerutils.cpp 2015-12-27 12:10:06 +0000 |
| 1597 | +++ src/plugin/file-qml-plugin/docviewerutils.cpp 1970-01-01 00:00:00 +0000 |
| 1598 | @@ -1,184 +0,0 @@ |
| 1599 | -/* |
| 1600 | - Copyright (C) 2015 Canonical, Ltd. |
| 1601 | - |
| 1602 | - This program is free software: you can redistribute it and/or modify |
| 1603 | - it under the terms of the GNU General Public License 3 as published by |
| 1604 | - the Free Software Foundation. |
| 1605 | - |
| 1606 | - This program is distributed in the hope that it will be useful, |
| 1607 | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1608 | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1609 | - GNU General Public License for more details. |
| 1610 | - |
| 1611 | - You should have received a copy of the GNU General Public License |
| 1612 | - along with this program. If not, see http://www.gnu.org/licenses/. |
| 1613 | -*/ |
| 1614 | - |
| 1615 | -#include "docviewerutils.h" |
| 1616 | - |
| 1617 | -#include <QFileInfo> |
| 1618 | -#include <QDir> |
| 1619 | -#include <QMimeDatabase> |
| 1620 | -#include <QStandardPaths> |
| 1621 | -#include <QDirIterator> |
| 1622 | -#include <QDateTime> |
| 1623 | -#include <QtGui/QGuiApplication> |
| 1624 | - |
| 1625 | -bool DocviewerUtils::desktopMode() const |
| 1626 | -{ |
| 1627 | - // Assume that platformName (QtUbuntu) with ubuntu |
| 1628 | - // in name means it's running on device |
| 1629 | - // TODO: replace this check with SDK call for formfactor |
| 1630 | - QString platform = QGuiApplication::platformName(); |
| 1631 | - return !((platform == "ubuntu") || (platform == "ubuntumirclient")); |
| 1632 | -} |
| 1633 | - |
| 1634 | -bool DocviewerUtils::exists(const QString &path) |
| 1635 | -{ |
| 1636 | - QFileInfo fi(path); |
| 1637 | - |
| 1638 | - if (fi.isFile()) |
| 1639 | - return fi.exists(); |
| 1640 | - |
| 1641 | - // else |
| 1642 | - return QDir(path).exists(); |
| 1643 | -} |
| 1644 | - |
| 1645 | -bool DocviewerUtils::copy(const QString &source, const QString &destination) |
| 1646 | -{ |
| 1647 | - return QFile::copy(source, destination); |
| 1648 | -} |
| 1649 | - |
| 1650 | -bool DocviewerUtils::isFileSupported(const QString &path) |
| 1651 | -{ |
| 1652 | - QMimeDatabase mdb; |
| 1653 | - const QString mimetype = mdb.mimeTypeForFile(path).name(); |
| 1654 | - |
| 1655 | - return mimetype.startsWith("text/") |
| 1656 | - || mimetype == "application/pdf" |
| 1657 | - || mimetype.startsWith("application/vnd.oasis.opendocument") |
| 1658 | - || mimetype == "application/msword" |
| 1659 | - || mimetype == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" |
| 1660 | - || mimetype == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" |
| 1661 | - || mimetype == "application/vnd.openxmlformats-officedocument.presentationml.presentation" |
| 1662 | - || mimetype == "application/vnd.ms-excel" |
| 1663 | - || mimetype == "application/vnd.ms-powerpoint"; |
| 1664 | -} |
| 1665 | - |
| 1666 | -QString DocviewerUtils::getXdgDocumentsLocation() |
| 1667 | -{ |
| 1668 | - return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); |
| 1669 | -} |
| 1670 | - |
| 1671 | -QString DocviewerUtils::buildDestinationPath(const QString &destinationDir, const QString &sourcePath) |
| 1672 | -{ |
| 1673 | - QFileInfo fi(sourcePath); |
| 1674 | - |
| 1675 | - /* |
| 1676 | - We don't support formats that use a double extension |
| 1677 | - (e.g. tar.gz), so we can safely use completeBaseName() and |
| 1678 | - suffix() functions, in order to properly detect the name of |
| 1679 | - the document even when there's a dot in the middle of the name. |
| 1680 | - */ |
| 1681 | - QString suffix = fi.suffix(); |
| 1682 | - QString filenameWithoutSuffix = fi.completeBaseName(); |
| 1683 | - |
| 1684 | - QMimeDatabase mdb; |
| 1685 | - QMimeType mt = mdb.mimeTypeForFile(sourcePath); |
| 1686 | - |
| 1687 | - // If the filename doesn't have an extension add one from the |
| 1688 | - // detected mimetype |
| 1689 | - if (suffix.isEmpty()) |
| 1690 | - suffix = mt.preferredSuffix(); |
| 1691 | - |
| 1692 | - QString dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator(); |
| 1693 | - QString destination = QString("%1.%2").arg(dir + filenameWithoutSuffix, suffix); |
| 1694 | - |
| 1695 | - // If there's already a file of this name, reformat it to |
| 1696 | - // "filename (copy x).png" where x is a number, incremented until we find an |
| 1697 | - // available filename. |
| 1698 | - if (QFile::exists(destination)) { |
| 1699 | - /* |
| 1700 | - TRANSLATORS: This string is used for renaming a copied file, |
| 1701 | - when a file with the same name already exists in user's |
| 1702 | - Documents folder. |
| 1703 | - |
| 1704 | - e.g. "Manual_Aquaris_E4.5_ubuntu_EN.pdf" will become |
| 1705 | - "Manual_Aquaris_E4.5_ubuntu_EN (copy 2).pdf" |
| 1706 | - |
| 1707 | - where "2" is given by the argument "%1" |
| 1708 | - */ |
| 1709 | - QString reformattedSuffix = QString(tr("copy %1")); |
| 1710 | - |
| 1711 | - // Check if the file has already a "copy" suffix |
| 1712 | - // If so, remove it since we will update it later. |
| 1713 | - QRegExp rx(" \\(" + reformattedSuffix.arg(QString("\\d+")) + "\\)"); |
| 1714 | - int reformattedSuffixPos = filenameWithoutSuffix.lastIndexOf(rx); |
| 1715 | - |
| 1716 | - if (reformattedSuffixPos != -1) |
| 1717 | - filenameWithoutSuffix.truncate(reformattedSuffixPos); |
| 1718 | - |
| 1719 | - // Add the right "copy" suffix. |
| 1720 | - int append = 1; |
| 1721 | - while (QFile::exists(destination)) { |
| 1722 | - destination = QString("%1 (%2).%3").arg( |
| 1723 | - dir + filenameWithoutSuffix, |
| 1724 | - reformattedSuffix.arg(QString::number(append)), |
| 1725 | - suffix); |
| 1726 | - append++; |
| 1727 | - } |
| 1728 | - } |
| 1729 | - |
| 1730 | - return destination; |
| 1731 | -} |
| 1732 | - |
| 1733 | -// Return the path of the file, if found in the storageLocation paths, |
| 1734 | -// otherwise return an empty string. |
| 1735 | -// Used for prevent importing of a second copy of a file through ContentHub. |
| 1736 | -QString DocviewerUtils::checkIfFileAlreadyImported(const QString &filePath, const QStringList &storageLocationList) |
| 1737 | -{ |
| 1738 | - QFileInfo fi(filePath); |
| 1739 | - QStringList files; |
| 1740 | - |
| 1741 | - // Get the list of all the files in the watched folders |
| 1742 | - Q_FOREACH(const QString &storageLocation, storageLocationList) { |
| 1743 | - QDirIterator dir(storageLocation, QDir::Files | QDir::NoDotAndDotDot | QDir::Readable, |
| 1744 | - QDirIterator::Subdirectories); |
| 1745 | - |
| 1746 | - while (dir.hasNext()) |
| 1747 | - { |
| 1748 | - dir.next(); |
| 1749 | - files.append(dir.filePath()); |
| 1750 | - } |
| 1751 | - } |
| 1752 | - |
| 1753 | - // Check if there's a file with the same name in the list |
| 1754 | - Q_FOREACH(const QString &file, files) { |
| 1755 | - if (file.endsWith(fi.fileName())) { |
| 1756 | - // Seems there could be already the same file in the watched |
| 1757 | - // folders. Check also size and lastModified date. |
| 1758 | - QFileInfo fileToCheck(file); |
| 1759 | - |
| 1760 | - if (fi.size() == fileToCheck.size() && |
| 1761 | - fi.lastModified() == fileToCheck.lastModified()) |
| 1762 | - return file; |
| 1763 | - } |
| 1764 | - } |
| 1765 | - |
| 1766 | - return QString(); |
| 1767 | -} |
| 1768 | - |
| 1769 | -QString DocviewerUtils::getFileBaseNameFromPath(const QString &filePath) |
| 1770 | -{ |
| 1771 | - return QFileInfo(filePath).completeBaseName(); |
| 1772 | -} |
| 1773 | - |
| 1774 | -QString DocviewerUtils::getFileNameFromPath(const QString &filePath) |
| 1775 | -{ |
| 1776 | - return QFileInfo(filePath).fileName(); |
| 1777 | -} |
| 1778 | - |
| 1779 | -QString DocviewerUtils::getCanonicalPath(const QString &filePath) |
| 1780 | -{ |
| 1781 | - return QFileInfo(filePath).canonicalPath(); |
| 1782 | -} |
| 1783 | |
| 1784 | === removed file 'src/plugin/file-qml-plugin/docviewerutils.h' |
| 1785 | --- src/plugin/file-qml-plugin/docviewerutils.h 2015-12-27 12:10:06 +0000 |
| 1786 | +++ src/plugin/file-qml-plugin/docviewerutils.h 1970-01-01 00:00:00 +0000 |
| 1787 | @@ -1,45 +0,0 @@ |
| 1788 | -/* |
| 1789 | - Copyright (C) 2015 Canonical, Ltd. |
| 1790 | - |
| 1791 | - This program is free software: you can redistribute it and/or modify |
| 1792 | - it under the terms of the GNU General Public License 3 as published by |
| 1793 | - the Free Software Foundation. |
| 1794 | - |
| 1795 | - This program is distributed in the hope that it will be useful, |
| 1796 | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1797 | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1798 | - GNU General Public License for more details. |
| 1799 | - |
| 1800 | - You should have received a copy of the GNU General Public License |
| 1801 | - along with this program. If not, see http://www.gnu.org/licenses/. |
| 1802 | -*/ |
| 1803 | - |
| 1804 | -#ifndef DOCVIEWERUTILS_H |
| 1805 | -#define DOCVIEWERUTILS_H |
| 1806 | - |
| 1807 | -#include <QObject> |
| 1808 | - |
| 1809 | -class DocviewerUtils : public QObject |
| 1810 | -{ |
| 1811 | - Q_OBJECT |
| 1812 | - Q_PROPERTY(bool desktopMode READ desktopMode CONSTANT) |
| 1813 | - |
| 1814 | -public: |
| 1815 | - bool desktopMode() const; |
| 1816 | - |
| 1817 | - Q_INVOKABLE static bool exists(const QString &path); |
| 1818 | - Q_INVOKABLE static bool copy(const QString &source, const QString &destination); |
| 1819 | - |
| 1820 | - Q_INVOKABLE static bool isFileSupported(const QString &path); |
| 1821 | - Q_INVOKABLE static QString getXdgDocumentsLocation(); |
| 1822 | - |
| 1823 | - Q_INVOKABLE static QString buildDestinationPath(const QString &destinationDir, const QString &sourcePath); |
| 1824 | - |
| 1825 | - Q_INVOKABLE static QString checkIfFileAlreadyImported(const QString &filePath, const QStringList &storageLocationList); |
| 1826 | - |
| 1827 | - Q_INVOKABLE static QString getFileBaseNameFromPath(const QString &filePath); |
| 1828 | - Q_INVOKABLE static QString getFileNameFromPath(const QString &filePath); |
| 1829 | - Q_INVOKABLE static QString getCanonicalPath(const QString &filePath); |
| 1830 | -}; |
| 1831 | - |
| 1832 | -#endif // DOCVIEWERUTILS_H |
| 1833 | |
| 1834 | === added file 'src/plugin/file-qml-plugin/fileutils.cpp' |
| 1835 | --- src/plugin/file-qml-plugin/fileutils.cpp 1970-01-01 00:00:00 +0000 |
| 1836 | +++ src/plugin/file-qml-plugin/fileutils.cpp 2016-02-03 14:19:17 +0000 |
| 1837 | @@ -0,0 +1,174 @@ |
| 1838 | +/* |
| 1839 | + Copyright (C) 2015 Canonical, Ltd. |
| 1840 | + |
| 1841 | + This program is free software: you can redistribute it and/or modify |
| 1842 | + it under the terms of the GNU General Public License 3 as published by |
| 1843 | + the Free Software Foundation. |
| 1844 | + |
| 1845 | + This program is distributed in the hope that it will be useful, |
| 1846 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1847 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1848 | + GNU General Public License for more details. |
| 1849 | + |
| 1850 | + You should have received a copy of the GNU General Public License |
| 1851 | + along with this program. If not, see http://www.gnu.org/licenses/. |
| 1852 | +*/ |
| 1853 | + |
| 1854 | +#include "fileutils.h" |
| 1855 | + |
| 1856 | +#include <QFileInfo> |
| 1857 | +#include <QDir> |
| 1858 | +#include <QMimeDatabase> |
| 1859 | +#include <QStandardPaths> |
| 1860 | +#include <QDirIterator> |
| 1861 | +#include <QDateTime> |
| 1862 | + |
| 1863 | +bool DocviewerFileUtils::exists(const QString &path) |
| 1864 | +{ |
| 1865 | + QFileInfo fi(path); |
| 1866 | + |
| 1867 | + if (fi.isFile()) |
| 1868 | + return fi.exists(); |
| 1869 | + |
| 1870 | + // else |
| 1871 | + return QDir(path).exists(); |
| 1872 | +} |
| 1873 | + |
| 1874 | +bool DocviewerFileUtils::copy(const QString &source, const QString &destination) |
| 1875 | +{ |
| 1876 | + return QFile::copy(source, destination); |
| 1877 | +} |
| 1878 | + |
| 1879 | +bool DocviewerFileUtils::isFileSupported(const QString &path) |
| 1880 | +{ |
| 1881 | + QMimeDatabase mdb; |
| 1882 | + const QString mimetype = mdb.mimeTypeForFile(path).name(); |
| 1883 | + |
| 1884 | + return mimetype.startsWith("text/") |
| 1885 | + || mimetype == "application/pdf" |
| 1886 | + || mimetype.startsWith("application/vnd.oasis.opendocument") |
| 1887 | + || mimetype == "application/msword" |
| 1888 | + || mimetype == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" |
| 1889 | + || mimetype == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" |
| 1890 | + || mimetype == "application/vnd.openxmlformats-officedocument.presentationml.presentation" |
| 1891 | + || mimetype == "application/vnd.ms-excel" |
| 1892 | + || mimetype == "application/vnd.ms-powerpoint"; |
| 1893 | +} |
| 1894 | + |
| 1895 | +QString DocviewerFileUtils::getXdgDocumentsLocation() |
| 1896 | +{ |
| 1897 | + return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); |
| 1898 | +} |
| 1899 | + |
| 1900 | +QString DocviewerFileUtils::buildDestinationPath(const QString &destinationDir, const QString &sourcePath) |
| 1901 | +{ |
| 1902 | + QFileInfo fi(sourcePath); |
| 1903 | + |
| 1904 | + /* |
| 1905 | + We don't support formats that use a double extension |
| 1906 | + (e.g. tar.gz), so we can safely use completeBaseName() and |
| 1907 | + suffix() functions, in order to properly detect the name of |
| 1908 | + the document even when there's a dot in the middle of the name. |
| 1909 | + */ |
| 1910 | + QString suffix = fi.suffix(); |
| 1911 | + QString filenameWithoutSuffix = fi.completeBaseName(); |
| 1912 | + |
| 1913 | + QMimeDatabase mdb; |
| 1914 | + QMimeType mt = mdb.mimeTypeForFile(sourcePath); |
| 1915 | + |
| 1916 | + // If the filename doesn't have an extension add one from the |
| 1917 | + // detected mimetype |
| 1918 | + if (suffix.isEmpty()) |
| 1919 | + suffix = mt.preferredSuffix(); |
| 1920 | + |
| 1921 | + QString dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator(); |
| 1922 | + QString destination = QString("%1.%2").arg(dir + filenameWithoutSuffix, suffix); |
| 1923 | + |
| 1924 | + // If there's already a file of this name, reformat it to |
| 1925 | + // "filename (copy x).png" where x is a number, incremented until we find an |
| 1926 | + // available filename. |
| 1927 | + if (QFile::exists(destination)) { |
| 1928 | + /* |
| 1929 | + TRANSLATORS: This string is used for renaming a copied file, |
| 1930 | + when a file with the same name already exists in user's |
| 1931 | + Documents folder. |
| 1932 | + |
| 1933 | + e.g. "Manual_Aquaris_E4.5_ubuntu_EN.pdf" will become |
| 1934 | + "Manual_Aquaris_E4.5_ubuntu_EN (copy 2).pdf" |
| 1935 | + |
| 1936 | + where "2" is given by the argument "%1" |
| 1937 | + */ |
| 1938 | + QString reformattedSuffix = QString(tr("copy %1")); |
| 1939 | + |
| 1940 | + // Check if the file has already a "copy" suffix |
| 1941 | + // If so, remove it since we will update it later. |
| 1942 | + QRegExp rx(" \\(" + reformattedSuffix.arg(QString("\\d+")) + "\\)"); |
| 1943 | + int reformattedSuffixPos = filenameWithoutSuffix.lastIndexOf(rx); |
| 1944 | + |
| 1945 | + if (reformattedSuffixPos != -1) |
| 1946 | + filenameWithoutSuffix.truncate(reformattedSuffixPos); |
| 1947 | + |
| 1948 | + // Add the right "copy" suffix. |
| 1949 | + int append = 1; |
| 1950 | + while (QFile::exists(destination)) { |
| 1951 | + destination = QString("%1 (%2).%3").arg( |
| 1952 | + dir + filenameWithoutSuffix, |
| 1953 | + reformattedSuffix.arg(QString::number(append)), |
| 1954 | + suffix); |
| 1955 | + append++; |
| 1956 | + } |
| 1957 | + } |
| 1958 | + |
| 1959 | + return destination; |
| 1960 | +} |
| 1961 | + |
| 1962 | +// Return the path of the file, if found in the storageLocation paths, |
| 1963 | +// otherwise return an empty string. |
| 1964 | +// Used for prevent importing of a second copy of a file through ContentHub. |
| 1965 | +QString DocviewerFileUtils::checkIfFileAlreadyImported(const QString &filePath, const QStringList &storageLocationList) |
| 1966 | +{ |
| 1967 | + QFileInfo fi(filePath); |
| 1968 | + QStringList files; |
| 1969 | + |
| 1970 | + // Get the list of all the files in the watched folders |
| 1971 | + Q_FOREACH(const QString &storageLocation, storageLocationList) { |
| 1972 | + QDirIterator dir(storageLocation, QDir::Files | QDir::NoDotAndDotDot | QDir::Readable, |
| 1973 | + QDirIterator::Subdirectories); |
| 1974 | + |
| 1975 | + while (dir.hasNext()) |
| 1976 | + { |
| 1977 | + dir.next(); |
| 1978 | + files.append(dir.filePath()); |
| 1979 | + } |
| 1980 | + } |
| 1981 | + |
| 1982 | + // Check if there's a file with the same name in the list |
| 1983 | + Q_FOREACH(const QString &file, files) { |
| 1984 | + if (file.endsWith(fi.fileName())) { |
| 1985 | + // Seems there could be already the same file in the watched |
| 1986 | + // folders. Check also size and lastModified date. |
| 1987 | + QFileInfo fileToCheck(file); |
| 1988 | + |
| 1989 | + if (fi.size() == fileToCheck.size() && |
| 1990 | + fi.lastModified() == fileToCheck.lastModified()) |
| 1991 | + return file; |
| 1992 | + } |
| 1993 | + } |
| 1994 | + |
| 1995 | + return QString(); |
| 1996 | +} |
| 1997 | + |
| 1998 | +QString DocviewerFileUtils::getFileBaseNameFromPath(const QString &filePath) |
| 1999 | +{ |
| 2000 | + return QFileInfo(filePath).completeBaseName(); |
| 2001 | +} |
| 2002 | + |
| 2003 | +QString DocviewerFileUtils::getFileNameFromPath(const QString &filePath) |
| 2004 | +{ |
| 2005 | + return QFileInfo(filePath).fileName(); |
| 2006 | +} |
| 2007 | + |
| 2008 | +QString DocviewerFileUtils::getCanonicalPath(const QString &filePath) |
| 2009 | +{ |
| 2010 | + return QFileInfo(filePath).canonicalPath(); |
| 2011 | +} |
| 2012 | |
| 2013 | === added file 'src/plugin/file-qml-plugin/fileutils.h' |
| 2014 | --- src/plugin/file-qml-plugin/fileutils.h 1970-01-01 00:00:00 +0000 |
| 2015 | +++ src/plugin/file-qml-plugin/fileutils.h 2016-02-03 14:19:17 +0000 |
| 2016 | @@ -0,0 +1,42 @@ |
| 2017 | +/* |
| 2018 | + Copyright (C) 2015 Canonical, Ltd. |
| 2019 | + |
| 2020 | + This program is free software: you can redistribute it and/or modify |
| 2021 | + it under the terms of the GNU General Public License 3 as published by |
| 2022 | + the Free Software Foundation. |
| 2023 | + |
| 2024 | + This program is distributed in the hope that it will be useful, |
| 2025 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2026 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2027 | + GNU General Public License for more details. |
| 2028 | + |
| 2029 | + You should have received a copy of the GNU General Public License |
| 2030 | + along with this program. If not, see http://www.gnu.org/licenses/. |
| 2031 | +*/ |
| 2032 | + |
| 2033 | +#ifndef DOCVIEWER_FILEUTILS_H |
| 2034 | +#define DOCVIEWER_FILEUTILS_H |
| 2035 | + |
| 2036 | +#include <QObject> |
| 2037 | + |
| 2038 | +class DocviewerFileUtils : public QObject |
| 2039 | +{ |
| 2040 | + Q_OBJECT |
| 2041 | + |
| 2042 | +public: |
| 2043 | + Q_INVOKABLE static bool exists(const QString &path); |
| 2044 | + Q_INVOKABLE static bool copy(const QString &source, const QString &destination); |
| 2045 | + |
| 2046 | + Q_INVOKABLE static bool isFileSupported(const QString &path); |
| 2047 | + Q_INVOKABLE static QString getXdgDocumentsLocation(); |
| 2048 | + |
| 2049 | + Q_INVOKABLE static QString buildDestinationPath(const QString &destinationDir, const QString &sourcePath); |
| 2050 | + |
| 2051 | + Q_INVOKABLE static QString checkIfFileAlreadyImported(const QString &filePath, const QStringList &storageLocationList); |
| 2052 | + |
| 2053 | + Q_INVOKABLE static QString getFileBaseNameFromPath(const QString &filePath); |
| 2054 | + Q_INVOKABLE static QString getFileNameFromPath(const QString &filePath); |
| 2055 | + Q_INVOKABLE static QString getCanonicalPath(const QString &filePath); |
| 2056 | +}; |
| 2057 | + |
| 2058 | +#endif // DOCVIEWER_FILEUTILS_H |
| 2059 | |
| 2060 | === added file 'src/plugin/file-qml-plugin/ubuntuconvergenceutils.cpp' |
| 2061 | --- src/plugin/file-qml-plugin/ubuntuconvergenceutils.cpp 1970-01-01 00:00:00 +0000 |
| 2062 | +++ src/plugin/file-qml-plugin/ubuntuconvergenceutils.cpp 2016-02-03 14:19:17 +0000 |
| 2063 | @@ -0,0 +1,82 @@ |
| 2064 | +/* |
| 2065 | + Copyright (C) 2015 Stefano Verzegnassi |
| 2066 | + |
| 2067 | + This program is free software: you can redistribute it and/or modify |
| 2068 | + it under the terms of the GNU General Public License 3 as published by |
| 2069 | + the Free Software Foundation. |
| 2070 | + |
| 2071 | + This program is distributed in the hope that it will be useful, |
| 2072 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2073 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2074 | + GNU General Public License for more details. |
| 2075 | + |
| 2076 | + You should have received a copy of the GNU General Public License |
| 2077 | + along with this program. If not, see http://www.gnu.org/licenses/. |
| 2078 | +*/ |
| 2079 | + |
| 2080 | +#include "ubuntuconvergenceutils.h" |
| 2081 | +#include "InputInfo/qinputinfo.h" |
| 2082 | + |
| 2083 | +#include <QtGui/QGuiApplication> |
| 2084 | + |
| 2085 | +bool isUnity8Env() |
| 2086 | +{ |
| 2087 | + // Assume that platformName (QtUbuntu) with ubuntu |
| 2088 | + // in name means it's running on device |
| 2089 | + QString platform = QGuiApplication::platformName(); |
| 2090 | + return (platform == "ubuntu") || (platform == "ubuntumirclient"); |
| 2091 | +} |
| 2092 | + |
| 2093 | +UbuntuConvergenceUtils::UbuntuConvergenceUtils(QObject *parent) : |
| 2094 | + QObject(parent), |
| 2095 | + m_desktopMode(false), |
| 2096 | + m_mouseAttached(false), |
| 2097 | + m_inputDevicesWatcher(new QInputDeviceManager()) |
| 2098 | +{ |
| 2099 | + // Initialize signals when the watcher is ready. |
| 2100 | + // QInputDeviceManager() emits deviceAdded() signal multiple times during its |
| 2101 | + // initializations. |
| 2102 | + connect(m_inputDevicesWatcher, &QInputDeviceManager::ready, |
| 2103 | + this, &UbuntuConvergenceUtils::init); |
| 2104 | +} |
| 2105 | + |
| 2106 | +void UbuntuConvergenceUtils::init() |
| 2107 | +{ |
| 2108 | + // Connect signals |
| 2109 | + connect(m_inputDevicesWatcher, SIGNAL(deviceAdded(QString)), this, SLOT(checkPointersCount())); |
| 2110 | + connect(m_inputDevicesWatcher, SIGNAL(deviceRemoved(QString)), this, SLOT(checkPointersCount())); |
| 2111 | + |
| 2112 | + checkPointersCount(); |
| 2113 | +} |
| 2114 | + |
| 2115 | +void UbuntuConvergenceUtils::checkPointersCount() |
| 2116 | +{ |
| 2117 | + int mouseCount = m_inputDevicesWatcher->deviceCount(QInputDevice::Mouse); |
| 2118 | + int touchPadCount = m_inputDevicesWatcher->deviceCount(QInputDevice::TouchPad); |
| 2119 | + |
| 2120 | + setMouseAttached(mouseCount || touchPadCount); |
| 2121 | + setDesktopMode(isUnity8Env() || m_mouseAttached); |
| 2122 | +} |
| 2123 | + |
| 2124 | +void UbuntuConvergenceUtils::setDesktopMode(bool desktopMode) |
| 2125 | +{ |
| 2126 | + if (m_desktopMode == desktopMode) |
| 2127 | + return; |
| 2128 | + |
| 2129 | + m_desktopMode = desktopMode; |
| 2130 | + Q_EMIT desktopModeChanged(); |
| 2131 | +} |
| 2132 | + |
| 2133 | +void UbuntuConvergenceUtils::setMouseAttached(bool mouseAttached) |
| 2134 | +{ |
| 2135 | + if (m_mouseAttached == mouseAttached) |
| 2136 | + return; |
| 2137 | + |
| 2138 | + m_mouseAttached = mouseAttached; |
| 2139 | + Q_EMIT mouseAttachedChanged(); |
| 2140 | +} |
| 2141 | + |
| 2142 | +UbuntuConvergenceUtils::~UbuntuConvergenceUtils() |
| 2143 | +{ |
| 2144 | + delete m_inputDevicesWatcher; |
| 2145 | +} |
| 2146 | |
| 2147 | === added file 'src/plugin/file-qml-plugin/ubuntuconvergenceutils.h' |
| 2148 | --- src/plugin/file-qml-plugin/ubuntuconvergenceutils.h 1970-01-01 00:00:00 +0000 |
| 2149 | +++ src/plugin/file-qml-plugin/ubuntuconvergenceutils.h 2016-02-03 14:19:17 +0000 |
| 2150 | @@ -0,0 +1,56 @@ |
| 2151 | +/* |
| 2152 | + Copyright (C) 2015 Stefano Verzegnassi |
| 2153 | + |
| 2154 | + This program is free software: you can redistribute it and/or modify |
| 2155 | + it under the terms of the GNU General Public License 3 as published by |
| 2156 | + the Free Software Foundation. |
| 2157 | + |
| 2158 | + This program is distributed in the hope that it will be useful, |
| 2159 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2160 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2161 | + GNU General Public License for more details. |
| 2162 | + |
| 2163 | + You should have received a copy of the GNU General Public License |
| 2164 | + along with this program. If not, see http://www.gnu.org/licenses/. |
| 2165 | +*/ |
| 2166 | + |
| 2167 | +#ifndef DOCVIEWER_CONVERGENCEUTILS_H |
| 2168 | +#define DOCVIEWER_CONVERGENCEUTILS_H |
| 2169 | + |
| 2170 | +#include <QObject> |
| 2171 | + |
| 2172 | +class QInputDeviceManager; |
| 2173 | + |
| 2174 | +class UbuntuConvergenceUtils : public QObject |
| 2175 | +{ |
| 2176 | + Q_OBJECT |
| 2177 | + Q_PROPERTY(bool desktopMode READ desktopMode NOTIFY desktopModeChanged) |
| 2178 | + Q_PROPERTY(bool mouseAttached READ mouseAttached NOTIFY mouseAttachedChanged) |
| 2179 | + |
| 2180 | +public: |
| 2181 | + UbuntuConvergenceUtils(QObject *parent = 0); |
| 2182 | + ~UbuntuConvergenceUtils(); |
| 2183 | + |
| 2184 | + bool desktopMode() const { return m_desktopMode; } |
| 2185 | + bool mouseAttached() const { return m_mouseAttached; } |
| 2186 | + |
| 2187 | +Q_SIGNALS: |
| 2188 | + void desktopModeChanged(); |
| 2189 | + void mouseAttachedChanged(); |
| 2190 | + |
| 2191 | +private slots: |
| 2192 | + void checkPointersCount(); |
| 2193 | + void init(); |
| 2194 | + |
| 2195 | +private: |
| 2196 | + bool m_desktopMode; |
| 2197 | + bool m_mouseAttached; |
| 2198 | + |
| 2199 | +private: |
| 2200 | + QInputDeviceManager* m_inputDevicesWatcher; |
| 2201 | + |
| 2202 | + void setDesktopMode(bool desktopMode); |
| 2203 | + void setMouseAttached(bool mouseAttached); |
| 2204 | +}; |
| 2205 | + |
| 2206 | +#endif // DOCVIEWER_CONVERGENCEUTILS_H |

Moved the MP to a new branch