Merge lp:~dpm/ubuntu-filemanager-app/include-plugin into lp:ubuntu-filemanager-app
- include-plugin
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Nicholas Skaggs | ||||||||
Approved revision: | 171 | ||||||||
Merged at revision: | 160 | ||||||||
Proposed branch: | lp:~dpm/ubuntu-filemanager-app/include-plugin | ||||||||
Merge into: | lp:ubuntu-filemanager-app | ||||||||
Diff against target: |
15999 lines (+15391/-104) 69 files modified
.bzrignore (+2/-0) CMakeLists.txt (+25/-15) apparmor.json (+2/-2) click/CMakeLists.txt (+0/-8) debian/changelog (+7/-0) debian/control (+19/-2) debian/qtdeclarative5-nemo-qml-plugin-folderlistmodel.install (+1/-0) manifest.json (+12/-11) plugins.json (+0/-6) src/CMakeLists.txt (+2/-0) src/app/CMakeLists.txt (+24/-0) src/app/main.cpp (+114/-0) src/plugin/CMakeLists.txt (+7/-0) src/plugin/folderlistmodel/CMakeLists.txt (+54/-0) src/plugin/folderlistmodel/README (+14/-0) src/plugin/folderlistmodel/clipboard.cpp (+495/-0) src/plugin/folderlistmodel/clipboard.h (+132/-0) src/plugin/folderlistmodel/diritemabstractlistmodel.h (+46/-0) src/plugin/folderlistmodel/diriteminfo.cpp (+345/-0) src/plugin/folderlistmodel/diriteminfo.h (+123/-0) src/plugin/folderlistmodel/dirmodel.cpp (+1563/-0) src/plugin/folderlistmodel/dirmodel.h (+430/-0) src/plugin/folderlistmodel/dirselection.cpp (+298/-0) src/plugin/folderlistmodel/dirselection.h (+116/-0) src/plugin/folderlistmodel/externalfswatcher.cpp (+114/-0) src/plugin/folderlistmodel/externalfswatcher.h (+68/-0) src/plugin/folderlistmodel/filecompare.cpp (+108/-0) src/plugin/folderlistmodel/filecompare.h (+51/-0) src/plugin/folderlistmodel/filesystemaction.cpp (+1302/-0) src/plugin/folderlistmodel/filesystemaction.h (+241/-0) src/plugin/folderlistmodel/fmutil.cpp (+132/-0) src/plugin/folderlistmodel/fmutil.h (+46/-0) src/plugin/folderlistmodel/folderlistmodel.pri (+44/-0) src/plugin/folderlistmodel/folderlistmodel.pro (+39/-0) src/plugin/folderlistmodel/imageprovider.cpp (+93/-0) src/plugin/folderlistmodel/imageprovider.h (+29/-0) src/plugin/folderlistmodel/iorequest.cpp (+185/-0) src/plugin/folderlistmodel/iorequest.h (+109/-0) src/plugin/folderlistmodel/iorequestworker.cpp (+100/-0) src/plugin/folderlistmodel/iorequestworker.h (+61/-0) src/plugin/folderlistmodel/ioworkerthread.cpp (+64/-0) src/plugin/folderlistmodel/ioworkerthread.h (+52/-0) src/plugin/folderlistmodel/plugin.cpp (+58/-0) src/plugin/folderlistmodel/plugin.h (+75/-0) src/plugin/folderlistmodel/qmldir (+2/-0) src/plugin/folderlistmodel/trash/qtrashdir.cpp (+335/-0) src/plugin/folderlistmodel/trash/qtrashdir.h (+128/-0) src/plugin/test_folderlistmodel/regression/media_asx.h (+21/-0) src/plugin/test_folderlistmodel/regression/media_xspf.h (+135/-0) src/plugin/test_folderlistmodel/regression/regression_folderlilstmodel.pro (+30/-0) src/plugin/test_folderlistmodel/regression/sound_7200_amr.h (+87/-0) src/plugin/test_folderlistmodel/regression/sound_mp3.h (+3598/-0) src/plugin/test_folderlistmodel/regression/tempfiles.cpp (+207/-0) src/plugin/test_folderlistmodel/regression/tempfiles.h (+95/-0) src/plugin/test_folderlistmodel/regression/testonly_pdf.h (+641/-0) src/plugin/test_folderlistmodel/regression/tst_folderlistmodel.cpp (+2483/-0) src/plugin/test_folderlistmodel/regression/ubuntu_touch_run.sh (+11/-0) src/plugin/test_folderlistmodel/results/DesktopQt4.74.txt (+47/-0) src/plugin/test_folderlistmodel/results/DesktopQt5.0.txt (+53/-0) src/plugin/test_folderlistmodel/results/NemoEmulatorQ8.43.txt (+36/-0) src/plugin/test_folderlistmodel/results/openFiles.Readme.txt (+7/-0) src/plugin/test_folderlistmodel/simpleUI/main.cpp (+32/-0) src/plugin/test_folderlistmodel/simpleUI/simplelist.cpp (+281/-0) src/plugin/test_folderlistmodel/simpleUI/simplelist.h (+74/-0) src/plugin/test_folderlistmodel/simpleUI/simplelist.ui (+219/-0) src/plugin/test_folderlistmodel/simpleUI/simpleui.pro (+32/-0) tests/autopilot/ubuntu_filemanager_app/tests/__init__.py (+35/-37) ubuntu-filemanager-app.in (+0/-3) ubuntu-filemanager-app.qmlproject (+0/-20) |
||||||||
To merge this branch: | bzr merge lp:~dpm/ubuntu-filemanager-app/include-plugin | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Nicholas Skaggs (community) | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Carlos Jose Mazieri | Approve | ||
Sergio Schvezov (community) | Needs Fixing | ||
Review via email: mp+213368@code.launchpad.net |
Commit message
Merge the C++ folderlistmodel plugin into the app's source tree
Description of the change
After a conversation with sergiusens it seems we can no longer build the File Manager app click package in our CI infrastructure if the plugin lives outside of the app's source tree.
This merge proposal does exactly that: bring the plugin into the app's source tree. It should be considered as work in progress, but as I'm not a cmake expert, I'm sending it as a request for feedback before merging it in.
What works:
- Project builds in Qt Creator
- click-buddy builds and packages the plugin and the app successfully
- Ctrl+R in Qt Creator runs the app
- Debian packaging: two independent packages (app and plugin) are generated
What's not yet implemented:
- The plugin depends on taglib1-dev. If it's not installed, cmake will fail. It'd be nice to add a check for it, but it seems cmake has only in-built checks for a certain number of libraries.
What will be addressed in a separate MP:
- Fix copyright headers of the plugin, which don't seem to point to the original sources
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Sergio Schvezov (sergiusens) wrote : | # |
20 + set(EXEC "qmlscene -qt5 qml/${MAIN_QML} -I ../plugin")
Prefer to use the upstart app launch set import dirs of lib/$arch/ and remove -I ../plugin"
If not set QT_IMPORTS_DIR will need to be set to this.
Additionally, and not related, I thought this project was forked from org.nemo but the copyright headers have:
197 + * Copyright 2014 Canonical Ltd.
198 + * Copyright 2014 Carlos J Mazieri <email address hidden>
and no trace of the original.
David Planella (dpm) wrote : | # |
On Tue, Apr 1, 2014 at 10:12 AM, Sergio Schvezov <
<email address hidden>> wrote:
> Review: Needs Fixing
>
> 20 + set(EXEC "qmlscene -qt5 qml/${MAIN_QML} -I ../plugin")
>
> Prefer to use the upstart app launch set import dirs of lib/$arch/ and
> remove -I ../plugin"
> If not set QT_IMPORTS_DIR will need to be set to this.
>
>
Ok, thanks for the review! I think I've addressed this now, at least for
the click package build.
>
> Additionally, and not related, I thought this project was forked from
> org.nemo but the copyright headers have:
> 197 + * Copyright 2014 Canonical Ltd.
> 198 + * Copyright 2014 Carlos J Mazieri <email address hidden>
>
> and no trace of the original.
>
Oh, wow, I hadn't seen it. Yes, this needs to be addressed for all headers,
I'll send a separate MP fixing this.
Sergio Schvezov (sergiusens) wrote : | # |
> On Tue, Apr 1, 2014 at 10:12 AM, Sergio Schvezov <
> <email address hidden>> wrote:
>
> > Review: Needs Fixing
> >
> > 20 + set(EXEC "qmlscene -qt5 qml/${MAIN_QML} -I ../plugin")
> >
> > Prefer to use the upstart app launch set import dirs of lib/$arch/ and
> > remove -I ../plugin"
> > If not set QT_IMPORTS_DIR will need to be set to this.
> >
> >
> Ok, thanks for the review! I think I've addressed this now, at least for
> the click package build.
Seems this looks good now
Sergio Schvezov (sergiusens) wrote : | # |
95 +add_executable
108 + install(TARGETS filemanager DESTINATION ${BIN_DIR})
I thought filemanager was launched with qmlscene $@
Is there a reason for building this? If so the exec needs to indeed change; but I'm guessing this isn't supposed to be there
David Planella (dpm) wrote : | # |
On Tue, Apr 1, 2014 at 4:28 PM, Sergio Schvezov <
<email address hidden>> wrote:
> 95 +add_executable
> 108 + install(TARGETS filemanager DESTINATION ${BIN_DIR})
>
> I thought filemanager was launched with qmlscene $@
>
> Is there a reason for building this? If so the exec needs to indeed
> change; but I'm guessing this isn't supposed to be there
>
This is intentional. The original intention was to use qmlscene, but as
pointed out in the original description, then Qt Creator could not launch
the app. After digging deeper into this and a conversation with zbenjamin,
it seems Qt Creator's cmake plugin cannot handle mixed (QML + C++) projects
to be launched with qmlscene, as it cannot actually detect which type of
project it is.
So the suggestion was to use a binary that does the work of qmlscene, so
that Qt Creator can launch that. Essentially, we're now doing what
Reminders does too.
So if this is needed, which exec needs to be changed?
Carlos Jose Mazieri (carlos-mazieri) wrote : | # |
> 20 + set(EXEC "qmlscene -qt5 qml/${MAIN_QML} -I ../plugin")
>
> Prefer to use the upstart app launch set im3port dirs of lib/$arch/ and remove
> -I ../plugin"
> If not set QT_IMPORTS_DIR will need to be set to this.
>
>
> Additionally, and not related, I thought this project was forked from org.nemo
> but the copyright headers have:
> 197 + * Copyright 2014 Canonical Ltd.
> 198 + * Copyright 2014 Carlos J Mazieri <email address hidden>
>
> and no trace of the original.
The project was forked from Nemo Mobile, orignal files were using BSD license, several files were added I just mentioned GPLv3 as result of some discussion we had about it in the meetings.
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:160
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:161
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:167
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Carlos Jose Mazieri (carlos-mazieri) wrote : | # |
It looks OK to me, everything is there.
I downloaded and tested https:/
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:168
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Nicholas Skaggs (nskaggs) wrote : | # |
Looking close!
Nicholas Skaggs (nskaggs) wrote : | # |
I'm proposing a merge to solve the AP launch issue.
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:170
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Nicholas Skaggs (nskaggs) wrote : | # |
Work happening here:
https:/
I've kicked off a build of jenkins including my commits, and I'll iterate if needed till we see proper launching.
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:171
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Nicholas Skaggs (nskaggs) wrote : | # |
All working on my side; merge away :-)
https:/
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:171
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Nicholas Skaggs (nskaggs) : | # |
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2013-12-30 20:31:12 +0000 |
3 | +++ .bzrignore 2014-04-15 08:19:22 +0000 |
4 | @@ -6,3 +6,5 @@ |
5 | debian/app-template/ |
6 | debian/*.debhelper.log |
7 | debian/*.substvars |
8 | +.excludes |
9 | +*.user |
10 | |
11 | === modified file 'CMakeLists.txt' |
12 | --- CMakeLists.txt 2014-03-26 14:25:39 +0000 |
13 | +++ CMakeLists.txt 2014-04-15 08:19:22 +0000 |
14 | @@ -1,6 +1,9 @@ |
15 | -project(com.ubuntu.filemanager) |
16 | +project(com.ubuntu.filemanager C CXX) |
17 | cmake_minimum_required(VERSION 2.8.9) |
18 | |
19 | +set(CMAKE_AUTOMOC ON) |
20 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-permissive -pedantic -Wall -Wextra -fPIC") |
21 | + |
22 | # Standard install paths |
23 | include(GNUInstallDirs) |
24 | |
25 | @@ -8,49 +11,56 @@ |
26 | option(CLICK_MODE "Installs to a contained location" off) |
27 | |
28 | set(APP_NAME filemanager) |
29 | -set(DESKTOP_FILE "${PROJECT_NAME}_${APP_NAME}.desktop") |
30 | +set(DESKTOP_FILE "${PROJECT_NAME}.desktop") |
31 | set(URLS_FILE "${PROJECT_NAME}_${APP_NAME}.url-dispatcher") |
32 | set(APP_HARDCODE ubuntu-filemanager-app) |
33 | set(MAIN_QML ${APP_HARDCODE}.qml) |
34 | set(ICON_FILE filemanager64.png) |
35 | set(AUTOPILOT_DIR ubuntu_filemanager_app) |
36 | +set(EXEC "filemanager") |
37 | |
38 | if(CLICK_MODE) |
39 | if(NOT DEFINED BZR_SOURCE) |
40 | set(BZR_SOURCE "lp:${APP_HARDCODE}") |
41 | message("-- Setting BZR_SOURCE to ${BZR_SOURCE}") |
42 | endif(NOT DEFINED BZR_SOURCE) |
43 | + # Find out the architecture for package building |
44 | + # to determine the plugin's installation path |
45 | + execute_process( |
46 | + COMMAND dpkg-architecture -qDEB_HOST_MULTIARCH |
47 | + OUTPUT_VARIABLE ARCH_TRIPLET |
48 | + OUTPUT_STRIP_TRAILING_WHITESPACE |
49 | + ) |
50 | set(CMAKE_INSTALL_PREFIX /) |
51 | set(CMAKE_INSTALL_BINDIR /) |
52 | set(DATA_DIR /) |
53 | set(ICON ${ICON_FILE}) |
54 | - set(EXEC "qmlscene -qt5 ${MAIN_QML}") |
55 | + set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}") |
56 | + set(BIN_DIR /lib/${ARCH_TRIPLET}/bin) |
57 | set(DESKTOP_DIR ${DATA_DIR}) |
58 | set(URLS_DIR ${DATA_DIR}) |
59 | + install(FILES manifest.json apparmor.json DESTINATION ${CMAKE_INSTALL_PREFIX}) |
60 | else(CLICK_MODE) |
61 | + execute_process( |
62 | + COMMAND qmake -query QT_INSTALL_QML |
63 | + OUTPUT_VARIABLE QT_IMPORTS_DIR |
64 | + OUTPUT_STRIP_TRAILING_WHITESPACE |
65 | + ) |
66 | set(DATA_DIR ${CMAKE_INSTALL_DATADIR}/${APP_HARDCODE}) |
67 | - set(EXEC ${APP_HARDCODE}) |
68 | set(ICON ${CMAKE_INSTALL_PREFIX}/${DATA_DIR}/${ICON_FILE}) |
69 | - configure_file(${APP_HARDCODE}.in |
70 | - ${CMAKE_CURRENT_BINARY_DIR}/${APP_HARDCODE}) |
71 | - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${APP_HARDCODE} |
72 | - DESTINATION ${CMAKE_INSTALL_BINDIR}) |
73 | set(DESKTOP_DIR ${CMAKE_INSTALL_DATADIR}/applications) |
74 | set(URLS_DIR ${CMAKE_INSTALL_DATADIR}/url-dispatcher/urls) |
75 | endif(CLICK_MODE) |
76 | |
77 | file(GLOB_RECURSE I18N_SRC_FILES |
78 | RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} |
79 | - rc/**.qml desktop/**.desktop.in) |
80 | + src/app/**.qml *.desktop.in) |
81 | list(SORT I18N_SRC_FILES) |
82 | |
83 | - |
84 | file(GLOB SRC_FILES |
85 | RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} |
86 | - *.qml *.js *.png *.js *.json) |
87 | -install(DIRECTORY ui components icons |
88 | - DESTINATION ${DATA_DIR}) |
89 | -install(FILES ${SRC_FILES} ${ICON_FILE} DESTINATION ${DATA_DIR}) |
90 | + *.qml *.js *.png *.js) |
91 | +install(FILES ${SRC_FILES} DESTINATION ${DATA_DIR}) |
92 | |
93 | configure_file(${DESKTOP_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE}) |
94 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE} |
95 | @@ -61,6 +71,6 @@ |
96 | # Tests |
97 | enable_testing() |
98 | |
99 | -add_subdirectory(click) |
100 | add_subdirectory(po) |
101 | add_subdirectory(tests) |
102 | +add_subdirectory(src) |
103 | |
104 | === renamed file 'click/apparmor.json' => 'apparmor.json' |
105 | --- click/apparmor.json 2014-01-31 20:03:12 +0000 |
106 | +++ apparmor.json 2014-04-15 08:19:22 +0000 |
107 | @@ -1,4 +1,4 @@ |
108 | { |
109 | - "policy_version": 1.0, |
110 | + "policy_version": 1.1, |
111 | "template": "unconfined" |
112 | -} |
113 | \ No newline at end of file |
114 | +} |
115 | |
116 | === removed directory 'click' |
117 | === removed file 'click/CMakeLists.txt' |
118 | --- click/CMakeLists.txt 2014-01-31 20:03:12 +0000 |
119 | +++ click/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
120 | @@ -1,8 +0,0 @@ |
121 | -if(CLICK_MODE) |
122 | - if(NOT BZR_REVNO) |
123 | - set(BZR_REVNO "latest") |
124 | - endif(NOT BZR_REVNO) |
125 | - configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json) |
126 | - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json apparmor.json |
127 | - DESTINATION ${CMAKE_INSTALL_PREFIX}) |
128 | -endif(CLICK_MODE) |
129 | |
130 | === renamed file 'com.ubuntu.filemanager_filemanager.desktop.in' => 'com.ubuntu.filemanager.desktop.in' |
131 | === modified file 'debian/changelog' |
132 | --- debian/changelog 2013-04-19 20:30:19 +0000 |
133 | +++ debian/changelog 2014-04-15 08:19:22 +0000 |
134 | @@ -1,3 +1,10 @@ |
135 | +ubuntu-filemanager-app (0.2) trusty; urgency=medium |
136 | + |
137 | + * Merged the plugin code into the main tree, now the main source package |
138 | + generates a binary package for the app and another for the plugin |
139 | + |
140 | + -- David Planella <david.planella@ubuntu.com> Thu, 10 Apr 2014 09:23:41 +0200 |
141 | + |
142 | ubuntu-filemanager-app (0.1.1) raring; urgency=low |
143 | |
144 | * Initial release |
145 | |
146 | === modified file 'debian/control' |
147 | --- debian/control 2014-03-07 21:10:42 +0000 |
148 | +++ debian/control 2014-04-15 08:19:22 +0000 |
149 | @@ -4,14 +4,19 @@ |
150 | Build-Depends: cmake, |
151 | debhelper (>= 9), |
152 | python, |
153 | -Standards-Version: 3.9.4 |
154 | + qtbase5-dev, |
155 | + qtdeclarative5-dev, |
156 | + qt5-default, |
157 | + pkg-kde-tools, |
158 | + libtag1-dev, |
159 | +Standards-Version: 3.9.5 |
160 | Section: misc |
161 | Homepage: https://launchpad.net/ubuntu-filemanager-app |
162 | Vcs-Bzr: https://code.launchpad.net/~ubuntu-filemanager-dev/ubuntu-filemanager-app/trunk |
163 | |
164 | Package: ubuntu-filemanager-app |
165 | Section: misc |
166 | -Architecture: all |
167 | +Architecture: any |
168 | Depends: qmlscene, |
169 | qtdeclarative5-hud1.0, |
170 | qtdeclarative5-nemo-qml-plugin-folderlistmodel, |
171 | @@ -22,6 +27,18 @@ |
172 | Description: File Manager application |
173 | Core File Manager application |
174 | |
175 | +Package: qtdeclarative5-nemo-qml-plugin-folderlistmodel |
176 | +Architecture: any |
177 | +Multi-Arch: same |
178 | +Depends: ${misc:Depends}, |
179 | + ${shlibs:Depends}, |
180 | +Description: Nemo QML plugin - folder list model |
181 | + Qt is a cross-platform C++ application framework. Qt's primary feature |
182 | + is its rich set of widgets that provide standard GUI functionality. |
183 | + . |
184 | + This package contains the Folder List model plugin of the Nemo QML |
185 | + plugins collection. |
186 | + |
187 | Package: ubuntu-filemanager-app-autopilot |
188 | Architecture: all |
189 | Depends: libautopilot-qt (>= 1.4), |
190 | |
191 | === added file 'debian/qtdeclarative5-nemo-qml-plugin-folderlistmodel.install' |
192 | --- debian/qtdeclarative5-nemo-qml-plugin-folderlistmodel.install 1970-01-01 00:00:00 +0000 |
193 | +++ debian/qtdeclarative5-nemo-qml-plugin-folderlistmodel.install 2014-04-15 08:19:22 +0000 |
194 | @@ -0,0 +1,1 @@ |
195 | +usr/lib/*/qt5/qml/org/nemomobile/folderlistmodel/ |
196 | |
197 | === renamed file 'click/manifest.json.in' => 'manifest.json' |
198 | --- click/manifest.json.in 2014-04-11 22:15:18 +0000 |
199 | +++ manifest.json 2014-04-15 08:19:22 +0000 |
200 | @@ -1,23 +1,24 @@ |
201 | { |
202 | "description": "File Manager application", |
203 | - "framework": "ubuntu-sdk-13.10", |
204 | + "framework": "ubuntu-sdk-14.04-dev1", |
205 | + "architecture": "armhf", |
206 | "hooks": { |
207 | - "@APP_NAME@": { |
208 | + "filemanager": { |
209 | "apparmor": "apparmor.json", |
210 | - "desktop": "@DESKTOP_FILE@", |
211 | - "urls": "@URLS_FILE@" |
212 | + "desktop": "com.ubuntu.filemanager.desktop", |
213 | + "urls": "com.ubuntu.filemanager_filemanager.url-dispatcher" |
214 | } |
215 | }, |
216 | - "icon": "@ICON@", |
217 | + "icon": "filemanager64.png", |
218 | "maintainer": "Ubuntu App Cats <ubuntu-touch-coreapps@lists.launchpad.net>", |
219 | - "name": "@PROJECT_NAME@", |
220 | + "name": "com.ubuntu.filemanager", |
221 | "title": "File Manager", |
222 | - "version": "0.1.1.@BZR_REVNO@", |
223 | + "version": "0.3", |
224 | "x-source": { |
225 | - "vcs-bzr": "@BZR_SOURCE@", |
226 | - "vcs-bzr-revno": "@BZR_REVNO@" |
227 | + "vcs-bzr": "lp:ubuntu-filemanager-app", |
228 | + "vcs-bzr-revno": "latest" |
229 | }, |
230 | "x-test": { |
231 | - "autopilot": "@AUTOPILOT_DIR@" |
232 | + "autopilot": "ubuntu_filemanager_app" |
233 | } |
234 | -} |
235 | +} |
236 | \ No newline at end of file |
237 | |
238 | === removed file 'plugins.json' |
239 | --- plugins.json 2013-10-10 16:43:14 +0000 |
240 | +++ plugins.json 1970-01-01 00:00:00 +0000 |
241 | @@ -1,6 +0,0 @@ |
242 | -[ |
243 | -{ |
244 | - "package": "qtdeclarative5-nemo-qml-plugin-folderlistmodel", |
245 | - "ppa": "ppa:ubuntu-touch-coreapps-drivers/daily" |
246 | -} |
247 | -] |
248 | |
249 | === added directory 'src' |
250 | === added file 'src/CMakeLists.txt' |
251 | --- src/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
252 | +++ src/CMakeLists.txt 2014-04-15 08:19:22 +0000 |
253 | @@ -0,0 +1,2 @@ |
254 | +add_subdirectory(plugin) |
255 | +add_subdirectory(app) |
256 | |
257 | === added directory 'src/app' |
258 | === added file 'src/app/CMakeLists.txt' |
259 | --- src/app/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
260 | +++ src/app/CMakeLists.txt 2014-04-15 08:19:22 +0000 |
261 | @@ -0,0 +1,24 @@ |
262 | +file(GLOB_RECURSE QML_SRCS *.qml *.js) |
263 | + |
264 | +set(filemanager_SRCS |
265 | + main.cpp |
266 | + ${QML_SRCS} |
267 | +) |
268 | + |
269 | +add_executable(filemanager ${filemanager_SRCS}) |
270 | + |
271 | +qt5_use_modules(filemanager Gui Qml Quick) |
272 | + |
273 | +if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") |
274 | +add_custom_target(filemanager-qmlfiles ALL |
275 | + COMMAND cp -r ${CMAKE_CURRENT_SOURCE_DIR}/qml ${CMAKE_CURRENT_BINARY_DIR} |
276 | + DEPENDS ${QMLFILES} |
277 | +) |
278 | +endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") |
279 | + |
280 | +install(DIRECTORY qml DESTINATION ${DATA_DIR}) |
281 | +if(CLICK_MODE) |
282 | + install(TARGETS filemanager DESTINATION ${BIN_DIR}) |
283 | +else() |
284 | + install(TARGETS filemanager RUNTIME DESTINATION bin) |
285 | +endif() |
286 | |
287 | === added file 'src/app/main.cpp' |
288 | --- src/app/main.cpp 1970-01-01 00:00:00 +0000 |
289 | +++ src/app/main.cpp 2014-04-15 08:19:22 +0000 |
290 | @@ -0,0 +1,114 @@ |
291 | +/* |
292 | + * Copyright: 2013 - 2014 Canonical, Ltd |
293 | + * |
294 | + * This file is part of ubuntu-filemanager-app |
295 | + * |
296 | + * ubuntu-filemanager-app is free software: you can redistribute it and/or modify |
297 | + * it under the terms of the GNU General Public License as published by |
298 | + * the Free Software Foundation, either version 3 of the License, or |
299 | + * (at your option) any later version. |
300 | + * |
301 | + * ubuntu-filemanager-app is distributed in the hope that it will be useful, |
302 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
303 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
304 | + * GNU General Public License for more details. |
305 | + * |
306 | + * You should have received a copy of the GNU General Public License |
307 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
308 | + * |
309 | + * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
310 | + * Riccardo Padovani <rpadovani@ubuntu.com> |
311 | + * David Planella <david.planella@ubuntu.com> |
312 | + */ |
313 | + |
314 | +#include <QtGui/QGuiApplication> |
315 | +#include <QtQuick/QQuickView> |
316 | +#include <QtQml/QtQml> |
317 | +#include <QLibrary> |
318 | + |
319 | +#include <QDebug> |
320 | + |
321 | +int main(int argc, char *argv[]) |
322 | +{ |
323 | + QGuiApplication a(argc, argv); |
324 | + QQuickView view; |
325 | + view.setResizeMode(QQuickView::SizeRootObjectToView); |
326 | + |
327 | + // Set up import paths |
328 | + QStringList importPathList = view.engine()->importPathList(); |
329 | + importPathList.append(QDir::currentPath() + "/../plugin/"); |
330 | + |
331 | + QStringList args = a.arguments(); |
332 | + if (args.contains("-h") || args.contains("--help")) { |
333 | + qDebug() << "usage: " + args.at(0) + " [-p|--phone] [-t|--tablet] [-h|--help] [-I <path>]"; |
334 | + qDebug() << " -p|--phone If running on Desktop, start in a phone sized window."; |
335 | + qDebug() << " -t|--tablet If running on Desktop, start in a tablet sized window."; |
336 | + qDebug() << " -h|--help Print this help."; |
337 | + qDebug() << " -I <path> Give a path for an additional QML import directory. May be used multiple times."; |
338 | + qDebug() << " -q <qmlfile> Give an alternative location for the main qml file."; |
339 | + return 0; |
340 | + } |
341 | + |
342 | + QString qmlfile; |
343 | + for (int i = 0; i < args.count(); i++) { |
344 | + if (args.at(i) == "-I" && args.count() > i + 1) { |
345 | + QString addedPath = args.at(i+1); |
346 | + if (addedPath.startsWith('.')) { |
347 | + addedPath = addedPath.right(addedPath.length() - 1); |
348 | + addedPath.prepend(QDir::currentPath()); |
349 | + } |
350 | + importPathList.append(addedPath); |
351 | + } else if (args.at(i) == "-q" && args.count() > i + 1) { |
352 | + qmlfile = args.at(i+1); |
353 | + } |
354 | + } |
355 | + |
356 | + if (args.contains(QLatin1String("-testability")) || getenv("QT_LOAD_TESTABILITY")) { |
357 | + QLibrary testLib(QLatin1String("qttestability")); |
358 | + if (testLib.load()) { |
359 | + typedef void (*TasInitialize)(void); |
360 | + TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init"); |
361 | + if (initFunction) { |
362 | + initFunction(); |
363 | + } else { |
364 | + qCritical("Library qttestability resolve failed!"); |
365 | + } |
366 | + } else { |
367 | + qCritical("Library qttestability load failed!"); |
368 | + } |
369 | + } |
370 | + |
371 | + view.engine()->rootContext()->setContextProperty("tablet", QVariant(false)); |
372 | + view.engine()->rootContext()->setContextProperty("phone", QVariant(false)); |
373 | + if (args.contains("-t") || args.contains("--tablet")) { |
374 | + qDebug() << "running in tablet mode"; |
375 | + view.engine()->rootContext()->setContextProperty("tablet", QVariant(true)); |
376 | + } else if (args.contains("-p") || args.contains("--phone")){ |
377 | + qDebug() << "running in phone mode"; |
378 | + view.engine()->rootContext()->setContextProperty("phone", QVariant(true)); |
379 | + } else if (qgetenv("QT_QPA_PLATFORM") != "ubuntumirclient") { |
380 | + // Default to tablet size on X11 |
381 | + view.engine()->rootContext()->setContextProperty("tablet", QVariant(true)); |
382 | + } |
383 | + |
384 | + view.engine()->setImportPathList(importPathList); |
385 | + |
386 | + // load the qml file |
387 | + if (qmlfile.isEmpty()) { |
388 | + QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DataLocation); |
389 | + paths.prepend("."); |
390 | + |
391 | + foreach (const QString &path, paths) { |
392 | + QFileInfo fi(path + "/qml/ubuntu-filemanager-app.qml"); |
393 | + if (fi.exists()) { |
394 | + qmlfile = path + "/qml/ubuntu-filemanager-app.qml"; |
395 | + break; |
396 | + } |
397 | + } |
398 | + } |
399 | + qDebug() << "using main qml file from:" << qmlfile; |
400 | + view.setSource(QUrl::fromLocalFile(qmlfile)); |
401 | + view.show(); |
402 | + |
403 | + return a.exec(); |
404 | +} |
405 | |
406 | === renamed directory 'components' => 'src/app/qml' |
407 | === added directory 'src/app/qml/components' |
408 | === renamed file 'components/AutoSpacedGrid.qml' => 'src/app/qml/components/AutoSpacedGrid.qml' |
409 | === renamed file 'components/FolderIconDelegate.qml' => 'src/app/qml/components/FolderIconDelegate.qml' |
410 | === renamed file 'components/FolderIconView.qml' => 'src/app/qml/components/FolderIconView.qml' |
411 | === renamed file 'components/FolderListDelegate.qml' => 'src/app/qml/components/FolderListDelegate.qml' |
412 | === renamed file 'components/FolderListView.qml' => 'src/app/qml/components/FolderListView.qml' |
413 | === renamed file 'components/PathBar.qml' => 'src/app/qml/components/PathBar.qml' |
414 | === renamed file 'components/PlacesSidebar.qml' => 'src/app/qml/components/PlacesSidebar.qml' |
415 | === renamed file 'components/Sidebar.qml' => 'src/app/qml/components/Sidebar.qml' |
416 | === renamed file 'components/SuruSheetStyle.qml' => 'src/app/qml/components/SuruSheetStyle.qml' |
417 | === renamed file 'components/VerticalDivider.qml' => 'src/app/qml/components/VerticalDivider.qml' |
418 | === renamed file 'ubuntu-filemanager-app.qml' => 'src/app/qml/ubuntu-filemanager-app.qml' |
419 | === renamed directory 'ui' => 'src/app/qml/ui' |
420 | === added directory 'src/plugin' |
421 | === added file 'src/plugin/CMakeLists.txt' |
422 | --- src/plugin/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
423 | +++ src/plugin/CMakeLists.txt 2014-04-15 08:19:22 +0000 |
424 | @@ -0,0 +1,7 @@ |
425 | +include(FindPkgConfig) |
426 | +find_package(Qt5Core) |
427 | +find_package(Qt5Qml) |
428 | +find_package(Qt5Quick) |
429 | +find_package(Qt5Widgets) |
430 | + |
431 | +add_subdirectory(folderlistmodel) |
432 | |
433 | === added directory 'src/plugin/folderlistmodel' |
434 | === added file 'src/plugin/folderlistmodel/CMakeLists.txt' |
435 | --- src/plugin/folderlistmodel/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
436 | +++ src/plugin/folderlistmodel/CMakeLists.txt 2014-04-15 08:19:22 +0000 |
437 | @@ -0,0 +1,54 @@ |
438 | +include_directories( |
439 | + ${CMAKE_CURRENT_SOURCE_DIR} |
440 | +) |
441 | + |
442 | +set(folderlistmodel_SRCS |
443 | + clipboard.cpp |
444 | + clipboard.h |
445 | + diritemabstractlistmodel.h |
446 | + diriteminfo.cpp |
447 | + diriteminfo.h |
448 | + dirmodel.cpp |
449 | + dirmodel.h |
450 | + dirselection.cpp |
451 | + dirselection.h |
452 | + externalfswatcher.cpp |
453 | + externalfswatcher.h |
454 | + filecompare.cpp |
455 | + filecompare.h |
456 | + filesystemaction.cpp |
457 | + filesystemaction.h |
458 | + fmutil.cpp |
459 | + fmutil.h |
460 | + imageprovider.cpp |
461 | + imageprovider.h |
462 | + iorequest.cpp |
463 | + iorequest.h |
464 | + iorequestworker.cpp |
465 | + iorequestworker.h |
466 | + ioworkerthread.cpp |
467 | + ioworkerthread.h |
468 | + plugin.cpp |
469 | + plugin.h |
470 | + trash/qtrashdir.cpp |
471 | + trash/qtrashdir.h |
472 | +) |
473 | + |
474 | +add_library(folderlistmodel MODULE |
475 | + ${folderlistmodel_SRCS} |
476 | +) |
477 | + |
478 | +qt5_use_modules(folderlistmodel Gui Qml Quick Widgets) |
479 | + |
480 | +# Copy qmldir file to build dir for running in QtCreator |
481 | +if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") |
482 | + add_custom_target(folderlistmodel-qmldir ALL |
483 | + COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/qmldir ${CMAKE_CURRENT_BINARY_DIR} |
484 | + DEPENDS ${QMLFILES} |
485 | + ) |
486 | +endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") |
487 | + |
488 | +# Install plugin file |
489 | +install(TARGETS folderlistmodel DESTINATION ${QT_IMPORTS_DIR}/org/nemomobile/folderlistmodel/) |
490 | +install(FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/org/nemomobile/folderlistmodel/) |
491 | + |
492 | |
493 | === added file 'src/plugin/folderlistmodel/README' |
494 | --- src/plugin/folderlistmodel/README 1970-01-01 00:00:00 +0000 |
495 | +++ src/plugin/folderlistmodel/README 2014-04-15 08:19:22 +0000 |
496 | @@ -0,0 +1,14 @@ |
497 | +Building and installing |
498 | +======================= |
499 | + |
500 | +qmake [available-defines] |
501 | + |
502 | + where available-debug-messages are: |
503 | + DEBUG_MESSAGES -> enable generic debug messages use: qmake "DEINES+=DEBUG_MESSAGES" |
504 | + DEBUG_EXT_FS_WATCHER -> enable External File System Watcher messages use: qmake "DEINES+=DEBUG_EXT_FS_WATCHER" |
505 | + DEBUG_REMOVE -> enable message about every remove use: qmake "DEINES+=DEBUG_REMOVE" |
506 | + DO_NOT_USE_TAG_LIB -> disable using TAGLIB and getting metada use: qmake "DEINES+=DO_NOT_USE_TAG_LIB" |
507 | + |
508 | +make |
509 | +sudo make install |
510 | + |
511 | |
512 | === added file 'src/plugin/folderlistmodel/clipboard.cpp' |
513 | --- src/plugin/folderlistmodel/clipboard.cpp 1970-01-01 00:00:00 +0000 |
514 | +++ src/plugin/folderlistmodel/clipboard.cpp 2014-04-15 08:19:22 +0000 |
515 | @@ -0,0 +1,495 @@ |
516 | +/************************************************************************** |
517 | + * |
518 | + * Copyright 2014 Canonical Ltd. |
519 | + * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com> |
520 | + * |
521 | + * You may use this file under the terms of the BSD license as follows: |
522 | + * |
523 | + * "Redistribution and use in source and binary forms, with or without |
524 | + * modification, are permitted provided that the following conditions are |
525 | + * met: |
526 | + * * Redistributions of source code must retain the above copyright |
527 | + * notice, this list of conditions and the following disclaimer. |
528 | + * * Redistributions in binary form must reproduce the above copyright |
529 | + * notice, this list of conditions and the following disclaimer in |
530 | + * the documentation and/or other materials provided with the |
531 | + * distribution. |
532 | + * * Neither the name of Nemo Mobile nor the names of its contributors |
533 | + * may be used to endorse or promote products derived from this |
534 | + * software without specific prior written permission. |
535 | + * |
536 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
537 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
538 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
539 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
540 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
541 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
542 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
543 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
544 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
545 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
546 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
547 | + * |
548 | + * File: clipboard.cpp |
549 | + * Date: 1/22/2014 |
550 | + */ |
551 | + |
552 | +#include "clipboard.h" |
553 | + |
554 | +#include <QClipboard> |
555 | +#include <QApplication> |
556 | +#include <QDir> |
557 | +#include <QFileInfo> |
558 | +#include <QDebug> |
559 | + |
560 | +static QLatin1String GNOME_COPIED_MIME_TYPE ("x-special/gnome-copied-files"); |
561 | +static QLatin1String KDE_CUT_MIME_TYPE ("application/x-kde-cutselection"); |
562 | + |
563 | + |
564 | +int DirModelMimeData::m_instances = 0; |
565 | +DirModelMimeData* DirModelMimeData::m_globalMimeData = 0; |
566 | + |
567 | + |
568 | +bool DirModelMimeData::hasFormat ( const QString & mimeType ) const |
569 | +{ |
570 | + bool ret = false; |
571 | + if ( mimeType == KDE_CUT_MIME_TYPE ) |
572 | + { |
573 | + ret = true; |
574 | + } |
575 | + else |
576 | + { |
577 | + ret = m_formats.contains(mimeType); |
578 | + } |
579 | + return ret; |
580 | +} |
581 | + |
582 | +//=============================================================================================== |
583 | +/*! |
584 | + * \brief DirModelMimeData::DirModelMimeData |
585 | + */ |
586 | +DirModelMimeData::DirModelMimeData() : |
587 | + QMimeData() |
588 | + , m_appMime(0) |
589 | +{ |
590 | + m_formats.append("text/uri-list"); |
591 | + m_formats.append(GNOME_COPIED_MIME_TYPE); |
592 | + m_formats.append("text/plain"); |
593 | + m_formats.append("COMPOUND_TEXT"); |
594 | + m_formats.append("TARGETS"); |
595 | + m_formats.append("MULTIPLE"); |
596 | + m_formats.append("TIMESTAMP"); |
597 | + m_formats.append("SAVE_TARGETS"); |
598 | + |
599 | + ++m_instances; |
600 | +#if DEBUG_MESSAGES |
601 | + qDebug() << Q_FUNC_INFO << this << "instances" << m_instances; |
602 | +#endif |
603 | +} |
604 | + |
605 | + |
606 | + |
607 | + |
608 | +DirModelMimeData::~DirModelMimeData() |
609 | +{ |
610 | + --m_instances; |
611 | +#if DEBUG_MESSAGES |
612 | + qDebug() << Q_FUNC_INFO << this << "instances" << m_instances |
613 | + << "m_globalMimeData" << m_globalMimeData; |
614 | +#endif |
615 | + if (m_instances == 1 && m_globalMimeData) |
616 | + { |
617 | + DirModelMimeData * tmp = m_globalMimeData; |
618 | + m_globalMimeData = 0; |
619 | + delete tmp; |
620 | + } |
621 | +} |
622 | + |
623 | +//=============================================================================================== |
624 | +/*! |
625 | + * \brief DirModelMimeData::gnomeUrls |
626 | + * \param mime |
627 | + * \param operation |
628 | + * \return |
629 | + */ |
630 | +QList<QUrl> |
631 | +DirModelMimeData::gnomeUrls(const QMimeData * mime, |
632 | + ClipboardOperation& operation) |
633 | +{ |
634 | + QList<QUrl> urls; |
635 | + if (mime->hasFormat(GNOME_COPIED_MIME_TYPE)) |
636 | + { |
637 | + QByteArray bytes = mime->data(GNOME_COPIED_MIME_TYPE); |
638 | + QList<QString> d = QString(bytes).split(QLatin1String("\n"), |
639 | + QString::SkipEmptyParts); |
640 | + operation = ClipboardCopy; |
641 | + if (d.count() > 0) |
642 | + { |
643 | + if (d.at(0).trimmed().startsWith(QLatin1String("cut"))) |
644 | + { |
645 | + operation = ClipboardCut; |
646 | + } |
647 | + for (int counter= 1; counter < d.count(); counter++) |
648 | + { |
649 | + urls.append(d.at(counter).trimmed()); |
650 | + } |
651 | + } |
652 | + } |
653 | + return urls; |
654 | +} |
655 | + |
656 | +//=============================================================================================== |
657 | +/*! |
658 | + * \brief DirModelMimeData::clipBoardOperation() |
659 | + * \param mime |
660 | + * \return |
661 | + */ |
662 | +ClipboardOperation DirModelMimeData::clipBoardOperation() |
663 | +{ |
664 | + ClipboardOperation op = ClipboardCopy; |
665 | + m_appMime = clipboardMimeData(); |
666 | + if (m_appMime) |
667 | + { |
668 | + //first check for GNOME clipboard format, op comes with Copy/Cut |
669 | + if (gnomeUrls(m_appMime, op).count() == 0) |
670 | + { // there is no gnome format, tries KDE format |
671 | + QStringList formats = m_appMime->formats(); |
672 | + int f = formats.count(); |
673 | + while(f--) |
674 | + { |
675 | + const QString &mi = formats.at(f); |
676 | + if(mi.startsWith(QLatin1String("application/x-kde")) ) |
677 | + { |
678 | + if (mi.contains(QLatin1String("cut"))) |
679 | + { |
680 | + op = ClipboardCut; |
681 | + break; |
682 | + } |
683 | + } |
684 | + } |
685 | + } |
686 | + } |
687 | + return op; |
688 | +} |
689 | + |
690 | + |
691 | +//=============================================================================================== |
692 | +/*! |
693 | + * \brief DirModelMimeData::setIntoClipboard |
694 | + * |
695 | + * Try to put data in the global cliboard |
696 | + * |
697 | + * \note: |
698 | + * On mobile devices clipboard might not work, in this case a local Clipboard is simulated |
699 | + * |
700 | + * \param files |
701 | + * \param path |
702 | + * \param isCut |
703 | + * \return who is owner of clipboard data |
704 | + */ |
705 | +DirModelMimeData::ClipBoardDataOwner |
706 | +DirModelMimeData::setIntoClipboard(const QStringList &files, const QString& path, ClipboardOperation operation) |
707 | +{ |
708 | + static bool firstTime = true; |
709 | + DirModelMimeData::ClipBoardDataOwner ret = Nobody; |
710 | + QClipboard *clipboard = QApplication::clipboard(); |
711 | + if (clipboard) |
712 | + { |
713 | + ret = Application; |
714 | + DirModelMimeData *mime = m_globalMimeData ? m_globalMimeData |
715 | + : new DirModelMimeData(); |
716 | + if (mime->fillClipboard(files, path, operation)) |
717 | + { |
718 | + clipboard->setMimeData(mime); |
719 | + //it looks like some mobile devices does not have X or Clipboard does work for other reason |
720 | + //in this case we simulate our own clipboard, the QClipboard::dataChanged() signal is also |
721 | + //checked in \ref Clipboard::storeOnClipboard() |
722 | + if (firstTime) |
723 | + { |
724 | + firstTime = false; |
725 | + if (!m_globalMimeData && !testClipboardContent(files, path)) |
726 | + { |
727 | + qWarning() << "QClipboard does not work, using own QMimeData storage"; |
728 | + m_globalMimeData = mime; |
729 | + } |
730 | + } |
731 | +#if DEBUG_MESSAGES |
732 | + qDebug() << Q_FUNC_INFO << "mime" << mime |
733 | + << "own Clipboard Mime Data" << m_globalMimeData; |
734 | +#endif |
735 | + } |
736 | + else |
737 | + if (m_globalMimeData != mime) |
738 | + { |
739 | + delete mime; |
740 | + } |
741 | + //check if it is necessary to send notification about Clipboard changed |
742 | + if (m_globalMimeData) |
743 | + { |
744 | + ret = MySelf; |
745 | + } |
746 | + } |
747 | + return ret; |
748 | +} |
749 | + |
750 | + |
751 | + |
752 | +bool DirModelMimeData::fillClipboard(const QStringList& files, const QString &path, ClipboardOperation operation) |
753 | +{ |
754 | + bool ret = false; |
755 | + int index = m_formats.indexOf(KDE_CUT_MIME_TYPE); |
756 | + if (index != -1 && operation != ClipboardCut) |
757 | + { |
758 | + m_formats.removeAt(index); |
759 | + } |
760 | + else |
761 | + if (operation == ClipboardCut) |
762 | + { |
763 | + m_formats.append(KDE_CUT_MIME_TYPE); |
764 | + } |
765 | + m_urls.clear(); |
766 | + m_gnomeData.clear(); |
767 | + m_gnomeData += operation == ClipboardCut ? |
768 | + QLatin1String("cut") : |
769 | + QLatin1String("copy"); |
770 | + QStringList fullPaths = makeFullPath(files, path); |
771 | + for(int counter = 0; counter < fullPaths.count(); counter++) |
772 | + { |
773 | + QUrl item = QUrl::fromLocalFile(fullPaths.at((counter))); |
774 | + m_urls.append(item); |
775 | + m_gnomeData += QLatin1Char('\n') + item.toEncoded() ; |
776 | + } |
777 | + if (m_urls.count() > 0) |
778 | + { |
779 | + setData(GNOME_COPIED_MIME_TYPE, m_gnomeData); |
780 | + setUrls(m_urls); |
781 | + ret = true; |
782 | + } |
783 | + else |
784 | + { |
785 | + // emit error( QObject::tr("Item does not exist"), item); |
786 | + } |
787 | + return ret; |
788 | +} |
789 | + |
790 | +//=============================================================================================== |
791 | +/*! |
792 | + * \brief DirModelMimeData::clipboardMimeData |
793 | + * \return |
794 | + */ |
795 | +const QMimeData *DirModelMimeData::clipboardMimeData() |
796 | +{ |
797 | + const QMimeData *ret = 0; |
798 | + QClipboard *clipboard = QApplication::clipboard(); |
799 | + if (m_globalMimeData) |
800 | + { |
801 | + ret = m_globalMimeData; |
802 | + } |
803 | + else |
804 | + if (clipboard) |
805 | + { |
806 | + ret = clipboard->mimeData(); |
807 | + } |
808 | +#if DEBUG_MESSAGES |
809 | + qDebug() << Q_FUNC_INFO << "clipboard" << clipboard |
810 | + << "m_ownClipboardMimeData" << m_globalMimeData |
811 | + << "clipboard->mimeData()" << ret; |
812 | +#endif |
813 | + return ret; |
814 | +} |
815 | + |
816 | +//=============================================================================================== |
817 | +/*! |
818 | + * \brief DirModelMimeData::localUrls |
819 | + * \return |
820 | + */ |
821 | +QStringList |
822 | +DirModelMimeData::localUrls(ClipboardOperation& operation) |
823 | +{ |
824 | + m_appMime = clipboardMimeData(); |
825 | + QStringList paths; |
826 | + //it may have external urls |
827 | + if (m_appMime) |
828 | + { |
829 | + QList<QUrl> urls; |
830 | + if (m_appMime->hasUrls()) |
831 | + { |
832 | + urls = m_appMime->urls(); |
833 | + operation = clipBoardOperation(); |
834 | + } |
835 | + else |
836 | + { |
837 | + urls = gnomeUrls(m_appMime, operation); |
838 | + } |
839 | + for (int counter=0; counter < urls.count(); counter++) |
840 | + { |
841 | + if (urls.at(counter).toString().startsWith(QLatin1String("file://"))) |
842 | + { |
843 | + paths.append(urls.at(counter).toLocalFile()); |
844 | + } |
845 | + } |
846 | + } |
847 | +#if DEBUG_MESSAGES |
848 | + qDebug() << Q_FUNC_INFO << paths; |
849 | +#endif |
850 | + return paths; |
851 | +} |
852 | + |
853 | + |
854 | +//=============================================================================================== |
855 | +/*! |
856 | + * \brief DirModelMimeData::testClipboardContent() Gets the clipboard content and compare with data previously stored |
857 | + * \param files |
858 | + * \param path |
859 | + * \return true if clipboard has content and it matches data previously stored |
860 | + */ |
861 | +bool DirModelMimeData::testClipboardContent(const QStringList &files, const QString &path) |
862 | +{ |
863 | + bool ret = false; |
864 | + ClipboardOperation tmpOperation; |
865 | + QStringList expectedList = makeFullPath(files,path); |
866 | + QStringList realList = localUrls(tmpOperation); |
867 | + if (realList == expectedList) |
868 | + { |
869 | + ret = true; |
870 | + } |
871 | + else |
872 | + { |
873 | + qWarning() << Q_FUNC_INFO << "FAILED, Clipboard does not work"; |
874 | + } |
875 | + return ret; |
876 | +} |
877 | + |
878 | +//=============================================================================================== |
879 | +/*! |
880 | + * \brief DirModelMimeData::makeFullPath() Just creates a fulpath file list when they do exist |
881 | + * \param files |
882 | + * \param path |
883 | + * \return the list itself |
884 | + */ |
885 | +QStringList DirModelMimeData::makeFullPath(const QStringList& files, const QString &path) |
886 | +{ |
887 | + QStringList fullPathnameList; |
888 | + QFileInfo fi; |
889 | + for(int counter = 0; counter < files.count(); counter++) |
890 | + { |
891 | + const QString& item = files.at(counter); |
892 | + fi.setFile(item); |
893 | + if (!fi.isAbsolute()) |
894 | + { |
895 | + fi.setFile(path + QDir::separator() + item); |
896 | + } |
897 | + if (fi.exists()) |
898 | + { |
899 | + fullPathnameList.append(fi.absoluteFilePath()); |
900 | + } |
901 | + } |
902 | + return fullPathnameList; |
903 | +} |
904 | + |
905 | + |
906 | +//=========================================================================== |
907 | +// |
908 | +//=========================================================================== |
909 | +Clipboard::Clipboard(QObject *parent): |
910 | + QObject(parent) |
911 | + , m_mimeData ( new DirModelMimeData() ) |
912 | + , m_clipboardModifiedByOther(false) |
913 | +{ |
914 | + QClipboard *clipboard = QApplication::clipboard(); |
915 | + |
916 | + connect(clipboard, SIGNAL(dataChanged()), this, SIGNAL(clipboardChanged())); |
917 | + connect(clipboard, SIGNAL(dataChanged()), this, SLOT(onClipboardChanged())); |
918 | +} |
919 | + |
920 | + |
921 | +Clipboard::~Clipboard() |
922 | +{ |
923 | + delete m_mimeData; |
924 | +} |
925 | + |
926 | +//================================================================================ |
927 | +/*! |
928 | + * \brief Clipboard::clipboardHasChanged() used to identify if the clipboard changed during a Cut operation |
929 | + * |
930 | + * \sa \ref endCurrentAction() |
931 | + */ |
932 | +void Clipboard::onClipboardChanged() |
933 | +{ |
934 | + m_clipboardModifiedByOther = true; |
935 | +} |
936 | + |
937 | + |
938 | +//================================================================== |
939 | +/*! |
940 | + * \brief Clipboard::storeOnClipboard() store data on Clipboard |
941 | + * \param pathnames files list |
942 | + * \param op \ref ClipboardOperation as \ref ClipboardCopy or \ref ClipboardCut |
943 | + * |
944 | + * Stores data on clipboard by calling \ref DirModelMimeData::setIntoClipboard() which uses Qt class QClipboard |
945 | + * It is expected that QClipboard class emits the dataChanged() signal when a new content is set into it, |
946 | + * if it does we caught that signal in \ref clipboardHasChanged() which sets \ref m_clipboardModifiedByOther to true. |
947 | + */ |
948 | +void Clipboard::storeOnClipboard(const QStringList &names, ClipboardOperation op, const QString& curPath) |
949 | +{ |
950 | +#if DEBUG_MESSAGES |
951 | + qDebug() << Q_FUNC_INFO << names << "ClipboardOperation" << op; |
952 | +#endif |
953 | + DirModelMimeData::ClipBoardDataOwner owner = |
954 | + m_mimeData->setIntoClipboard(names, curPath, op); |
955 | + if (owner == DirModelMimeData::MySelf || !m_clipboardModifiedByOther) |
956 | + { |
957 | + emit clipboardChanged(); |
958 | + } |
959 | + m_clipboardModifiedByOther = false; |
960 | +} |
961 | + |
962 | +//=============================================================================================== |
963 | +/*! |
964 | + * \brief Clipboard::copy |
965 | + * \param pathnames |
966 | + */ |
967 | +void Clipboard::copy(const QStringList &names, const QString& path) |
968 | +{ |
969 | + storeOnClipboard(names, ClipboardCopy, path); |
970 | +} |
971 | + |
972 | +//=============================================================================================== |
973 | +/*! |
974 | + * \brief Clipboard::cut |
975 | + * \param pathnames |
976 | + */ |
977 | +void Clipboard::cut(const QStringList &names, const QString &path) |
978 | +{ |
979 | + storeOnClipboard(names, ClipboardCut, path); |
980 | +} |
981 | + |
982 | + |
983 | +//======================================================= |
984 | +/*! |
985 | + * \brief Clipboard::clipboardLocalUrlsCounter |
986 | + * \return |
987 | + */ |
988 | +int Clipboard::clipboardLocalUrlsCounter() |
989 | +{ |
990 | + ClipboardOperation operation; |
991 | + return m_mimeData->localUrls(operation).count(); |
992 | +} |
993 | + |
994 | + |
995 | +//======================================================= |
996 | +/*! |
997 | + * \brief Clipboard::paste |
998 | + * \param operation |
999 | + * \return |
1000 | + */ |
1001 | +QStringList Clipboard::paste(ClipboardOperation &operation) |
1002 | +{ |
1003 | + QStringList items = m_mimeData->localUrls(operation); |
1004 | + if (operation == ClipboardCut) |
1005 | + { |
1006 | + //this must still be false when cut finishes to change the clipboard to the target |
1007 | + m_clipboardModifiedByOther = false; |
1008 | + } |
1009 | + return items; |
1010 | +} |
1011 | |
1012 | === added file 'src/plugin/folderlistmodel/clipboard.h' |
1013 | --- src/plugin/folderlistmodel/clipboard.h 1970-01-01 00:00:00 +0000 |
1014 | +++ src/plugin/folderlistmodel/clipboard.h 2014-04-15 08:19:22 +0000 |
1015 | @@ -0,0 +1,132 @@ |
1016 | +/************************************************************************** |
1017 | + * |
1018 | + * Copyright 2014 Canonical Ltd. |
1019 | + * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com> |
1020 | + * |
1021 | + * You may use this file under the terms of the BSD license as follows: |
1022 | + * |
1023 | + * "Redistribution and use in source and binary forms, with or without |
1024 | + * modification, are permitted provided that the following conditions are |
1025 | + * met: |
1026 | + * * Redistributions of source code must retain the above copyright |
1027 | + * notice, this list of conditions and the following disclaimer. |
1028 | + * * Redistributions in binary form must reproduce the above copyright |
1029 | + * notice, this list of conditions and the following disclaimer in |
1030 | + * the documentation and/or other materials provided with the |
1031 | + * distribution. |
1032 | + * * Neither the name of Nemo Mobile nor the names of its contributors |
1033 | + * may be used to endorse or promote products derived from this |
1034 | + * software without specific prior written permission. |
1035 | + * |
1036 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
1037 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
1038 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
1039 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
1040 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
1041 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
1042 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
1043 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
1044 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
1045 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
1046 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
1047 | + * |
1048 | + * File: clipboard.h |
1049 | + * Date: 1/22/2014 |
1050 | + */ |
1051 | + |
1052 | +#ifndef CLIPBOARD_H |
1053 | +#define CLIPBOARD_H |
1054 | + |
1055 | +#include <QMimeData> |
1056 | +#include <QUrl> |
1057 | +#include <QStringList> |
1058 | + |
1059 | +class DirModelMimeData; |
1060 | + |
1061 | +enum ClipboardOperation |
1062 | +{ |
1063 | + NoClipboard, ClipboardCopy, ClipboardCut |
1064 | +}; |
1065 | + |
1066 | + |
1067 | + |
1068 | +/*! |
1069 | + * \brief The Clipboard class handles global clipboard storage |
1070 | + */ |
1071 | +class Clipboard : public QObject |
1072 | +{ |
1073 | + Q_OBJECT |
1074 | +public: |
1075 | + explicit Clipboard(QObject *parent = 0); |
1076 | + ~Clipboard(); |
1077 | + QStringList paste(ClipboardOperation& operation); |
1078 | + int clipboardLocalUrlsCounter(); |
1079 | + inline bool hasClipboardModifiedByOtherApplication() const {return m_clipboardModifiedByOther;} |
1080 | + |
1081 | +public slots: |
1082 | + void cut(const QStringList& names, const QString &path); |
1083 | + void copy(const QStringList& names, const QString &path); |
1084 | + |
1085 | + |
1086 | +signals: |
1087 | + void clipboardChanged(); |
1088 | + |
1089 | +private slots: |
1090 | + void onClipboardChanged (); |
1091 | + |
1092 | +private: |
1093 | + void storeOnClipboard(const QStringList &names, |
1094 | + ClipboardOperation op, |
1095 | + const QString &curPath); |
1096 | +private: |
1097 | + DirModelMimeData * m_mimeData; |
1098 | + bool m_clipboardModifiedByOther; |
1099 | +}; |
1100 | + |
1101 | + |
1102 | + |
1103 | +/*! |
1104 | + * \brief The DirModelMimeData class is the storage on Clipboard |
1105 | + */ |
1106 | +class DirModelMimeData : public QMimeData |
1107 | +{ |
1108 | +public: |
1109 | + explicit DirModelMimeData(); |
1110 | + ~DirModelMimeData(); |
1111 | + virtual QStringList formats() const { return m_formats; } |
1112 | + virtual bool hasFormat ( const QString & mimeType ) const; |
1113 | + |
1114 | +public: |
1115 | + enum ClipBoardDataOwner |
1116 | + { |
1117 | + Nobody, // might have failed |
1118 | + Application, |
1119 | + MySelf |
1120 | + }; |
1121 | + |
1122 | + ClipBoardDataOwner setIntoClipboard(const QStringList& files, |
1123 | + const QString &path, |
1124 | + ClipboardOperation operation); |
1125 | + const QMimeData * clipboardMimeData(); |
1126 | + QStringList localUrls(ClipboardOperation& operation); |
1127 | + |
1128 | +private: |
1129 | + static QList<QUrl> gnomeUrls(const QMimeData *mime, ClipboardOperation& operation); |
1130 | + ClipboardOperation clipBoardOperation(); |
1131 | + bool fillClipboard(const QStringList& files, const QString &path, ClipboardOperation operation); |
1132 | + QStringList makeFullPath(const QStringList& files, const QString &path); |
1133 | + bool testClipboardContent(const QStringList& files, const QString &path); |
1134 | + |
1135 | +private: |
1136 | + QStringList m_formats; |
1137 | + const QMimeData * m_appMime; |
1138 | + QByteArray m_gnomeData; |
1139 | + QList<QUrl> m_urls; |
1140 | + static DirModelMimeData* m_globalMimeData; //!< some mobile devices do not use X, they may not have clipboard |
1141 | + static int m_instances; |
1142 | +}; |
1143 | + |
1144 | + |
1145 | + |
1146 | +#endif //CLIPBOARD_H |
1147 | + |
1148 | |
1149 | === added file 'src/plugin/folderlistmodel/diritemabstractlistmodel.h' |
1150 | --- src/plugin/folderlistmodel/diritemabstractlistmodel.h 1970-01-01 00:00:00 +0000 |
1151 | +++ src/plugin/folderlistmodel/diritemabstractlistmodel.h 2014-04-15 08:19:22 +0000 |
1152 | @@ -0,0 +1,46 @@ |
1153 | +/************************************************************************** |
1154 | + * |
1155 | + * Copyright 2014 Canonical Ltd. |
1156 | + * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com> |
1157 | + * |
1158 | + * This program is free software; you can redistribute it and/or modify |
1159 | + * it under the terms of the GNU Lesser General Public License as published by |
1160 | + * the Free Software Foundation; version 3. |
1161 | + * |
1162 | + * This program is distributed in the hope that it will be useful, |
1163 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1164 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1165 | + * GNU Lesser General Public License for more details. |
1166 | + * |
1167 | + * You should have received a copy of the GNU Lesser General Public License |
1168 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1169 | + * |
1170 | + * File: diritemabstractlistmodel.h |
1171 | + * Date: 30/01/2014 |
1172 | + */ |
1173 | + |
1174 | +#ifndef DIRITEMABSTRACTLISTMODEL_H |
1175 | +#define DIRITEMABSTRACTLISTMODEL_H |
1176 | + |
1177 | +#include <QObject> |
1178 | + |
1179 | +#include <QAbstractListModel> |
1180 | + |
1181 | + |
1182 | +class DirItemInfo; |
1183 | +class DirItemModel; |
1184 | + |
1185 | +class DirItemAbstractListModel : public QAbstractListModel |
1186 | +{ |
1187 | + Q_OBJECT |
1188 | +public: |
1189 | + virtual int getIndex(const QString& name) = 0; |
1190 | + virtual void notifyItemChanged(int index) = 0; |
1191 | +protected: |
1192 | + explicit DirItemAbstractListModel(QObject *parent = 0) : |
1193 | + QAbstractListModel(parent) |
1194 | + { |
1195 | + } |
1196 | +}; |
1197 | + |
1198 | +#endif // DIRITEMABSTRACTLISTMODEL_H |
1199 | |
1200 | === added file 'src/plugin/folderlistmodel/diriteminfo.cpp' |
1201 | --- src/plugin/folderlistmodel/diriteminfo.cpp 1970-01-01 00:00:00 +0000 |
1202 | +++ src/plugin/folderlistmodel/diriteminfo.cpp 2014-04-15 08:19:22 +0000 |
1203 | @@ -0,0 +1,345 @@ |
1204 | +/************************************************************************** |
1205 | + * |
1206 | + * Copyright 2014 Canonical Ltd()-> |
1207 | + * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com> |
1208 | + * |
1209 | + * This program is free software; you can redistribute it and/or modify |
1210 | + * it under the terms of the GNU Lesser General Public License as published by |
1211 | + * the Free Software Foundation; version 3. |
1212 | + * |
1213 | + * This program is distributed in the hope that it will be useful, |
1214 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1215 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1216 | + * GNU Lesser General Public License for more details. |
1217 | + * |
1218 | + * You should have received a copy of the GNU Lesser General Public License |
1219 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1220 | + * |
1221 | + * File: diriteminfo.cpp |
1222 | + * Date: 30/01/2014 |
1223 | + */ |
1224 | + |
1225 | +#include "diriteminfo.h" |
1226 | + |
1227 | + |
1228 | + |
1229 | + |
1230 | +#include <QUrl> |
1231 | +#include <QDir> |
1232 | + |
1233 | + |
1234 | +class DirItemInfoPrivate : public QSharedData |
1235 | +{ |
1236 | +public: |
1237 | + DirItemInfoPrivate(); |
1238 | + DirItemInfoPrivate(const DirItemInfoPrivate& other); |
1239 | + DirItemInfoPrivate(const QFileInfo& fi); |
1240 | + void setFileInfo(const QFileInfo&); |
1241 | + |
1242 | +public: |
1243 | + bool _isValid :1; |
1244 | + bool _isLocal :1; |
1245 | + bool _isRemote :1; |
1246 | + bool _isSelected :1; |
1247 | + bool _isAbsolute :1; |
1248 | + bool _exists :1; |
1249 | + bool _isFile :1; |
1250 | + bool _isDir :1; |
1251 | + bool _isSymLink :1; |
1252 | + bool _isRoot :1; |
1253 | + bool _isReadable :1; |
1254 | + bool _isWritable :1; |
1255 | + bool _isExecutable:1; |
1256 | + QFile::Permissions _permissions; |
1257 | + qint64 _size; |
1258 | + QDateTime _created; |
1259 | + QDateTime _lastModified; |
1260 | + QDateTime _lastRead; |
1261 | + QString _path; |
1262 | + QString _fileName; |
1263 | + static QMimeDatabase mimeDatabase; |
1264 | +}; |
1265 | + |
1266 | + |
1267 | +QMimeDatabase DirItemInfoPrivate::mimeDatabase; |
1268 | + |
1269 | + |
1270 | +DirItemInfoPrivate::DirItemInfoPrivate() : |
1271 | + _isValid(false) |
1272 | + ,_isLocal(false) |
1273 | + ,_isRemote(false) |
1274 | + ,_isSelected(false) |
1275 | + ,_isAbsolute(false) |
1276 | + ,_exists(false) |
1277 | + ,_isDir(false) |
1278 | + ,_isSymLink(false) |
1279 | + ,_isRoot(false) |
1280 | + ,_isReadable(false) |
1281 | + ,_isWritable(false) |
1282 | + ,_isExecutable(false) |
1283 | + ,_permissions(0) |
1284 | + ,_size(0) |
1285 | +{ |
1286 | + |
1287 | +} |
1288 | + |
1289 | + |
1290 | +DirItemInfoPrivate::DirItemInfoPrivate(const DirItemInfoPrivate &other): |
1291 | + QSharedData(other) |
1292 | + ,_isValid(other._isValid) |
1293 | + ,_isLocal(other._isLocal) |
1294 | + ,_isRemote(other._isRemote) |
1295 | + ,_isSelected(other._isSelected) |
1296 | + ,_isAbsolute(other._isAbsolute) |
1297 | + ,_exists(other._exists) |
1298 | + ,_isDir(other._isDir) |
1299 | + ,_isSymLink(other._isSymLink) |
1300 | + ,_isRoot(other._isRoot) |
1301 | + ,_isReadable(other._isReadable) |
1302 | + ,_isWritable(other._isWritable) |
1303 | + ,_isExecutable(other._isExecutable) |
1304 | + ,_permissions(other._permissions) |
1305 | + ,_size(other._size) |
1306 | + ,_created(other._created) |
1307 | + ,_lastModified(other._lastModified) |
1308 | + ,_lastRead(other._lastRead) |
1309 | + ,_path(other._path) |
1310 | + ,_fileName(other._fileName) |
1311 | +{ |
1312 | + |
1313 | +} |
1314 | + |
1315 | + |
1316 | +DirItemInfoPrivate::DirItemInfoPrivate(const QFileInfo &fi): |
1317 | + _isValid(true) |
1318 | + ,_isLocal(true) |
1319 | + ,_isRemote(false) |
1320 | + ,_isSelected(false) |
1321 | +{ |
1322 | + setFileInfo(fi); |
1323 | +} |
1324 | + |
1325 | +void DirItemInfoPrivate::setFileInfo(const QFileInfo &fi) |
1326 | +{ |
1327 | + if (fi.exists() && fi.isRelative()) |
1328 | + { |
1329 | + QFileInfo abs(fi.absoluteFilePath()); |
1330 | + setFileInfo(abs); |
1331 | + } |
1332 | + else |
1333 | + { |
1334 | + _path = fi.absolutePath(); |
1335 | + _fileName = fi.fileName(); |
1336 | + _isAbsolute = fi.isAbsolute(); |
1337 | + _exists = fi.exists(); |
1338 | + _isDir = fi.isDir(); |
1339 | + _isFile = fi.isFile(); |
1340 | + _isSymLink = fi.isSymLink(); |
1341 | + _isRoot = fi.isRoot(); |
1342 | + _isReadable = fi.isReadable(); |
1343 | + _isWritable = fi.isWritable(); |
1344 | + _isExecutable = fi.isExecutable(); |
1345 | + _permissions = fi.permissions(); |
1346 | + _size = fi.size(); |
1347 | + _created = fi.created(); |
1348 | + _lastRead = fi.lastRead(); |
1349 | + _lastModified = fi.lastModified(); |
1350 | + } |
1351 | +} |
1352 | + |
1353 | +//================================================================ |
1354 | + |
1355 | +DirItemInfo::DirItemInfo(): d_ptr(new DirItemInfoPrivate()) |
1356 | +{ |
1357 | +} |
1358 | + |
1359 | + |
1360 | +DirItemInfo::~DirItemInfo() |
1361 | +{ |
1362 | +} |
1363 | + |
1364 | + |
1365 | + |
1366 | +DirItemInfo::DirItemInfo(const QFileInfo &fi): |
1367 | + d_ptr(new DirItemInfoPrivate(fi)) |
1368 | +{ |
1369 | + |
1370 | +} |
1371 | + |
1372 | + |
1373 | + |
1374 | +DirItemInfo::DirItemInfo(const QString& urlOrPath): |
1375 | + d_ptr( new DirItemInfoPrivate(QFileInfo(urlOrPath)) ) |
1376 | +{ |
1377 | + |
1378 | +} |
1379 | + |
1380 | + |
1381 | +DirItemInfo::DirItemInfo(const DirItemInfo& other) |
1382 | +{ |
1383 | + d_ptr = other.d_ptr; |
1384 | +} |
1385 | + |
1386 | + |
1387 | +bool DirItemInfo::isSelected() const |
1388 | +{ |
1389 | + return d_ptr->_isSelected; |
1390 | +} |
1391 | + |
1392 | +/*! |
1393 | + * \brief DirItemInfo::setSelection() |
1394 | + * \param selected true/false new selection state |
1395 | + * \return true if a new state was set, false if the selection is already equal to \a selected |
1396 | + */ |
1397 | +bool DirItemInfo::setSelection(bool selected) |
1398 | +{ |
1399 | + bool ret = selected != isSelected(); |
1400 | + d_ptr->_isSelected = selected; |
1401 | + return ret; |
1402 | +} |
1403 | + |
1404 | + |
1405 | +bool DirItemInfo::isValid() const |
1406 | +{ |
1407 | + return d_ptr->_isValid; |
1408 | +} |
1409 | + |
1410 | +bool DirItemInfo::isLocal() const |
1411 | +{ |
1412 | + return d_ptr->_isLocal; |
1413 | +} |
1414 | + |
1415 | +bool DirItemInfo::isRemote() const |
1416 | +{ |
1417 | + return d_ptr->_isRemote; |
1418 | +} |
1419 | + |
1420 | +bool DirItemInfo::exists() const |
1421 | +{ |
1422 | + return d_ptr->_exists; |
1423 | +} |
1424 | + |
1425 | +QString DirItemInfo::filePath() const |
1426 | +{ |
1427 | + QString filepath; |
1428 | + if (!d_ptr->_path.isEmpty()) |
1429 | + { |
1430 | + filepath = d_ptr->_path; |
1431 | + if (d_ptr->_path != QDir::rootPath()) |
1432 | + { |
1433 | + filepath += QDir::separator(); |
1434 | + } |
1435 | + } |
1436 | + filepath += d_ptr->_fileName; |
1437 | + return filepath; |
1438 | +} |
1439 | + |
1440 | +QString DirItemInfo::fileName() const |
1441 | +{ |
1442 | + return d_ptr->_fileName; |
1443 | +} |
1444 | + |
1445 | +QString DirItemInfo::absoluteFilePath() const |
1446 | +{ |
1447 | + return filePath(); |
1448 | +} |
1449 | + |
1450 | +QString DirItemInfo::absolutePath() const |
1451 | +{ |
1452 | + return d_ptr->_path; |
1453 | +} |
1454 | + |
1455 | +bool DirItemInfo::isReadable() const |
1456 | +{ |
1457 | + return d_ptr->_isReadable; |
1458 | +} |
1459 | + |
1460 | +bool DirItemInfo::isWritable() const |
1461 | +{ |
1462 | + return d_ptr->_isWritable; |
1463 | +} |
1464 | + |
1465 | +bool DirItemInfo::isExecutable() const |
1466 | +{ |
1467 | + return d_ptr->_isExecutable; |
1468 | +} |
1469 | + |
1470 | +bool DirItemInfo::isRelative() const |
1471 | +{ |
1472 | + return ! isAbsolute(); |
1473 | +} |
1474 | + |
1475 | +bool DirItemInfo::isAbsolute() const |
1476 | +{ |
1477 | + return d_ptr->_isAbsolute; |
1478 | +} |
1479 | + |
1480 | +bool DirItemInfo::isFile() const |
1481 | +{ |
1482 | + return d_ptr->_isFile; |
1483 | +} |
1484 | + |
1485 | +bool DirItemInfo::isDir() const |
1486 | +{ |
1487 | + return d_ptr->_isDir; |
1488 | +} |
1489 | + |
1490 | +bool DirItemInfo::isSymLink() const |
1491 | +{ |
1492 | + return d_ptr->_isSymLink; |
1493 | +} |
1494 | + |
1495 | +bool DirItemInfo::isRoot() const |
1496 | +{ |
1497 | + return d_ptr->_isRoot; |
1498 | +} |
1499 | + |
1500 | +QFile::Permissions DirItemInfo::permissions() const |
1501 | +{ |
1502 | + return d_ptr->_permissions; |
1503 | +} |
1504 | + |
1505 | +qint64 DirItemInfo::size() const |
1506 | +{ |
1507 | + return d_ptr->_size; |
1508 | +} |
1509 | + |
1510 | +QDateTime DirItemInfo::created() const |
1511 | +{ |
1512 | + return d_ptr->_created; |
1513 | +} |
1514 | + |
1515 | +QDateTime DirItemInfo::lastModified() const |
1516 | +{ |
1517 | + return d_ptr->_lastModified; |
1518 | +} |
1519 | + |
1520 | +QDateTime DirItemInfo::lastRead() const |
1521 | +{ |
1522 | + return d_ptr->_lastRead; |
1523 | +} |
1524 | + |
1525 | +void DirItemInfo::setFile(const QString &dir, const QString &file) |
1526 | +{ |
1527 | + QFileInfo f; |
1528 | + f.setFile(dir,file); |
1529 | + d_ptr->setFileInfo(f); |
1530 | +} |
1531 | + |
1532 | +QFileInfo DirItemInfo::diskFileInfo() const |
1533 | +{ |
1534 | + QFileInfo fi(absoluteFilePath()); |
1535 | + return fi; |
1536 | +} |
1537 | + |
1538 | +QString DirItemInfo::path() const |
1539 | +{ |
1540 | + return d_ptr->_path; |
1541 | +} |
1542 | + |
1543 | + |
1544 | +QMimeType DirItemInfo::mimeType() const |
1545 | +{ |
1546 | + return d_ptr->mimeDatabase.mimeTypeForFile(diskFileInfo()); |
1547 | +} |
1548 | + |
1549 | |
1550 | === added file 'src/plugin/folderlistmodel/diriteminfo.h' |
1551 | --- src/plugin/folderlistmodel/diriteminfo.h 1970-01-01 00:00:00 +0000 |
1552 | +++ src/plugin/folderlistmodel/diriteminfo.h 2014-04-15 08:19:22 +0000 |
1553 | @@ -0,0 +1,123 @@ |
1554 | +/************************************************************************** |
1555 | + * |
1556 | + * Copyright 2014 Canonical Ltd. |
1557 | + * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com> |
1558 | + * |
1559 | + * This program is free software; you can redistribute it and/or modify |
1560 | + * it under the terms of the GNU Lesser General Public License as published by |
1561 | + * the Free Software Foundation; version 3. |
1562 | + * |
1563 | + * This program is distributed in the hope that it will be useful, |
1564 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1565 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1566 | + * GNU Lesser General Public License for more details. |
1567 | + * |
1568 | + * You should have received a copy of the GNU Lesser General Public License |
1569 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1570 | + * |
1571 | + * File: diriteminfo.h |
1572 | + * Date: 30/01/2014 |
1573 | + */ |
1574 | + |
1575 | +#ifndef DIRITEMINFO_H |
1576 | +#define DIRITEMINFO_H |
1577 | + |
1578 | +#include <QtGlobal> |
1579 | +#include <QVector> |
1580 | +#include <QFileInfo> |
1581 | +#include <QSharedData> |
1582 | +#include <QDateTime> |
1583 | + |
1584 | +#include <QMimeType> |
1585 | +#include <QMimeDatabase> |
1586 | + |
1587 | +class DirItemInfoPrivate; |
1588 | + |
1589 | + |
1590 | +/*! |
1591 | + * \brief The DirItemInfo class |
1592 | + * |
1593 | + * It intends to provide the same information as QFileInfo for Local Files: |
1594 | + * * selection state |
1595 | + * * any information about the item type, if it is Local/Remove |
1596 | + * * |
1597 | + */ |
1598 | +class DirItemInfo |
1599 | +{ |
1600 | +public: |
1601 | + DirItemInfo(); |
1602 | + DirItemInfo(const QString& urlOrPath); |
1603 | + DirItemInfo(const QFileInfo&); |
1604 | + DirItemInfo(const DirItemInfo& other); |
1605 | + |
1606 | + virtual ~DirItemInfo(); |
1607 | + |
1608 | +public: |
1609 | + bool isSelected() const; |
1610 | + bool setSelection(bool selected); |
1611 | + virtual bool isValid() const; |
1612 | + |
1613 | + /*! |
1614 | + * \brief isLocal() |
1615 | + * \return true if the file is the disk: valid for Trash and any mounted FS |
1616 | + */ |
1617 | + virtual bool isLocal() const; |
1618 | + |
1619 | + /*! |
1620 | + * \brief isRemote() |
1621 | + * \return true if the file is in any remote host, mounted File Sharing is considered as Local |
1622 | + */ |
1623 | + virtual bool isRemote() const; |
1624 | + |
1625 | + QFileInfo diskFileInfo() const; |
1626 | + |
1627 | + inline void swap(DirItemInfo &other) |
1628 | + { qSwap(d_ptr, other.d_ptr); } |
1629 | + |
1630 | + inline DirItemInfo& operator=(const DirItemInfo &other) |
1631 | + { swap(*(const_cast<DirItemInfo*>(&other))); return *this; } |
1632 | + |
1633 | + virtual bool exists() const; |
1634 | + virtual QString filePath() const; |
1635 | + virtual QString fileName() const; |
1636 | + virtual QString path() const; |
1637 | + virtual QString absolutePath() const; |
1638 | + virtual QString absoluteFilePath() const; |
1639 | + virtual bool isReadable() const; |
1640 | + virtual bool isWritable() const; |
1641 | + virtual bool isExecutable() const; |
1642 | + virtual bool isRelative() const; |
1643 | + virtual bool isAbsolute() const; |
1644 | + virtual bool isFile() const; |
1645 | + virtual bool isDir() const; |
1646 | + virtual bool isSymLink() const; |
1647 | + virtual bool isRoot() const; |
1648 | + virtual QFile::Permissions permissions() const; |
1649 | + virtual qint64 size() const; |
1650 | + virtual QDateTime created() const; |
1651 | + virtual QDateTime lastModified() const; |
1652 | + virtual QDateTime lastRead() const; |
1653 | + virtual QMimeType mimeType() const; |
1654 | + |
1655 | + virtual void setFile(const QString &dir, const QString & file); |
1656 | + |
1657 | +#if 0 |
1658 | + virtual QString path() const; |
1659 | + virtual QString owner() const; |
1660 | + virtual uint ownerId() const; |
1661 | + virtual QString group() const; |
1662 | + virtual uint groupId() const; |
1663 | + virtual bool permission(QFile::Permissions permissions) const; |
1664 | +#endif |
1665 | + |
1666 | + |
1667 | +protected: |
1668 | + QSharedDataPointer<DirItemInfoPrivate> d_ptr; |
1669 | +}; |
1670 | + |
1671 | +typedef QVector<DirItemInfo> DirItemInfoList; |
1672 | + |
1673 | +Q_DECLARE_SHARED(DirItemInfo) |
1674 | +Q_DECLARE_METATYPE(DirItemInfo) |
1675 | + |
1676 | +#endif // DIRITEMINFO_H |
1677 | |
1678 | === added file 'src/plugin/folderlistmodel/dirmodel.cpp' |
1679 | --- src/plugin/folderlistmodel/dirmodel.cpp 1970-01-01 00:00:00 +0000 |
1680 | +++ src/plugin/folderlistmodel/dirmodel.cpp 2014-04-15 08:19:22 +0000 |
1681 | @@ -0,0 +1,1563 @@ |
1682 | +/* |
1683 | + * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net> |
1684 | + * |
1685 | + * You may use this file under the terms of the BSD license as follows: |
1686 | + * |
1687 | + * "Redistribution and use in source and binary forms, with or without |
1688 | + * modification, are permitted provided that the following conditions are |
1689 | + * met: |
1690 | + * * Redistributions of source code must retain the above copyright |
1691 | + * notice, this list of conditions and the following disclaimer. |
1692 | + * * Redistributions in binary form must reproduce the above copyright |
1693 | + * notice, this list of conditions and the following disclaimer in |
1694 | + * the documentation and/or other materials provided with the |
1695 | + * distribution. |
1696 | + * * Neither the name of Nemo Mobile nor the names of its contributors |
1697 | + * may be used to endorse or promote products derived from this |
1698 | + * software without specific prior written permission. |
1699 | + * |
1700 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
1701 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
1702 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
1703 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
1704 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
1705 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
1706 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
1707 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
1708 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
1709 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
1710 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
1711 | + */ |
1712 | + |
1713 | +#include "dirselection.h" |
1714 | +#include "dirmodel.h" |
1715 | +#include "iorequest.h" |
1716 | +#include "ioworkerthread.h" |
1717 | +#include "filesystemaction.h" |
1718 | +#include "externalfswatcher.h" |
1719 | +#include "clipboard.h" |
1720 | +#include "fmutil.h" |
1721 | + |
1722 | + |
1723 | +#ifndef DO_NOT_USE_TAG_LIB |
1724 | +#include <taglib/attachedpictureframe.h> |
1725 | +#include <taglib/id3v2tag.h> |
1726 | +#include <taglib/fileref.h> |
1727 | +#include <taglib/mpegfile.h> |
1728 | +#include <taglib/tag.h> |
1729 | +#include <taglib/audioproperties.h> |
1730 | +#endif |
1731 | + |
1732 | +#include <errno.h> |
1733 | +#include <string.h> |
1734 | +#include <QDirIterator> |
1735 | +#include <QDir> |
1736 | +#include <QDebug> |
1737 | +#include <QFileIconProvider> |
1738 | +#include <QUrl> |
1739 | +#include <QDesktopServices> |
1740 | +#include <QMetaType> |
1741 | +#include <QDateTime> |
1742 | +#include <QMimeType> |
1743 | + |
1744 | +#if defined(REGRESSION_TEST_FOLDERLISTMODEL) |
1745 | +# include <QColor> |
1746 | +# include <QBrush> |
1747 | +#endif |
1748 | + |
1749 | + |
1750 | + |
1751 | + |
1752 | + |
1753 | +#define IS_VALID_ROW(row) (row >=0 && row < mDirectoryContents.count()) |
1754 | +#define WARN_ROW_OUT_OF_RANGE(row) qWarning() << Q_FUNC_INFO << this << "row:" << row << "Out of bounds access" |
1755 | + |
1756 | +#define IS_FILE_MANAGER_IDLE() (!mAwaitingResults) |
1757 | + |
1758 | + |
1759 | +Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread) |
1760 | + |
1761 | +namespace { |
1762 | + QHash<QByteArray, int> roleMapping; |
1763 | +} |
1764 | + |
1765 | + |
1766 | + |
1767 | +/*! |
1768 | + * Sort was originally done in \ref onItemsAdded() and that code is now in \ref addItem(), |
1769 | + * the reason to keep doing sort and do not let QDir does it is that when adding new items |
1770 | + * by \ref mkdir() or \paste() it is not necessary to call refresh() to load the entire directory |
1771 | + * to organize it items again. New items order/position are organized by \ref addItem() |
1772 | + * |
1773 | + */ |
1774 | +static CompareFunction availableCompareFunctions[2][2] = |
1775 | +{ |
1776 | + {fileCompareAscending, fileCompareDescending} |
1777 | + ,{dateCompareAscending, dateCompareDescending} |
1778 | +}; |
1779 | + |
1780 | + |
1781 | +DirModel::DirModel(QObject *parent) |
1782 | + : DirItemAbstractListModel(parent) |
1783 | + , mFilterDirectories(false) |
1784 | + , mShowDirectories(true) |
1785 | + , mAwaitingResults(false) |
1786 | + , mIsRecursive(false) |
1787 | + , mReadsMediaMetadata(false) |
1788 | + , mShowHiddenFiles(false) |
1789 | + , mSortBy(SortByName) |
1790 | + , mSortOrder(SortAscending) |
1791 | + , mCompareFunction(0) |
1792 | + , mExtFSWatcher(0) |
1793 | + , mClipboard(new Clipboard(this)) |
1794 | + , m_fsAction(new FileSystemAction(this) ) |
1795 | +{ |
1796 | + mNameFilters = QStringList() << "*"; |
1797 | + |
1798 | + mSelection = new DirSelection(this, &mDirectoryContents); |
1799 | + |
1800 | + connect(m_fsAction, SIGNAL(progress(int,int,int)), |
1801 | + this, SIGNAL(progress(int,int,int))); |
1802 | + |
1803 | + connect(m_fsAction, SIGNAL(added(DirItemInfo)), |
1804 | + this, SLOT(onItemAdded(DirItemInfo))); |
1805 | + |
1806 | + connect(m_fsAction, SIGNAL(added(QString)), |
1807 | + this, SLOT(onItemAdded(QString))); |
1808 | + |
1809 | + connect(m_fsAction, SIGNAL(removed(DirItemInfo)), |
1810 | + this, SLOT(onItemRemoved(DirItemInfo))); |
1811 | + |
1812 | + connect(m_fsAction, SIGNAL(removed(QString)), |
1813 | + this, SLOT(onItemRemoved(QString))); |
1814 | + |
1815 | + connect(m_fsAction, SIGNAL(error(QString,QString)), |
1816 | + this, SIGNAL(error(QString,QString))); |
1817 | + |
1818 | + connect(this, SIGNAL(pathChanged(QString)), |
1819 | + m_fsAction, SLOT(pathChanged(QString))); |
1820 | + |
1821 | + connect(mClipboard, SIGNAL(clipboardChanged()), |
1822 | + this, SIGNAL(clipboardChanged())); |
1823 | + |
1824 | + connect(m_fsAction, SIGNAL(changed(DirItemInfo)), |
1825 | + this, SLOT(onItemChanged(DirItemInfo))); |
1826 | + |
1827 | + connect(mClipboard, SIGNAL(clipboardChanged()), |
1828 | + m_fsAction, SLOT(onClipboardChanged())); |
1829 | + |
1830 | + connect(m_fsAction, SIGNAL(recopy(QStringList,QString)), |
1831 | + mClipboard, SLOT(copy(QStringList,QString))); |
1832 | + |
1833 | + setCompareAndReorder(); |
1834 | + |
1835 | + if (QIcon::themeName().isEmpty() && !FMUtil::hasTriedThemeName()) |
1836 | + { |
1837 | + FMUtil::setThemeName(); |
1838 | + } |
1839 | +} |
1840 | + |
1841 | + |
1842 | + |
1843 | +DirModel::~DirModel() |
1844 | +{ |
1845 | + stoptExternalFsWatcher(); |
1846 | +} |
1847 | + |
1848 | + |
1849 | + |
1850 | +QHash<int, QByteArray> DirModel::roleNames() const |
1851 | +{ |
1852 | + static QHash<int, QByteArray> roles; |
1853 | + if (roles.isEmpty()) { |
1854 | + roles = buildRoleNames(); |
1855 | + } |
1856 | + |
1857 | + return roles; |
1858 | +} |
1859 | + |
1860 | + |
1861 | + |
1862 | + |
1863 | +QHash<int, QByteArray> DirModel::buildRoleNames() const |
1864 | +{ |
1865 | + QHash<int, QByteArray> roles; |
1866 | + roles.insert(FileNameRole, QByteArray("fileName")); |
1867 | + roles.insert(AccessedDateRole, QByteArray("accessedDate")); |
1868 | + roles.insert(CreationDateRole, QByteArray("creationDate")); |
1869 | + roles.insert(ModifiedDateRole, QByteArray("modifiedDate")); |
1870 | + roles.insert(FileSizeRole, QByteArray("fileSize")); |
1871 | + roles.insert(IconSourceRole, QByteArray("iconSource")); |
1872 | + roles.insert(FilePathRole, QByteArray("filePath")); |
1873 | + roles.insert(IsDirRole, QByteArray("isDir")); |
1874 | + roles.insert(IsFileRole, QByteArray("isFile")); |
1875 | + roles.insert(IsReadableRole, QByteArray("isReadable")); |
1876 | + roles.insert(IsWritableRole, QByteArray("isWritable")); |
1877 | + roles.insert(IsExecutableRole, QByteArray("isExecutable")); |
1878 | + roles.insert(IsSelectedRole, QByteArray("isSelected")); |
1879 | + roles.insert(TrackTitleRole, QByteArray("trackTitle")); |
1880 | + roles.insert(TrackArtistRole, QByteArray("trackArtist")); |
1881 | + roles.insert(TrackAlbumRole, QByteArray("trackAlbum")); |
1882 | + roles.insert(TrackYearRole, QByteArray("trackYear")); |
1883 | + roles.insert(TrackNumberRole, QByteArray("trackNumber")); |
1884 | + roles.insert(TrackGenreRole, QByteArray("trackGenre")); |
1885 | + roles.insert(TrackLengthRole, QByteArray("trackLength")); |
1886 | + roles.insert(TrackCoverRole, QByteArray("trackCover")); |
1887 | + |
1888 | + // populate reverse mapping |
1889 | + if (roleMapping.isEmpty()) { |
1890 | + QHash<int, QByteArray>::ConstIterator it = roles.constBegin(); |
1891 | + for (;it != roles.constEnd(); ++it) |
1892 | + roleMapping.insert(it.value(), it.key()); |
1893 | + |
1894 | + // make sure we cover all roles |
1895 | + // Q_ASSERT(roles.count() == IsFileRole - FileNameRole); |
1896 | + } |
1897 | + |
1898 | + return roles; |
1899 | +} |
1900 | + |
1901 | +QVariant DirModel::data(int row, const QByteArray &stringRole) const |
1902 | +{ |
1903 | + QHash<QByteArray, int>::ConstIterator it = roleMapping.constFind(stringRole); |
1904 | + |
1905 | + if (it == roleMapping.constEnd()) |
1906 | + return QVariant(); |
1907 | + |
1908 | + return data(index(row, 0), *it); |
1909 | +} |
1910 | + |
1911 | +QVariant DirModel::data(const QModelIndex &index, int role) const |
1912 | +{ |
1913 | +//its not for QML |
1914 | +#if defined(REGRESSION_TEST_FOLDERLISTMODEL) |
1915 | + if (!index.isValid() || |
1916 | + (role != Qt::DisplayRole && role != Qt::DecorationRole && role != Qt::BackgroundRole) |
1917 | + ) |
1918 | + { |
1919 | + return QVariant(); |
1920 | + } |
1921 | + if (role == Qt::DecorationRole && index.column() == 0) |
1922 | + { |
1923 | + QIcon icon; |
1924 | + QMimeType mime = mDirectoryContents.at(index.row()).mimeType(); |
1925 | + if (mime.isValid()) |
1926 | + { |
1927 | + if (QIcon::hasThemeIcon(mime.iconName()) ) { |
1928 | + icon = QIcon::fromTheme(mime.iconName()); |
1929 | + } |
1930 | + else if (QIcon::hasThemeIcon(mime.genericIconName())) { |
1931 | + icon = QIcon::fromTheme(mime.genericIconName()); |
1932 | + } |
1933 | + } |
1934 | + if (icon.isNull()) |
1935 | + { |
1936 | + if (mDirectoryContents.at(index.row()).isLocal()) |
1937 | + { |
1938 | + icon = QFileIconProvider().icon(mDirectoryContents.at(index.row()).diskFileInfo()); |
1939 | + } |
1940 | + else |
1941 | + if (mDirectoryContents.at(index.row()).isDir()) |
1942 | + { |
1943 | + icon = QFileIconProvider().icon(QFileIconProvider::Folder); |
1944 | + } |
1945 | + else |
1946 | + { |
1947 | + icon = QFileIconProvider().icon(QFileIconProvider::File); |
1948 | + } |
1949 | + } |
1950 | + return icon; |
1951 | + } |
1952 | + if (role == Qt::BackgroundRole && index.column() == 0) |
1953 | + { |
1954 | + if (mDirectoryContents.at(index.row()).isSelected()) |
1955 | + { |
1956 | + //TODO it'd better to get some style or other default |
1957 | + // background color |
1958 | + return QBrush(Qt::lightGray); |
1959 | + } |
1960 | + return QVariant(); |
1961 | + } |
1962 | + role = FileNameRole + index.column(); |
1963 | +#else |
1964 | + if (role < FileNameRole || role > TrackCoverRole) { |
1965 | + qWarning() << Q_FUNC_INFO << this << "Got an out of range role: " << role; |
1966 | + return QVariant(); |
1967 | + } |
1968 | + |
1969 | + if (index.row() < 0 || index.row() >= mDirectoryContents.count()) { |
1970 | + qWarning() << "Attempted to access out of range row: " << index.row(); |
1971 | + return QVariant(); |
1972 | + } |
1973 | + |
1974 | + if (index.column() != 0) |
1975 | + return QVariant(); |
1976 | +#endif |
1977 | + |
1978 | + const DirItemInfo &fi = mDirectoryContents.at(index.row()); |
1979 | + |
1980 | + switch (role) { |
1981 | + case FileNameRole: |
1982 | + return fi.fileName(); |
1983 | + case AccessedDateRole: |
1984 | + return fi.lastRead(); |
1985 | + case CreationDateRole: |
1986 | + return fi.created(); |
1987 | + case ModifiedDateRole: |
1988 | + return fi.lastModified(); |
1989 | + case FileSizeRole: { |
1990 | + if (fi.isDir() && fi.isLocal()) |
1991 | + { |
1992 | + return dirItems(fi.diskFileInfo()); |
1993 | + } |
1994 | + return fileSize(fi.size()); |
1995 | + } |
1996 | + case IconSourceRole: { |
1997 | + const QString &fileName = fi.fileName(); |
1998 | + |
1999 | + if (fi.isDir()) |
2000 | + return QLatin1String("image://theme/icon-m-common-directory"); |
2001 | + |
2002 | + if (fileName.endsWith(QLatin1String(".jpg"), Qt::CaseInsensitive) || |
2003 | + fileName.endsWith(QLatin1String(".png"), Qt::CaseInsensitive)) { |
2004 | + return QLatin1String("image://nemoThumbnail/") + fi.filePath(); |
2005 | + } |
2006 | + |
2007 | + return "image://theme/icon-m-content-document"; |
2008 | + } |
2009 | + case FilePathRole: |
2010 | + return fi.filePath(); |
2011 | + case IsDirRole: |
2012 | + return fi.isDir(); |
2013 | + case IsFileRole: |
2014 | + return !fi.isDir(); |
2015 | + case IsReadableRole: |
2016 | + return fi.isReadable(); |
2017 | + case IsWritableRole: |
2018 | + return fi.isWritable(); |
2019 | + case IsExecutableRole: |
2020 | + return fi.isExecutable(); |
2021 | + case IsSelectedRole: |
2022 | + return fi.isSelected(); |
2023 | +#ifndef DO_NOT_USE_TAG_LIB |
2024 | + case TrackTitleRole: |
2025 | + case TrackArtistRole: |
2026 | + case TrackAlbumRole: |
2027 | + case TrackYearRole: |
2028 | + case TrackNumberRole: |
2029 | + case TrackGenreRole: |
2030 | + case TrackLengthRole: |
2031 | + case TrackCoverRole: |
2032 | + if (mReadsMediaMetadata && fi.isLocal()) |
2033 | + { |
2034 | + return getAudioMetaData(fi.diskFileInfo(), role); |
2035 | + } |
2036 | + break; |
2037 | +#endif |
2038 | + default: |
2039 | +#if !defined(REGRESSION_TEST_FOLDERLISTMODEL) |
2040 | + // this should not happen, ever |
2041 | + Q_ASSERT(false); |
2042 | + qWarning() << Q_FUNC_INFO << this << "Got an unknown role: " << role; |
2043 | +#endif |
2044 | + break; |
2045 | + } |
2046 | + |
2047 | + return QVariant(); |
2048 | +} |
2049 | + |
2050 | +void DirModel::setPath(const QString &pathName) |
2051 | +{ |
2052 | + if (pathName.isEmpty()) |
2053 | + return; |
2054 | + |
2055 | + if (!canReadDir(pathName)) |
2056 | + { |
2057 | + emit error(tr("cannot read path"), pathName); |
2058 | + return; |
2059 | + } |
2060 | + |
2061 | + if (mAwaitingResults) { |
2062 | + // TODO: handle the case where pathName != our current path, cancel old |
2063 | + // request, start a new one |
2064 | + qDebug() << Q_FUNC_INFO << this << "Ignoring path change request, request already running"; |
2065 | + return; |
2066 | + } |
2067 | + |
2068 | + mAwaitingResults = true; |
2069 | + emit awaitingResultsChanged(); |
2070 | +#if DEBUG_MESSAGES |
2071 | + qDebug() << Q_FUNC_INFO << this << "Changing to " << pathName << " on " << QThread::currentThreadId(); |
2072 | +#endif |
2073 | + |
2074 | + clear(); |
2075 | + |
2076 | + DirListWorker *dlw = createWorkerRequest(IORequest::DirList, pathName); |
2077 | + connect(dlw, SIGNAL(itemsAdded(DirItemInfoList)), SLOT(onItemsAdded(DirItemInfoList))); |
2078 | + connect(dlw, SIGNAL(workerFinished()), SLOT(onResultsFetched())); |
2079 | + ioWorkerThread()->addRequest(dlw); |
2080 | + |
2081 | + mCurrentDir = pathName; |
2082 | + emit pathChanged(pathName); |
2083 | +} |
2084 | + |
2085 | + |
2086 | +void DirModel::onResultsFetched() { |
2087 | + if (mAwaitingResults) { |
2088 | +#if DEBUG_MESSAGES |
2089 | + qDebug() << Q_FUNC_INFO << this << "No longer awaiting results"; |
2090 | +#endif |
2091 | + mAwaitingResults = false; |
2092 | + emit awaitingResultsChanged(); |
2093 | + } |
2094 | +} |
2095 | + |
2096 | +void DirModel::onItemsAdded(const DirItemInfoList &newFiles) |
2097 | +{ |
2098 | +#if DEBUG_MESSAGES |
2099 | + qDebug() << Q_FUNC_INFO << this << "Got new files: " << newFiles.count(); |
2100 | +#endif |
2101 | + |
2102 | + if (newFiles.count() > 0) |
2103 | + { |
2104 | + mDirectoryContents.reserve(newFiles.count()) ; |
2105 | + } |
2106 | + foreach (const DirItemInfo &fi, newFiles) { |
2107 | + |
2108 | + bool doAdd = false; |
2109 | + foreach (const QString &nameFilter, mNameFilters) { |
2110 | + // TODO: using QRegExp for wildcard matching is slow |
2111 | + QRegExp re(nameFilter, Qt::CaseInsensitive, QRegExp::Wildcard); |
2112 | + if (re.exactMatch(fi.fileName()) || (fi.isDir() && !mFilterDirectories)) { |
2113 | + doAdd = true; |
2114 | + break; |
2115 | + } |
2116 | + } |
2117 | + |
2118 | + if (!doAdd) |
2119 | + continue; |
2120 | + |
2121 | + addItem(fi); |
2122 | + } |
2123 | +} |
2124 | + |
2125 | +void DirModel::rm(const QStringList &paths) |
2126 | +{ |
2127 | + m_fsAction->remove(paths); |
2128 | +} |
2129 | + |
2130 | + |
2131 | +bool DirModel::rename(const QString& oldName, const QString &newName) |
2132 | +{ |
2133 | + return rename(getIndex(oldName), newName); |
2134 | +} |
2135 | + |
2136 | + |
2137 | +bool DirModel::rename(int row, const QString &newName) |
2138 | +{ |
2139 | +#if DEBUG_MESSAGES |
2140 | + qDebug() << Q_FUNC_INFO << this << "Renaming " << row << " to " << newName; |
2141 | +#endif |
2142 | + |
2143 | + if (!IS_VALID_ROW(row)) { |
2144 | + WARN_ROW_OUT_OF_RANGE(row); |
2145 | + return false; |
2146 | + } |
2147 | + |
2148 | + const DirItemInfo &fi = mDirectoryContents.at(row); |
2149 | + QString newFullFilename(fi.absolutePath() + QDir::separator() + newName); |
2150 | + |
2151 | + //QFile::rename() works for File and Dir |
2152 | + QFile f(fi.absoluteFilePath()); |
2153 | + bool retval = f.rename(newFullFilename); |
2154 | + if (!retval) |
2155 | + { |
2156 | + qDebug() << Q_FUNC_INFO << this << "Rename returned error code: " << f.error() << f.errorString(); |
2157 | + emit(QObject::tr("Rename error"), f.errorString()); |
2158 | + } |
2159 | + else |
2160 | + { |
2161 | + bool isSelected = mDirectoryContents.at(row).isSelected(); |
2162 | + onItemRemoved(mDirectoryContents.at(row)); |
2163 | + int newRow = addItem(DirItemInfo(QFileInfo(newFullFilename))); |
2164 | + //keep previous selected state, selection takes care of everything |
2165 | + mSelection->setIndex(newRow,isSelected); |
2166 | + } |
2167 | + return retval; |
2168 | +} |
2169 | + |
2170 | +void DirModel::mkdir(const QString &newDir) |
2171 | +{ |
2172 | + QDir dir(mCurrentDir); |
2173 | + bool retval = dir.mkdir(newDir); |
2174 | + if (!retval) { |
2175 | + const char *errorStr = strerror(errno); |
2176 | + qDebug() << Q_FUNC_INFO << this << "Error creating new directory: " << errno << " (" << errorStr << ")"; |
2177 | + emit error(QObject::tr("Error creating new folder"), errorStr); |
2178 | + } else { |
2179 | + onItemAdded(dir.filePath(newDir)); |
2180 | + } |
2181 | +} |
2182 | + |
2183 | +bool DirModel::showDirectories() const |
2184 | +{ |
2185 | + return mShowDirectories; |
2186 | +} |
2187 | + |
2188 | +void DirModel::setShowDirectories(bool showDirectories) |
2189 | +{ |
2190 | + mShowDirectories = showDirectories; |
2191 | + refresh(); |
2192 | + emit showDirectoriesChanged(); |
2193 | +} |
2194 | + |
2195 | +bool DirModel::isRecursive() const |
2196 | +{ |
2197 | + return mIsRecursive; |
2198 | +} |
2199 | + |
2200 | +void DirModel::setIsRecursive(bool isRecursive) |
2201 | +{ |
2202 | + mIsRecursive = isRecursive; |
2203 | + refresh(); |
2204 | + emit isRecursiveChanged(); |
2205 | +} |
2206 | + |
2207 | +bool DirModel::readsMediaMetadata() const |
2208 | +{ |
2209 | + return mReadsMediaMetadata; |
2210 | +} |
2211 | + |
2212 | +void DirModel::setReadsMediaMetadata(bool readsMediaMetadata) |
2213 | +{ |
2214 | + mReadsMediaMetadata = readsMediaMetadata; |
2215 | + refresh(); |
2216 | + emit readsMediaMetadataChanged(); |
2217 | +} |
2218 | + |
2219 | +bool DirModel::filterDirectories() const |
2220 | +{ |
2221 | + return mFilterDirectories; |
2222 | +} |
2223 | + |
2224 | +void DirModel::setFilterDirectories(bool filterDirectories) |
2225 | +{ |
2226 | + mFilterDirectories = filterDirectories; |
2227 | + refresh(); |
2228 | + emit filterDirectoriesChanged(); |
2229 | +} |
2230 | + |
2231 | +QStringList DirModel::nameFilters() const |
2232 | +{ |
2233 | + return mNameFilters; |
2234 | +} |
2235 | + |
2236 | +void DirModel::setNameFilters(const QStringList &nameFilters) |
2237 | +{ |
2238 | + mNameFilters = nameFilters; |
2239 | + refresh(); |
2240 | + emit nameFiltersChanged(); |
2241 | +} |
2242 | + |
2243 | +bool DirModel::awaitingResults() const |
2244 | +{ |
2245 | + return mAwaitingResults; |
2246 | +} |
2247 | + |
2248 | + |
2249 | +QString DirModel::parentPath() const |
2250 | +{ |
2251 | + QDir dir(mCurrentDir); |
2252 | + if (dir.isRoot()) { |
2253 | + qDebug() << Q_FUNC_INFO << this << "already at root"; |
2254 | + return mCurrentDir; |
2255 | + } |
2256 | + |
2257 | + bool success = dir.cdUp(); |
2258 | + if (!success) { |
2259 | + qWarning() << Q_FUNC_INFO << this << "Failed to to go to parent of " << mCurrentDir; |
2260 | + return mCurrentDir; |
2261 | + } |
2262 | + qDebug() << Q_FUNC_INFO << this << "returning" << dir.absolutePath(); |
2263 | + return dir.absolutePath(); |
2264 | +} |
2265 | + |
2266 | +QString DirModel::homePath() const |
2267 | +{ |
2268 | + return QDir::homePath(); |
2269 | +} |
2270 | + |
2271 | +#if defined(REGRESSION_TEST_FOLDERLISTMODEL) |
2272 | + QVariant DirModel::headerData(int section, Qt::Orientation orientation, int role) const |
2273 | + { |
2274 | + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) |
2275 | + { |
2276 | + QVariant ret; |
2277 | + QHash<int, QByteArray> roles = this->roleNames(); |
2278 | + section += FileNameRole; |
2279 | + if (roles.contains(section)) |
2280 | + { |
2281 | + QString header= QString(roles.value(section)); |
2282 | + ret = header; |
2283 | + } |
2284 | + return ret; |
2285 | + } |
2286 | + return QAbstractItemModel::headerData(section, orientation, role); |
2287 | + } |
2288 | +#endif |
2289 | + |
2290 | + |
2291 | +void DirModel::goHome() |
2292 | +{ |
2293 | + setPath(QDir::homePath()); |
2294 | +} |
2295 | + |
2296 | + |
2297 | +bool DirModel::cdUp() |
2298 | +{ |
2299 | + int ret = false; |
2300 | + if (!mCurrentDir.isEmpty()) // we are in any dir |
2301 | + { |
2302 | + QDir current(mCurrentDir); |
2303 | + if (current.cdUp()) |
2304 | + { |
2305 | + setPath(current.absolutePath()); |
2306 | + ret = true; |
2307 | + } |
2308 | + } |
2309 | + return ret; |
2310 | +} |
2311 | + |
2312 | + |
2313 | +void DirModel::removeIndex(int row) |
2314 | +{ |
2315 | + if (IS_VALID_ROW(row)) |
2316 | + { |
2317 | + const DirItemInfo &fi = mDirectoryContents.at(row); |
2318 | + QStringList list(fi.absoluteFilePath()); |
2319 | + this->rm(list); |
2320 | + } |
2321 | + else |
2322 | + { |
2323 | + WARN_ROW_OUT_OF_RANGE(row); |
2324 | + } |
2325 | +} |
2326 | + |
2327 | +void DirModel::removePaths(const QStringList& items) |
2328 | +{ |
2329 | + this->rm(items); |
2330 | +} |
2331 | + |
2332 | +void DirModel::copyIndex(int row) |
2333 | +{ |
2334 | + if (IS_VALID_ROW(row)) |
2335 | + { |
2336 | + const DirItemInfo &fi = mDirectoryContents.at(row); |
2337 | + QStringList list(fi.absoluteFilePath()); |
2338 | + this->copyPaths(list); |
2339 | + } |
2340 | + else |
2341 | + { |
2342 | + WARN_ROW_OUT_OF_RANGE(row); |
2343 | + } |
2344 | +} |
2345 | + |
2346 | +void DirModel::copyPaths(const QStringList &items) |
2347 | +{ |
2348 | + mClipboard->copy(items, mCurrentDir); |
2349 | +} |
2350 | + |
2351 | + |
2352 | +void DirModel::cutIndex(int row) |
2353 | +{ |
2354 | + if (IS_VALID_ROW(row)) |
2355 | + { |
2356 | + const DirItemInfo &fi = mDirectoryContents.at(row); |
2357 | + QStringList list(fi.absoluteFilePath()); |
2358 | + this->cutPaths(list); |
2359 | + } |
2360 | + else |
2361 | + { |
2362 | + WARN_ROW_OUT_OF_RANGE(row); |
2363 | + } |
2364 | +} |
2365 | + |
2366 | + |
2367 | +void DirModel::cutPaths(const QStringList &items) |
2368 | +{ |
2369 | + mClipboard->cut(items, mCurrentDir); |
2370 | +} |
2371 | + |
2372 | + |
2373 | +void DirModel::paste() |
2374 | +{ |
2375 | + ClipboardOperation operation; |
2376 | + QStringList items = mClipboard->paste(operation); |
2377 | + if (operation == ClipboardCut) |
2378 | + { |
2379 | + m_fsAction->moveIntoCurrentPath(items); |
2380 | + } |
2381 | + else |
2382 | + { |
2383 | + m_fsAction->copyIntoCurrentPath(items); |
2384 | + } |
2385 | +} |
2386 | + |
2387 | + |
2388 | +bool DirModel::cdIntoIndex(int row) |
2389 | +{ |
2390 | + bool ret = false; |
2391 | + if (IS_VALID_ROW(row)) |
2392 | + { |
2393 | + ret = cdInto(mDirectoryContents.at(row)); |
2394 | + } |
2395 | + else |
2396 | + { |
2397 | + WARN_ROW_OUT_OF_RANGE(row); |
2398 | + } |
2399 | + return ret; |
2400 | +} |
2401 | + |
2402 | + |
2403 | +bool DirModel::cdIntoPath(const QString &filename) |
2404 | +{ |
2405 | + bool ret = false; |
2406 | + DirItemInfo fi(filename); |
2407 | + if (fi.isValid()) |
2408 | + { |
2409 | + if (fi.isRelative()) |
2410 | + { |
2411 | + fi.setFile(mCurrentDir, filename); |
2412 | + } |
2413 | + ret = cdInto(fi); |
2414 | + } |
2415 | + return ret; |
2416 | +} |
2417 | + |
2418 | + |
2419 | +bool DirModel::cdInto(const DirItemInfo &fi) |
2420 | +{ |
2421 | + bool ret = false; |
2422 | + if (canReadDir(fi.diskFileInfo())) |
2423 | + { |
2424 | + if (fi.isRelative()) |
2425 | + { |
2426 | + QDir childDir(mCurrentDir); |
2427 | + if ( childDir.cd(fi.fileName()) ) |
2428 | + { |
2429 | + setPath(childDir.absolutePath()); |
2430 | + ret = true; |
2431 | + } |
2432 | + } |
2433 | + else |
2434 | + { |
2435 | + ret = true; |
2436 | + setPath(fi.absoluteFilePath()); |
2437 | + } |
2438 | + } |
2439 | + return ret; |
2440 | +} |
2441 | + |
2442 | +/*! |
2443 | + * \brief DirModel::onItemRemoved() |
2444 | + * \param pathname full pathname of removed file |
2445 | + */ |
2446 | +void DirModel::onItemRemoved(const QString &pathname) |
2447 | +{ |
2448 | + DirItemInfo info(pathname); |
2449 | + onItemRemoved(info); |
2450 | +} |
2451 | + |
2452 | + |
2453 | +void DirModel::onItemRemoved(const DirItemInfo &fi) |
2454 | +{ |
2455 | + int row = rowOfItem(fi); |
2456 | +#if DEBUG_MESSAGES || DEBUG_EXT_FS_WATCHER |
2457 | + qDebug() << Q_FUNC_INFO << this |
2458 | + << "row" << row |
2459 | + << "name" << fi.absoluteFilePath() |
2460 | + << "removed[True|False]:" << (row >= 0); |
2461 | +#endif |
2462 | + if (row >= 0) |
2463 | + { |
2464 | + beginRemoveRows(QModelIndex(), row, row); |
2465 | + if (mDirectoryContents.at(row).isSelected()) |
2466 | + { |
2467 | + mSelection->itemGoingToBeRemoved(mDirectoryContents.at(row)); |
2468 | + } |
2469 | + mDirectoryContents.remove(row,1); |
2470 | + endRemoveRows(); |
2471 | + } |
2472 | +} |
2473 | + |
2474 | + |
2475 | +/*! |
2476 | + * \brief DirModel::onItemAdded() |
2477 | + * \param pathname full pathname of the added file |
2478 | + */ |
2479 | +void DirModel::onItemAdded(const QString &pathname) |
2480 | +{ |
2481 | + DirItemInfo info(pathname); |
2482 | + onItemAdded(info); |
2483 | +} |
2484 | + |
2485 | + |
2486 | +void DirModel::onItemAdded(const DirItemInfo &fi) |
2487 | +{ |
2488 | + int newRow = addItem(fi); |
2489 | + emit insertedRow(newRow); |
2490 | +} |
2491 | + |
2492 | +/*! |
2493 | + * \brief DirModel::addItem() adds an item into the model |
2494 | + * This code was moved from onItemsAdded(const QVector<QFileInfo> &newFiles), |
2495 | + * the reason is: this code now is used for \ref mkdir() and for \ref paste() operations |
2496 | + * that inserts new items |
2497 | + * \param fi |
2498 | + * \return the index where it was inserted, it can be used in the view |
2499 | + * \sa insertedRow() |
2500 | + */ |
2501 | +int DirModel::addItem(const DirItemInfo &fi) |
2502 | +{ |
2503 | + DirItemInfoList::Iterator it = qLowerBound(mDirectoryContents.begin(), |
2504 | + mDirectoryContents.end(), |
2505 | + fi, |
2506 | + mCompareFunction); |
2507 | + int idx = mDirectoryContents.count(); |
2508 | + |
2509 | + if (it == mDirectoryContents.end()) { |
2510 | + beginInsertRows(QModelIndex(), idx, idx); |
2511 | + mDirectoryContents.append(fi); |
2512 | + endInsertRows(); |
2513 | + } else { |
2514 | + idx = it - mDirectoryContents.begin(); |
2515 | + beginInsertRows(QModelIndex(), idx, idx); |
2516 | + mDirectoryContents.insert(it, fi); |
2517 | + endInsertRows(); |
2518 | + } |
2519 | + return idx; |
2520 | +} |
2521 | + |
2522 | +/*! |
2523 | + * \brief DirModel::onItemChanged() Changes an item data |
2524 | + * |
2525 | + * \note If the item does not exist it is inserted |
2526 | + * |
2527 | + * \param fi DirItemInfo of the item |
2528 | + */ |
2529 | +void DirModel::onItemChanged(const DirItemInfo &fi) |
2530 | +{ |
2531 | + int row = rowOfItem(fi); |
2532 | + if (row >= 0) |
2533 | + { |
2534 | + if (mDirectoryContents.at(row).isSelected()) |
2535 | + { |
2536 | + mSelection->itemGoingToBeReplaced(mDirectoryContents.at(row), fi); |
2537 | + DirItemInfo *myFi = const_cast<DirItemInfo*> (&fi); |
2538 | + myFi->setSelection(true); |
2539 | + } |
2540 | + mDirectoryContents[row] = fi; |
2541 | + notifyItemChanged(row); |
2542 | + } |
2543 | + else |
2544 | + { // it simplifies some logic outside, when removing and adding on the same operation |
2545 | + onItemAdded(fi); |
2546 | + } |
2547 | +} |
2548 | + |
2549 | + |
2550 | +void DirModel::cancelAction() |
2551 | +{ |
2552 | + m_fsAction->cancel(); |
2553 | +} |
2554 | + |
2555 | + |
2556 | +QString DirModel::fileSize(qint64 size) const |
2557 | +{ |
2558 | + struct UnitSizes |
2559 | + { |
2560 | + qint64 bytes; |
2561 | + const char *name; |
2562 | + }; |
2563 | + |
2564 | + static UnitSizes m_unitBytes[5] = |
2565 | + { |
2566 | + { 1, "Bytes" } |
2567 | + ,{1024, "kB"} |
2568 | + // got it from http://wiki.answers.com/Q/How_many_bytes_are_in_a_megabyte |
2569 | + ,{1000 * 1000, "MB"} |
2570 | + ,{1000 * m_unitBytes[2].bytes, "GB"} |
2571 | + ,{1000 * m_unitBytes[3].bytes, "TB"} |
2572 | + }; |
2573 | + |
2574 | + QString ret; |
2575 | + int unit = sizeof(m_unitBytes)/sizeof(m_unitBytes[0]); |
2576 | + while( unit-- > 1 && size < m_unitBytes[unit].bytes ); |
2577 | + if (unit > 0 ) |
2578 | + { |
2579 | + ret.sprintf("%0.1f %s", (float)size/m_unitBytes[unit].bytes, |
2580 | + m_unitBytes[unit].name); |
2581 | + } |
2582 | + else |
2583 | + { |
2584 | + ret.sprintf("%ld %s", (long int)size, m_unitBytes[0].name); |
2585 | + } |
2586 | + return ret; |
2587 | +} |
2588 | + |
2589 | + |
2590 | + |
2591 | +bool DirModel::getShowHiddenFiles() const |
2592 | +{ |
2593 | + return mShowHiddenFiles; |
2594 | +} |
2595 | + |
2596 | + |
2597 | +void DirModel::setShowHiddenFiles(bool show) |
2598 | +{ |
2599 | + if (show != mShowHiddenFiles) |
2600 | + { |
2601 | + mShowHiddenFiles = show; |
2602 | + refresh(); |
2603 | + emit showHiddenFilesChanged(); |
2604 | + } |
2605 | +} |
2606 | + |
2607 | + |
2608 | +void DirModel::toggleShowDirectories() |
2609 | +{ |
2610 | + setShowDirectories(!mShowDirectories); |
2611 | +} |
2612 | + |
2613 | + |
2614 | +void DirModel::toggleShowHiddenFiles() |
2615 | +{ |
2616 | + setShowHiddenFiles(!mShowHiddenFiles); |
2617 | +} |
2618 | + |
2619 | + |
2620 | +DirModel::SortBy |
2621 | +DirModel::getSortBy() const |
2622 | +{ |
2623 | + return mSortBy; |
2624 | +} |
2625 | + |
2626 | + |
2627 | +void DirModel::setSortBy(SortBy field) |
2628 | +{ |
2629 | + if (field != mSortBy) |
2630 | + { |
2631 | + mSortBy = field; |
2632 | + setCompareAndReorder(); |
2633 | + emit sortByChanged(); |
2634 | + } |
2635 | +} |
2636 | + |
2637 | + |
2638 | +DirModel::SortOrder |
2639 | +DirModel::getSortOrder() const |
2640 | +{ |
2641 | + return mSortOrder; |
2642 | +} |
2643 | + |
2644 | +void DirModel::setSortOrder(SortOrder order) |
2645 | +{ |
2646 | + if ( order != mSortOrder ) |
2647 | + { |
2648 | + mSortOrder = order; |
2649 | + setCompareAndReorder(); |
2650 | + emit sortOrderChanged(); |
2651 | + } |
2652 | +} |
2653 | + |
2654 | + |
2655 | +void DirModel::toggleSortOrder() |
2656 | +{ |
2657 | + SortOrder order = static_cast<SortOrder> (mSortOrder ^ 1); |
2658 | + setSortOrder(order); |
2659 | +} |
2660 | + |
2661 | + |
2662 | +void DirModel::toggleSortBy() |
2663 | +{ |
2664 | + SortBy by = static_cast<SortBy> (mSortBy ^ 1); |
2665 | + setSortBy(by); |
2666 | +} |
2667 | + |
2668 | +/*! |
2669 | + * \brief DirModel::setCompareAndReorder() called when SortOrder or SortBy change |
2670 | + * |
2671 | + * It does not reload items from disk, just reorganize items from \a mDirectoryContents array |
2672 | + */ |
2673 | +void DirModel::setCompareAndReorder() |
2674 | +{ |
2675 | + mCompareFunction = availableCompareFunctions[mSortBy][mSortOrder]; |
2676 | + if (mDirectoryContents.count() > 0 && !mAwaitingResults ) |
2677 | + { |
2678 | + DirItemInfoList tmpDirectoryContents = mDirectoryContents; |
2679 | + beginResetModel(); |
2680 | + mDirectoryContents.clear(); |
2681 | + endResetModel(); |
2682 | + for(int counter=0; counter < tmpDirectoryContents.count(); counter++) |
2683 | + { |
2684 | + addItem(tmpDirectoryContents.at(counter)); |
2685 | + } |
2686 | + } |
2687 | +} |
2688 | + |
2689 | + |
2690 | +int DirModel::getClipboardUrlsCounter() const |
2691 | +{ |
2692 | + return mClipboard->clipboardLocalUrlsCounter(); |
2693 | +} |
2694 | + |
2695 | + |
2696 | +int DirModel::rowOfItem(const DirItemInfo& fi) |
2697 | +{ |
2698 | + int row = -1; |
2699 | + //to use qBinaryFind() the array needs to be ordered ascending |
2700 | + if (mCompareFunction == fileCompareAscending) |
2701 | + { |
2702 | + DirItemInfoList::Iterator it = qBinaryFind(mDirectoryContents.begin(), |
2703 | + mDirectoryContents.end(), |
2704 | + fi, |
2705 | + fileCompareExists); |
2706 | + if (it != mDirectoryContents.end()) |
2707 | + { |
2708 | + row = it - mDirectoryContents.begin(); |
2709 | + } |
2710 | + } |
2711 | + else //walk through whole array |
2712 | + { |
2713 | + //TODO improve this search |
2714 | + int counter = mDirectoryContents.count(); |
2715 | + while (counter--) |
2716 | + { |
2717 | + if ( 0 == QString::localeAwareCompare(fi.absoluteFilePath(), |
2718 | + mDirectoryContents.at(counter).absoluteFilePath()) ) |
2719 | + { |
2720 | + row = counter; |
2721 | + break; |
2722 | + } |
2723 | + } |
2724 | + } |
2725 | + return row; |
2726 | +} |
2727 | + |
2728 | + |
2729 | +QDir::Filter DirModel::currentDirFilter() const |
2730 | +{ |
2731 | + int filter = QDir::AllEntries | QDir::NoDotAndDotDot ; |
2732 | + if (!mShowDirectories) |
2733 | + { |
2734 | + filter &= ~QDir::AllDirs; |
2735 | + filter &= ~QDir::Dirs; |
2736 | + } |
2737 | + if (mShowHiddenFiles) |
2738 | + { |
2739 | + filter |= QDir::Hidden; |
2740 | + } |
2741 | + if (mIsRecursive) |
2742 | + { |
2743 | + filter |= QDir::NoSymLinks; |
2744 | + } |
2745 | + QDir::Filter dirFilter = static_cast<QDir::Filter>(filter); |
2746 | + return dirFilter; |
2747 | +} |
2748 | + |
2749 | +QString DirModel::dirItems(const DirItemInfo& fi) const |
2750 | +{ |
2751 | + int counter = 0; |
2752 | + QDir d(fi.absoluteFilePath(), QString(), QDir::NoSort, currentDirFilter()); |
2753 | + counter = d.count(); |
2754 | + if (counter < 0) |
2755 | + { |
2756 | + counter = 0; |
2757 | + } |
2758 | + QString ret (QString::number(counter) + QLatin1Char(' ')); |
2759 | + ret += QObject::tr("items"); |
2760 | + return ret; |
2761 | +} |
2762 | + |
2763 | + |
2764 | +bool DirModel::openIndex(int row) |
2765 | +{ |
2766 | + bool ret = false; |
2767 | + if (IS_VALID_ROW(row)) |
2768 | + { |
2769 | + ret = openItem(mDirectoryContents.at(row)); |
2770 | + } |
2771 | + else |
2772 | + { |
2773 | + WARN_ROW_OUT_OF_RANGE(row); |
2774 | + } |
2775 | + return ret; |
2776 | +} |
2777 | + |
2778 | +bool DirModel::openPath(const QString &filename) |
2779 | +{ |
2780 | + DirItemInfo fi(setParentIfRelative(filename)); |
2781 | + return openItem(fi); |
2782 | +} |
2783 | + |
2784 | +/*! |
2785 | + * \brief DirModel::openItem() opens a directory/file |
2786 | + * \param fi |
2787 | + * \return true it could open the item |
2788 | + */ |
2789 | +bool DirModel::openItem(const DirItemInfo &fi) |
2790 | +{ |
2791 | + bool ret = false; |
2792 | + if (fi.isLocal()) |
2793 | + { |
2794 | + if (canReadDir(fi.diskFileInfo())) |
2795 | + { |
2796 | + ret = cdInto(fi.diskFileInfo()); |
2797 | + } |
2798 | + else |
2799 | + { |
2800 | + //TODO open executables |
2801 | + if (canReadFile(fi.diskFileInfo())) |
2802 | + { |
2803 | + ret = QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absoluteFilePath())); |
2804 | + } |
2805 | + } |
2806 | + } |
2807 | + return ret; |
2808 | +} |
2809 | + |
2810 | +/*! |
2811 | + * \brief DirModel::createWorkerRequest() create a request for IORequestWorker |
2812 | + * \param requestType the common IORequest::DirList to fill a directory content |
2813 | + * or IORequest::DirAutoRefresh that will verify any external File System modification |
2814 | + * \param pathName the path to get content |
2815 | + * \return the thread object |
2816 | + */ |
2817 | +DirListWorker * DirModel::createWorkerRequest(IORequest::RequestType requestType, |
2818 | + const QString& pathName) |
2819 | +{ |
2820 | + DirListWorker * reqThread = 0; |
2821 | + QDir::Filter dirFilter = currentDirFilter(); |
2822 | + if (requestType == IORequest::DirList) |
2823 | + { |
2824 | + // TODO: we need to set a spinner active before we start getting results from DirListWorker |
2825 | + reqThread = new DirListWorker(pathName, dirFilter, mIsRecursive); |
2826 | + } |
2827 | + else |
2828 | + { |
2829 | + reqThread = new ExternalFileSystemChangesWorker(mDirectoryContents, |
2830 | + pathName, |
2831 | + dirFilter, mIsRecursive); |
2832 | + } |
2833 | + return reqThread; |
2834 | +} |
2835 | + |
2836 | + |
2837 | + |
2838 | +/*! |
2839 | + * \brief DirModel::startExternalFsWatcher() starts the External File System Watcher |
2840 | + */ |
2841 | +void DirModel::startExternalFsWatcher() |
2842 | +{ |
2843 | +#if DEBUG_EXT_FS_WATCHER |
2844 | + qDebug() << "[extFsWorker]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") |
2845 | + << Q_FUNC_INFO << this; |
2846 | + |
2847 | +#endif |
2848 | + if (!mExtFSWatcher) |
2849 | + { |
2850 | + mExtFSWatcher = new ExternalFSWatcher(this); |
2851 | + mExtFSWatcher->setIntervalToNotifyChanges(EX_FS_WATCHER_TIMER_INTERVAL); |
2852 | + connect(this, SIGNAL(pathChanged(QString)), |
2853 | + mExtFSWatcher, SLOT(setCurrentPath(QString))); |
2854 | + |
2855 | + connect(mExtFSWatcher, SIGNAL(pathModified()), |
2856 | + this, SLOT(onThereAreExternalChanges())); |
2857 | + |
2858 | + //setCurrentPath() checks for empty paths |
2859 | + mExtFSWatcher->setCurrentPath(mCurrentDir); |
2860 | + } |
2861 | +} |
2862 | + |
2863 | + |
2864 | + |
2865 | +/*! |
2866 | + * \brief DirModel::stoptExternalFsWatcher stops the External File System Watcher |
2867 | + */ |
2868 | +void DirModel::stoptExternalFsWatcher() |
2869 | +{ |
2870 | +#if DEBUG_EXT_FS_WATCHER |
2871 | + qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") |
2872 | + << Q_FUNC_INFO << this; |
2873 | +#endif |
2874 | + if (mExtFSWatcher) |
2875 | + { |
2876 | + delete mExtFSWatcher; |
2877 | + mExtFSWatcher = 0; |
2878 | + } |
2879 | +} |
2880 | + |
2881 | + |
2882 | +void DirModel::onThereAreExternalChanges() |
2883 | +{ |
2884 | + if ( IS_FILE_MANAGER_IDLE() ) |
2885 | + { |
2886 | +#if DEBUG_EXT_FS_WATCHER |
2887 | + qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") |
2888 | + << Q_FUNC_INFO << this << "File System modified"; |
2889 | +#endif |
2890 | + DirListWorker *w = |
2891 | + createWorkerRequest(IORequest::DirListExternalFSChanges, |
2892 | + mCurrentDir |
2893 | + ); |
2894 | + ExternalFileSystemChangesWorker *extFsWorker = |
2895 | + static_cast<ExternalFileSystemChangesWorker*> (w); |
2896 | + |
2897 | + connect(extFsWorker, SIGNAL(added(DirItemInfo)), |
2898 | + this, SLOT(onItemAddedOutsideFm(DirItemInfo))); |
2899 | + connect(extFsWorker, SIGNAL(removed(DirItemInfo)), |
2900 | + this, SLOT(onItemRemovedOutSideFm(DirItemInfo))); |
2901 | + connect(extFsWorker, SIGNAL(changed(DirItemInfo)), |
2902 | + this, SLOT(onItemChangedOutSideFm(DirItemInfo))); |
2903 | + connect(extFsWorker, SIGNAL(finished(int)), |
2904 | + this, SLOT(onExternalFsWorkerFinished(int))); |
2905 | + |
2906 | + ioWorkerThread()->addRequest(extFsWorker); |
2907 | + } |
2908 | +#if DEBUG_EXT_FS_WATCHER |
2909 | + else |
2910 | + { |
2911 | + qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") |
2912 | + << Q_FUNC_INFO << this << "Busy, nothing to do"; |
2913 | + } |
2914 | +#endif |
2915 | +} |
2916 | + |
2917 | +/*! |
2918 | + * \brief DirModel::onItemAddedOutsideFm() It receives a signal saying an item was added by other application |
2919 | + * \param fi |
2920 | + */ |
2921 | +void DirModel::onItemAddedOutsideFm(const DirItemInfo &fi) |
2922 | +{ |
2923 | +#if DEBUG_EXT_FS_WATCHER |
2924 | + int before = rowCount(); |
2925 | +#endif |
2926 | + if (IS_FILE_MANAGER_IDLE()) |
2927 | + { |
2928 | + int row = rowOfItem(fi); |
2929 | + if (row == -1) |
2930 | + { |
2931 | + onItemAdded(fi); |
2932 | + } |
2933 | + } |
2934 | +#if DEBUG_EXT_FS_WATCHER |
2935 | + qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") |
2936 | + << Q_FUNC_INFO << this |
2937 | + << "counterBefore:" << before |
2938 | + << "added" << fi.absoluteFilePath() |
2939 | + << "counterAfter:" << rowCount(); |
2940 | +#endif |
2941 | +} |
2942 | + |
2943 | +/*! |
2944 | + * \brief DirModel::onItemRemovedOutSideFm() It receives a signal saying an item was removed by other application |
2945 | + * |
2946 | + * Just calls \ref onItemRemoved() which already checks if the item exists |
2947 | + * |
2948 | + * \param fi |
2949 | + */ |
2950 | +void DirModel::onItemRemovedOutSideFm(const DirItemInfo &fi) |
2951 | +{ |
2952 | + if (IS_FILE_MANAGER_IDLE()) |
2953 | + { |
2954 | +#if DEBUG_EXT_FS_WATCHER |
2955 | + qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") |
2956 | + << Q_FUNC_INFO << this << "removed" << fi.absoluteFilePath(); |
2957 | +#endif |
2958 | + onItemRemoved(fi); |
2959 | + } |
2960 | +} |
2961 | + |
2962 | +/*! |
2963 | + * \brief DirModel::onItemChangedOutSideFm() |
2964 | + * |
2965 | + * A File or a Dir modified by other applications: size,date, permissions |
2966 | + */ |
2967 | +void DirModel::onItemChangedOutSideFm(const DirItemInfo &fi) |
2968 | +{ |
2969 | + if (IS_FILE_MANAGER_IDLE()) |
2970 | + { |
2971 | + onItemChanged(fi); |
2972 | +#if DEBUG_EXT_FS_WATCHER |
2973 | + qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") |
2974 | + << Q_FUNC_INFO << this << "changed" << fi.absoluteFilePath() |
2975 | + << "from row" << rowOfItem(fi); |
2976 | +#endif |
2977 | + } |
2978 | +} |
2979 | + |
2980 | + |
2981 | +/*! |
2982 | + * \brief DirModel::onExternalFsWatcherFinihed() |
2983 | + */ |
2984 | +void DirModel::onExternalFsWorkerFinished(int currentDirCounter) |
2985 | +{ |
2986 | + |
2987 | +#if DEBUG_EXT_FS_WATCHER |
2988 | + qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") |
2989 | + << Q_FUNC_INFO << this |
2990 | + << "currentDirCounter:" << currentDirCounter; |
2991 | + |
2992 | +#endif |
2993 | + if (currentDirCounter == 0 && IS_FILE_MANAGER_IDLE()) |
2994 | + { |
2995 | + clear(); |
2996 | + } |
2997 | +} |
2998 | + |
2999 | + |
3000 | +/*! |
3001 | + * \brief DirModel:getEnabledExternalFSWatcher() |
3002 | + * \return true if the External File System Watcher is enabled |
3003 | + */ |
3004 | +bool DirModel::getEnabledExternalFSWatcher() const |
3005 | +{ |
3006 | + return mExtFSWatcher ? true : false; |
3007 | +} |
3008 | + |
3009 | + |
3010 | +/*! |
3011 | + * \brief DirModel::setEnabledExternalFSWatcher() enable/disable External File Sysmte Watcher |
3012 | + * \param enable |
3013 | + */ |
3014 | +void DirModel::setEnabledExternalFSWatcher(bool enable) |
3015 | +{ |
3016 | + if(enable) |
3017 | + { |
3018 | + startExternalFsWatcher(); |
3019 | + } |
3020 | + else |
3021 | + { |
3022 | + stoptExternalFsWatcher(); |
3023 | + } |
3024 | +} |
3025 | + |
3026 | + |
3027 | +bool DirModel::existsDir(const QString &folderName) const |
3028 | +{ |
3029 | + DirItemInfo d(setParentIfRelative(folderName)); |
3030 | + return d.exists() && d.isDir(); |
3031 | +} |
3032 | + |
3033 | +bool DirModel::canReadDir(const QString &folderName) const |
3034 | +{ |
3035 | + DirItemInfo d(setParentIfRelative(folderName)); |
3036 | + return canReadDir(d.diskFileInfo()); |
3037 | +} |
3038 | + |
3039 | +bool DirModel::canReadDir(const QFileInfo & d) const |
3040 | +{ |
3041 | + return d.exists() && d.isDir() && d.isReadable() && d.isExecutable(); |
3042 | +} |
3043 | + |
3044 | +bool DirModel::existsFile(const QString &fileName) const |
3045 | +{ |
3046 | + DirItemInfo f(setParentIfRelative(fileName)); |
3047 | + return f.exists() && f.isFile(); |
3048 | +} |
3049 | + |
3050 | +bool DirModel::canReadFile(const QString &fileName) const |
3051 | +{ |
3052 | + DirItemInfo f(setParentIfRelative(fileName)); |
3053 | + return canReadFile(f.diskFileInfo()); |
3054 | +} |
3055 | + |
3056 | +bool DirModel::canReadFile(const QFileInfo &f) const |
3057 | +{ |
3058 | + return f.exists() && f.isFile() && f.isReadable(); |
3059 | +} |
3060 | + |
3061 | + |
3062 | + |
3063 | +QDateTime DirModel::curPathCreatedDate() const |
3064 | +{ |
3065 | + QDateTime d; |
3066 | + QFileInfo f(mCurrentDir); |
3067 | + if (f.exists()) |
3068 | + { |
3069 | + d = f.created(); |
3070 | + } |
3071 | + return d; |
3072 | +} |
3073 | + |
3074 | + |
3075 | +QDateTime DirModel::curPathModifiedDate() const |
3076 | +{ |
3077 | + QDateTime d; |
3078 | + QFileInfo f(mCurrentDir); |
3079 | + if (f.exists()) |
3080 | + { |
3081 | + d = f.lastModified(); |
3082 | + } |
3083 | + return d; |
3084 | +} |
3085 | + |
3086 | + |
3087 | +QDateTime DirModel::curPathAccessedDate() const |
3088 | +{ |
3089 | + QDateTime d; |
3090 | + QFileInfo f(mCurrentDir); |
3091 | + if (f.exists()) |
3092 | + { |
3093 | + d = f.lastRead(); |
3094 | + } |
3095 | + return d; |
3096 | +} |
3097 | + |
3098 | + |
3099 | +bool DirModel::curPathIsWritable() const |
3100 | +{ |
3101 | + QFileInfo f(mCurrentDir); |
3102 | + return f.exists() && f.isWritable(); |
3103 | +} |
3104 | + |
3105 | +QString DirModel::curPathCreatedDateLocaleShort() const |
3106 | +{ |
3107 | + QString date; |
3108 | + QDateTime d(curPathCreatedDate()); |
3109 | + if (!d.isNull()) |
3110 | + { |
3111 | + date = d.toString(Qt::SystemLocaleShortDate); |
3112 | + } |
3113 | + return date; |
3114 | +} |
3115 | + |
3116 | + |
3117 | +QString DirModel::curPathModifiedDateLocaleShort() const |
3118 | +{ |
3119 | + QString date; |
3120 | + QDateTime d(curPathModifiedDate()); |
3121 | + if (!d.isNull()) |
3122 | + { |
3123 | + date = d.toString(Qt::SystemLocaleShortDate); |
3124 | + } |
3125 | + return date; |
3126 | +} |
3127 | + |
3128 | + |
3129 | +QString DirModel::curPathAccessedDateLocaleShort() const |
3130 | +{ |
3131 | + QString date; |
3132 | + QDateTime d(curPathAccessedDate()); |
3133 | + if (!d.isNull()) |
3134 | + { |
3135 | + date = d.toString(Qt::SystemLocaleShortDate); |
3136 | + } |
3137 | + return date; |
3138 | +} |
3139 | + |
3140 | + |
3141 | +QFileInfo DirModel::setParentIfRelative(const QString &fileOrDir) const |
3142 | +{ |
3143 | + QFileInfo myFi(fileOrDir); |
3144 | + if (myFi.isRelative()) |
3145 | + { |
3146 | + myFi.setFile(mCurrentDir, fileOrDir); |
3147 | + QFileInfo abs(myFi.absoluteFilePath()); |
3148 | + myFi = abs; |
3149 | + } |
3150 | + return myFi; |
3151 | +} |
3152 | + |
3153 | + |
3154 | +int DirModel::getProgressCounter() const |
3155 | +{ |
3156 | + return m_fsAction->getProgressCounter(); |
3157 | +} |
3158 | + |
3159 | + |
3160 | +void DirModel::clear() |
3161 | +{ |
3162 | + beginResetModel(); |
3163 | + mDirectoryContents.clear(); |
3164 | + mSelection->clear(); |
3165 | + endResetModel(); |
3166 | +} |
3167 | + |
3168 | + |
3169 | +DirSelection * DirModel::selectionObject() const |
3170 | +{ |
3171 | + return mSelection; |
3172 | +} |
3173 | + |
3174 | + |
3175 | +void DirModel::registerMetaTypes() |
3176 | +{ |
3177 | + qRegisterMetaType<DirItemInfoList>("DirItemInfoList"); |
3178 | + qRegisterMetaType<DirItemInfo>("DirItemInfo"); |
3179 | +} |
3180 | + |
3181 | +void DirModel::notifyItemChanged(int row) |
3182 | +{ |
3183 | + QModelIndex first = index(row,0); |
3184 | +#if REGRESSION_TEST_FOLDERLISTMODEL |
3185 | + QModelIndex last = index(row, columnCount()); //Table only when testing |
3186 | +#else |
3187 | + QModelIndex last = first; //QML uses Listview, just one column |
3188 | +#endif |
3189 | + emit dataChanged(first, last); |
3190 | +} |
3191 | + |
3192 | + |
3193 | +int DirModel::getIndex(const QString &name) |
3194 | +{ |
3195 | + QFileInfo i(name); |
3196 | + return rowOfItem(DirItemInfo(i)); |
3197 | +} |
3198 | + |
3199 | + |
3200 | +#ifndef DO_NOT_USE_TAG_LIB |
3201 | +QVariant DirModel::getAudioMetaData(const QFileInfo& fi, int role) const |
3202 | +{ |
3203 | + QVariant empty; |
3204 | + if (!fi.isDir()) { |
3205 | + TagLib::FileRef f(fi.absoluteFilePath().toStdString().c_str(), true, TagLib::AudioProperties::Fast); |
3206 | + TagLib::MPEG::File mp3(fi.absoluteFilePath().toStdString().c_str(), true, TagLib::MPEG::Properties::Fast); |
3207 | + TagLib::Tag *tag = f.tag(); |
3208 | + if (tag) |
3209 | + { |
3210 | + TagLib::ID3v2::FrameList list = mp3.ID3v2Tag()->frameListMap()["APIC"]; |
3211 | + switch (role) { |
3212 | + case TrackTitleRole: |
3213 | + return QString::fromUtf8(tag->title().toCString(true)); |
3214 | + case TrackArtistRole: |
3215 | + return QString::fromUtf8(tag->artist().toCString(true)); |
3216 | + case TrackAlbumRole: |
3217 | + return QString::fromUtf8(tag->album().toCString(true)); |
3218 | + case TrackYearRole: |
3219 | + return QString::number(tag->year()); |
3220 | + case TrackNumberRole: |
3221 | + return QString::number(tag->track()); |
3222 | + case TrackGenreRole: |
3223 | + return QString::fromUtf8(tag->genre().toCString(true)); |
3224 | + case TrackLengthRole: |
3225 | + if(!f.isNull() && f.audioProperties()) { |
3226 | + return QString::number(f.audioProperties()->length()); |
3227 | + } else { |
3228 | + return QString::number(0); |
3229 | + } |
3230 | + case TrackCoverRole: |
3231 | + if(!list.isEmpty()) { |
3232 | + TagLib::ID3v2::AttachedPictureFrame *Pic = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(list.front()); |
3233 | + QImage img; |
3234 | + img.loadFromData((const uchar *) Pic->picture().data(), Pic->picture().size()); |
3235 | + return img; |
3236 | + } |
3237 | + default: |
3238 | + break; |
3239 | + } //switch |
3240 | + }//if (tag) |
3241 | + } |
3242 | + return empty; |
3243 | +} |
3244 | +#endif |
3245 | |
3246 | === added file 'src/plugin/folderlistmodel/dirmodel.h' |
3247 | --- src/plugin/folderlistmodel/dirmodel.h 1970-01-01 00:00:00 +0000 |
3248 | +++ src/plugin/folderlistmodel/dirmodel.h 2014-04-15 08:19:22 +0000 |
3249 | @@ -0,0 +1,430 @@ |
3250 | +/* |
3251 | + * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net> |
3252 | + * |
3253 | + * You may use this file under the terms of the BSD license as follows: |
3254 | + * |
3255 | + * "Redistribution and use in source and binary forms, with or without |
3256 | + * modification, are permitted provided that the following conditions are |
3257 | + * met: |
3258 | + * * Redistributions of source code must retain the above copyright |
3259 | + * notice, this list of conditions and the following disclaimer. |
3260 | + * * Redistributions in binary form must reproduce the above copyright |
3261 | + * notice, this list of conditions and the following disclaimer in |
3262 | + * the documentation and/or other materials provided with the |
3263 | + * distribution. |
3264 | + * * Neither the name of Nemo Mobile nor the names of its contributors |
3265 | + * may be used to endorse or promote products derived from this |
3266 | + * software without specific prior written permission. |
3267 | + * |
3268 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
3269 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
3270 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
3271 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
3272 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
3273 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
3274 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
3275 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
3276 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
3277 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
3278 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
3279 | + */ |
3280 | + |
3281 | +#ifndef DIRMODEL_H |
3282 | +#define DIRMODEL_H |
3283 | + |
3284 | + |
3285 | +#include <QStringList> |
3286 | +#include <QDir> |
3287 | + |
3288 | +#include "iorequest.h" |
3289 | +#include "filecompare.h" |
3290 | +#include "diritemabstractlistmodel.h" |
3291 | +#include "diriteminfo.h" |
3292 | + |
3293 | +class FileSystemAction; |
3294 | +class ExternalFSWatcher; |
3295 | +class Clipboard; |
3296 | +class DirSelection; |
3297 | + |
3298 | +/*! |
3299 | + * When the External File System Wathcer is enabled, |
3300 | + * this is the interval used to check if there has been any change in the current path |
3301 | + * |
3302 | + * \sa setEnabledExternalFSWatcher() |
3303 | + */ |
3304 | +#define EX_FS_WATCHER_TIMER_INTERVAL 900 |
3305 | + |
3306 | +class DirModel : public DirItemAbstractListModel |
3307 | +{ |
3308 | + Q_OBJECT |
3309 | +public: |
3310 | + enum Roles { |
3311 | + FileNameRole = Qt::UserRole, |
3312 | + AccessedDateRole, |
3313 | + CreationDateRole, |
3314 | + ModifiedDateRole, |
3315 | + FileSizeRole, |
3316 | + IconSourceRole, |
3317 | + FilePathRole, |
3318 | + IsDirRole, |
3319 | + IsFileRole, |
3320 | + IsReadableRole, |
3321 | + IsWritableRole, |
3322 | + IsExecutableRole, |
3323 | + IsSelectedRole, |
3324 | + TrackTitleRole, |
3325 | + TrackArtistRole, |
3326 | + TrackAlbumRole, |
3327 | + TrackYearRole, |
3328 | + TrackNumberRole, |
3329 | + TrackGenreRole, |
3330 | + TrackLengthRole, |
3331 | + TrackCoverRole |
3332 | + }; |
3333 | + |
3334 | +public: |
3335 | + explicit DirModel(QObject *parent = 0); |
3336 | + ~DirModel(); |
3337 | + |
3338 | + static void registerMetaTypes(); |
3339 | + |
3340 | + //DirItemAbstractListModel |
3341 | + virtual int getIndex(const QString& name); |
3342 | + virtual void notifyItemChanged(int row); |
3343 | + |
3344 | + int rowCount(const QModelIndex &index = QModelIndex()) const |
3345 | + { |
3346 | + if (index.parent() != QModelIndex()) |
3347 | + return 0; |
3348 | + return mDirectoryContents.count(); |
3349 | + } |
3350 | + |
3351 | + // TODO: this won't be safe if the model can change under the holder of the row |
3352 | + Q_INVOKABLE QVariant data(int row, const QByteArray &stringRole) const; |
3353 | + |
3354 | + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; |
3355 | + |
3356 | + Q_INVOKABLE void refresh() |
3357 | + { |
3358 | + // just some syntactical sugar really |
3359 | + setPath(path()); |
3360 | + } |
3361 | + |
3362 | + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) |
3363 | + inline QString path() const { return mCurrentDir; } |
3364 | + void setPath(const QString &pathName); |
3365 | + |
3366 | + Q_INVOKABLE QDateTime curPathAccessedDate() const; |
3367 | + Q_INVOKABLE QDateTime curPathCreatedDate() const; |
3368 | + Q_INVOKABLE QDateTime curPathModifiedDate() const; |
3369 | + Q_INVOKABLE QString curPathAccessedDateLocaleShort() const; |
3370 | + Q_INVOKABLE QString curPathCreatedDateLocaleShort() const; |
3371 | + Q_INVOKABLE QString curPathModifiedDateLocaleShort() const; |
3372 | + Q_INVOKABLE bool curPathIsWritable() const; |
3373 | + |
3374 | + Q_PROPERTY(bool awaitingResults READ awaitingResults NOTIFY awaitingResultsChanged) |
3375 | + bool awaitingResults() const; |
3376 | + |
3377 | + Q_INVOKABLE void rm(const QStringList &paths); |
3378 | + |
3379 | + Q_INVOKABLE bool rename(const QString& oldName, const QString& newName); |
3380 | + Q_INVOKABLE bool rename(int row, const QString &newName); |
3381 | + |
3382 | + Q_INVOKABLE void mkdir(const QString &newdir); |
3383 | + |
3384 | + Q_PROPERTY(bool filterDirectories READ filterDirectories WRITE setFilterDirectories NOTIFY filterDirectoriesChanged) |
3385 | + bool filterDirectories() const; |
3386 | + |
3387 | + Q_PROPERTY(bool isRecursive READ isRecursive WRITE setIsRecursive NOTIFY isRecursiveChanged) |
3388 | + bool isRecursive() const; |
3389 | + |
3390 | + Q_PROPERTY(bool readsMediaMetadata READ readsMediaMetadata WRITE setReadsMediaMetadata NOTIFY readsMediaMetadataChanged) |
3391 | + bool readsMediaMetadata() const; |
3392 | + |
3393 | + Q_PROPERTY(bool showDirectories READ showDirectories WRITE setShowDirectories NOTIFY showDirectoriesChanged) |
3394 | + bool showDirectories() const; |
3395 | + |
3396 | + Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged) |
3397 | + QStringList nameFilters() const; |
3398 | + void setNameFilters(const QStringList &nameFilters); |
3399 | + |
3400 | +public slots: |
3401 | + void onItemsAdded(const DirItemInfoList &newFiles); |
3402 | + void onResultsFetched(); |
3403 | + |
3404 | +signals: |
3405 | + void awaitingResultsChanged(); |
3406 | + void nameFiltersChanged(); |
3407 | + void filterDirectoriesChanged(); |
3408 | + void isRecursiveChanged(); |
3409 | + void readsMediaMetadataChanged(); |
3410 | + void showDirectoriesChanged(); |
3411 | + void pathChanged(const QString& newPath); |
3412 | + void error(const QString &errorTitle, const QString &errorMessage); |
3413 | + |
3414 | +private: |
3415 | + QHash<int, QByteArray> buildRoleNames() const; |
3416 | + QHash<int, QByteArray> roleNames() const; |
3417 | + QStringList mNameFilters; |
3418 | + bool mFilterDirectories; |
3419 | + bool mShowDirectories; |
3420 | + bool mAwaitingResults; |
3421 | + bool mIsRecursive; |
3422 | + bool mReadsMediaMetadata; |
3423 | + QString mCurrentDir; |
3424 | + DirItemInfoList mDirectoryContents; |
3425 | + |
3426 | +public: |
3427 | + |
3428 | + Q_INVOKABLE DirSelection * selectionObject() const ; |
3429 | + |
3430 | + //[0] new stuff Ubuntu File Manager |
3431 | + Q_PROPERTY(QString parentPath READ parentPath NOTIFY pathChanged) |
3432 | + QString parentPath() const; |
3433 | + |
3434 | + Q_PROPERTY(bool showHiddenFiles READ getShowHiddenFiles WRITE setShowHiddenFiles NOTIFY showHiddenFilesChanged) |
3435 | + bool getShowHiddenFiles() const; |
3436 | + |
3437 | + Q_ENUMS(SortBy) |
3438 | + enum SortBy |
3439 | + { |
3440 | + SortByName, |
3441 | + SortByDate |
3442 | + }; |
3443 | + Q_PROPERTY(SortBy sortBy READ getSortBy WRITE setSortBy NOTIFY sortByChanged) |
3444 | + SortBy getSortBy() const; |
3445 | + |
3446 | + Q_ENUMS(SortOrder) |
3447 | + enum SortOrder |
3448 | + { |
3449 | + SortAscending = Qt::AscendingOrder, |
3450 | + SortDescending = Qt::DescendingOrder |
3451 | + }; |
3452 | + Q_PROPERTY(SortOrder sortOrder READ getSortOrder WRITE setSortOrder NOTIFY sortOrderChanged) |
3453 | + SortOrder getSortOrder() const; |
3454 | + |
3455 | + Q_PROPERTY(int clipboardUrlsCounter READ getClipboardUrlsCounter NOTIFY clipboardChanged) |
3456 | + int getClipboardUrlsCounter() const; |
3457 | + |
3458 | + Q_PROPERTY(bool enableExternalFSWatcher READ getEnabledExternalFSWatcher WRITE setEnabledExternalFSWatcher) |
3459 | + bool getEnabledExternalFSWatcher() const; |
3460 | + |
3461 | + Q_INVOKABLE QString homePath() const; |
3462 | + |
3463 | + /*! |
3464 | + * \brief Tries to make the directory pointed by row as the current to be browsed |
3465 | + * \return true if row points to a directory and the directory is readble, false otherwise |
3466 | + */ |
3467 | + Q_INVOKABLE bool cdIntoIndex(int row); |
3468 | + Q_INVOKABLE bool cdIntoPath(const QString& filename); |
3469 | + |
3470 | + /*! |
3471 | + * \brief copyIndex() puts the item pointed by \a row (dir or file) into the clipboard |
3472 | + * \param row points to the item file or directory |
3473 | + */ |
3474 | + Q_INVOKABLE void copyIndex(int row); |
3475 | + |
3476 | + /*! |
3477 | + * \brief copyPaths(const QStringList& urls) several items (dirs or files) into the clipboard |
3478 | + * \param items fullpathnames or names only |
3479 | + */ |
3480 | + Q_INVOKABLE void copyPaths(const QStringList& items); |
3481 | + |
3482 | + /*! |
3483 | + * \brief cutIndex() puts the item into the clipboard as \ref copy(), |
3484 | + * mark the item to be removed after \ref paste() |
3485 | + * \param row points to the item file or directory |
3486 | + */ |
3487 | + Q_INVOKABLE void cutIndex(int row); |
3488 | + |
3489 | + /*! |
3490 | + * \brief cut() puts several items (dirs or files) into the clipboard as \ref copy(), |
3491 | + * mark the item to be removed after \ref paste() |
3492 | + * \param items fullpathnames or names only |
3493 | + */ |
3494 | + Q_INVOKABLE void cutPaths(const QStringList& items); |
3495 | + |
3496 | + /*! |
3497 | + * \brief removeIndex(); remove a item file or directory |
3498 | + * |
3499 | + * I gets the item indicated by \row and calls \ref rm() |
3500 | + * |
3501 | + * \param row points to the item to b e removed |
3502 | + * \return true if it was possible to remove the item |
3503 | + */ |
3504 | + Q_INVOKABLE void removeIndex(int row); |
3505 | + |
3506 | + /*! |
3507 | + * Just calls \ref rm() |
3508 | + */ |
3509 | + Q_INVOKABLE void removePaths(const QStringList& items); |
3510 | + |
3511 | + /*! |
3512 | + * Tries to open a file using a suitable application, if the index points to a directory |
3513 | + * it goes into it using \ref cdIntoIndex() or \ref cdIntoPath() |
3514 | + * |
3515 | + * \note Qt uses Qt QDesktopServices::openUrl() |
3516 | + */ |
3517 | + Q_INVOKABLE bool openIndex(int row); |
3518 | + |
3519 | + /*! |
3520 | + * Same as \ref openIndex() but using a file name instead of index |
3521 | + * |
3522 | + * It allows to open directories and files using absoulte paths |
3523 | + * |
3524 | + * \sa \ref cdIntoPath() |
3525 | + */ |
3526 | + Q_INVOKABLE bool openPath(const QString& filename); |
3527 | + |
3528 | + /*! |
3529 | + * \brief getProgressCounter() returns the number of \ref progress() notifications an Action will perform |
3530 | + * |
3531 | + * It may be useful to decide about showing or not a progress dialog for Remove/Copy/Cut/Paste Actions |
3532 | + * |
3533 | + * This function can be called just after receiving first \ref progress() notification |
3534 | + * |
3535 | + * \note In the future this \ref getProgressCounter() and \ref progress() will merge to single signal that |
3536 | + * will send the Action full information, it will allow to have multi thread Actions. |
3537 | + * Also \ref cancelAction() needs to change |
3538 | + */ |
3539 | + Q_INVOKABLE int getProgressCounter() const; |
3540 | + |
3541 | + // some helper functions that can be useful to other QML applications than File Manager |
3542 | + Q_INVOKABLE bool existsDir(const QString& folderName) const; |
3543 | + Q_INVOKABLE bool canReadDir(const QString& folderName) const; |
3544 | + Q_INVOKABLE bool existsFile(const QString& fileName) const; |
3545 | + Q_INVOKABLE bool canReadFile(const QString& fileName) const; |
3546 | + |
3547 | +public slots: |
3548 | + /*! |
3549 | + * \brief goHome() goes to user home dir |
3550 | + * Go to user home dir, we may have a tab for places or something like that |
3551 | + */ |
3552 | + void goHome(); |
3553 | + |
3554 | + /*! |
3555 | + * \brief cdUp() sets the parent directory as current directory |
3556 | + * |
3557 | + * It can work as a back function if there is no user input path |
3558 | + * \return true if it was possible to change to parent dir, otherwise false |
3559 | + */ |
3560 | + bool cdUp(); |
3561 | + |
3562 | + /*! |
3563 | + * \brief paste() copy item(s) from \ref copy() and \ref paste() into the current directory |
3564 | + * |
3565 | + * If the operation was \ref cut(), then remove the original item |
3566 | + */ |
3567 | + void paste(); |
3568 | + |
3569 | + /*! |
3570 | + * \brief cancelAction() any copy/cut/remove can be cancelled |
3571 | + */ |
3572 | + void cancelAction(); |
3573 | + |
3574 | + void setIsRecursive(bool isRecursive); |
3575 | + void setReadsMediaMetadata(bool readsMediaMetadata); |
3576 | + void setFilterDirectories(bool filterDirectories); |
3577 | + void setShowDirectories(bool showDirectories); |
3578 | + void setShowHiddenFiles(bool show); |
3579 | + void setSortBy(SortBy field); |
3580 | + void setSortOrder(SortOrder order); |
3581 | + void setEnabledExternalFSWatcher(bool enable); |
3582 | + |
3583 | + |
3584 | + void toggleShowDirectories(); |
3585 | + void toggleShowHiddenFiles(); |
3586 | + void toggleSortOrder(); |
3587 | + void toggleSortBy(); |
3588 | + |
3589 | +signals: |
3590 | + /*! |
3591 | + * \brief insertedItem() |
3592 | + * |
3593 | + * It happens when a new file is inserted in an existent view, |
3594 | + * for example from \ref mkdir() or \ref paste() |
3595 | + * |
3596 | + * It can be used to make the new row visible to the user doing a scroll to |
3597 | + */ |
3598 | + void insertedRow(int row); |
3599 | + /*! |
3600 | + * \brief progress() |
3601 | + * Sends status about recursive and multi-items remove/move/copy |
3602 | + * |
3603 | + * \param curItem current item being handled |
3604 | + * \param totalItems total of items including recursive directories content |
3605 | + * \param percent a percent done |
3606 | + */ |
3607 | + void progress(int curItem, int totalItems, int percent); |
3608 | + |
3609 | + void showHiddenFilesChanged(); |
3610 | + void sortByChanged(); |
3611 | + void sortOrderChanged(); |
3612 | + |
3613 | + void clipboardChanged(); |
3614 | + |
3615 | +private slots: |
3616 | + void onItemRemoved(const QString&); |
3617 | + void onItemRemoved(const DirItemInfo&); |
3618 | + void onItemAdded(const QString&); |
3619 | + void onItemAdded(const DirItemInfo&); |
3620 | + void onItemChanged(const DirItemInfo&); |
3621 | + |
3622 | +private: |
3623 | + int addItem(const DirItemInfo& fi); |
3624 | + void setCompareAndReorder(); |
3625 | + int rowOfItem(const DirItemInfo& fi); |
3626 | + QDir::Filter currentDirFilter() const; |
3627 | + QString dirItems(const DirItemInfo& fi) const; |
3628 | + bool cdInto(const DirItemInfo& fi); |
3629 | + bool openItem(const DirItemInfo& fi); |
3630 | + DirListWorker * createWorkerRequest(IORequest::RequestType requestType, |
3631 | + const QString& pathName); |
3632 | + bool canReadDir(const QFileInfo& d) const; |
3633 | + bool canReadFile(const QFileInfo& f) const; |
3634 | + QFileInfo setParentIfRelative(const QString &fileOrDir) const; |
3635 | + |
3636 | +private: |
3637 | + void startExternalFsWatcher(); |
3638 | + void stoptExternalFsWatcher(); |
3639 | + void clear(); |
3640 | +private slots: |
3641 | + void onItemAddedOutsideFm(const DirItemInfo&fi); |
3642 | + void onItemRemovedOutSideFm(const DirItemInfo&); |
3643 | + void onItemChangedOutSideFm(const DirItemInfo&fi); |
3644 | + void onThereAreExternalChanges(); |
3645 | + void onExternalFsWorkerFinished(int); |
3646 | + |
3647 | + |
3648 | +private: |
3649 | + bool mShowHiddenFiles; |
3650 | + SortBy mSortBy; |
3651 | + SortOrder mSortOrder; |
3652 | + CompareFunction mCompareFunction; |
3653 | + ExternalFSWatcher* mExtFSWatcher; |
3654 | + Clipboard * mClipboard; |
3655 | + DirSelection * mSelection; |
3656 | + |
3657 | + |
3658 | +private: |
3659 | + FileSystemAction * m_fsAction; //!< it does file system recursive remove/copy/move |
3660 | + QString fileSize(qint64 size) const; |
3661 | +#ifndef DO_NOT_USE_TAG_LIB |
3662 | + QVariant getAudioMetaData(const QFileInfo& fi, int role) const; |
3663 | +#endif |
3664 | +//[0] |
3665 | + |
3666 | +#if defined(REGRESSION_TEST_FOLDERLISTMODEL) |
3667 | + //make this work with tables |
3668 | + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const |
3669 | + { |
3670 | + Q_UNUSED(parent); |
3671 | + return TrackCoverRole - FileNameRole + 1; |
3672 | + } |
3673 | + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; |
3674 | + friend class TestDirModel; |
3675 | +#endif |
3676 | +}; |
3677 | + |
3678 | + |
3679 | +#endif // DIRMODEL_H |
3680 | |
3681 | === added file 'src/plugin/folderlistmodel/dirselection.cpp' |
3682 | --- src/plugin/folderlistmodel/dirselection.cpp 1970-01-01 00:00:00 +0000 |
3683 | +++ src/plugin/folderlistmodel/dirselection.cpp 2014-04-15 08:19:22 +0000 |
3684 | @@ -0,0 +1,298 @@ |
3685 | +/************************************************************************** |
3686 | + * |
3687 | + * Copyright 2014 Canonical Ltd. |
3688 | + * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com> |
3689 | + * |
3690 | + * This program is free software; you can redistribute it and/or modify |
3691 | + * it under the terms of the GNU Lesser General Public License as published by |
3692 | + * the Free Software Foundation; version 3. |
3693 | + * |
3694 | + * This program is distributed in the hope that it will be useful, |
3695 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3696 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3697 | + * GNU Lesser General Public License for more details. |
3698 | + * |
3699 | + * You should have received a copy of the GNU Lesser General Public License |
3700 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3701 | + * |
3702 | + * File: dirselection.cpp |
3703 | + * Date: 29/01/2014 |
3704 | + */ |
3705 | + |
3706 | +#include "dirselection.h" |
3707 | +#include "diritemabstractlistmodel.h" |
3708 | +#include <QTimer> |
3709 | +#include <QDebug> |
3710 | + |
3711 | + |
3712 | +#define VALID_INDEX(index) (index >= 0 && index < m_model->rowCount()) |
3713 | + |
3714 | +DirSelection::DirSelection(QObject *parent) : QObject(parent) |
3715 | +{ |
3716 | +} |
3717 | + |
3718 | +DirSelection::DirSelection(DirItemAbstractListModel *parent, DirItemInfoList *listItems) : |
3719 | + QObject(parent) |
3720 | + ,m_selectedCounter(0) |
3721 | + ,m_model(parent) |
3722 | + ,m_listItems(listItems) |
3723 | + ,m_mode(Single) |
3724 | + ,m_lastSelectedItem(-1) |
3725 | +{ |
3726 | +} |
3727 | + |
3728 | + |
3729 | + |
3730 | +QStringList DirSelection::selectedAbsFilePaths() const |
3731 | +{ |
3732 | + QStringList ret; |
3733 | + int counter = m_model->rowCount(); |
3734 | + for(int index = 0 ; index < counter; ++index) |
3735 | + { |
3736 | + if (m_listItems->at(index).isSelected()) |
3737 | + { |
3738 | + ret.append(m_listItems->at(index).absoluteFilePath()); |
3739 | + } |
3740 | + } |
3741 | + return ret; |
3742 | +} |
3743 | + |
3744 | +QStringList DirSelection::selectedNames() const |
3745 | +{ |
3746 | + QStringList ret; |
3747 | + int counter = m_model->rowCount(); |
3748 | + for(int index = 0 ; index < counter; ++index) |
3749 | + { |
3750 | + if (m_listItems->at(index).isSelected()) |
3751 | + { |
3752 | + ret.append(m_listItems->at(index).fileName()); |
3753 | + } |
3754 | + } |
3755 | + return ret; |
3756 | +} |
3757 | + |
3758 | + |
3759 | + |
3760 | +QList<int> DirSelection::selectedIndexes() const |
3761 | +{ |
3762 | + QList<int> ret; |
3763 | + int counter = m_model->rowCount(); |
3764 | + for(int index = 0 ; index < counter; ++index) |
3765 | + { |
3766 | + if (m_listItems->at(index).isSelected()) |
3767 | + { |
3768 | + ret.append(index); |
3769 | + } |
3770 | + } |
3771 | + return ret; |
3772 | +} |
3773 | + |
3774 | + |
3775 | +void DirSelection::clear() |
3776 | +{ |
3777 | + if (priv_clear()) |
3778 | + { |
3779 | + notifyChanges(); |
3780 | + } |
3781 | +} |
3782 | + |
3783 | + |
3784 | +bool DirSelection::priv_clear() |
3785 | +{ |
3786 | + bool notify = m_selectedCounter != 0; |
3787 | + if (notify) |
3788 | + { |
3789 | + int counter = m_model->rowCount(); |
3790 | + DirItemInfo *data = m_listItems->data(); |
3791 | + while (m_selectedCounter > 0 && counter-- ) |
3792 | + { |
3793 | + if ( data[counter].setSelection(false) ) |
3794 | + { |
3795 | + --m_selectedCounter; |
3796 | + m_model->notifyItemChanged(counter); |
3797 | + } |
3798 | + } |
3799 | + } |
3800 | + //force it to zero, works when cleaning the buffer first |
3801 | + m_selectedCounter = 0; |
3802 | + m_lastSelectedItem = -1; |
3803 | + return notify; |
3804 | +} |
3805 | + |
3806 | + |
3807 | +void DirSelection::selectAll() |
3808 | +{ |
3809 | + int counter = m_model->rowCount(); |
3810 | + bool notify = m_selectedCounter != counter; |
3811 | + if (notify) |
3812 | + { |
3813 | + DirItemInfo *data = m_listItems->data(); |
3814 | + while ( counter-- ) |
3815 | + { |
3816 | + if ( data[counter].setSelection(true) ) |
3817 | + { |
3818 | + ++m_selectedCounter; |
3819 | + m_model->notifyItemChanged(counter); |
3820 | + } |
3821 | + } |
3822 | + notifyChanges(); |
3823 | + } |
3824 | +} |
3825 | + |
3826 | + |
3827 | +int DirSelection::counter() const |
3828 | +{ |
3829 | + return m_selectedCounter; |
3830 | +} |
3831 | + |
3832 | + |
3833 | +DirSelection::Mode DirSelection::mode() const |
3834 | +{ |
3835 | + return m_mode; |
3836 | +} |
3837 | + |
3838 | + |
3839 | +void DirSelection::itemGoingToBeRemoved(const DirItemInfo &item) |
3840 | +{ |
3841 | + if (m_selectedCounter > 0 && item.isSelected()) |
3842 | + { |
3843 | + --m_selectedCounter; |
3844 | + notifyChanges(); |
3845 | + } |
3846 | + // item is going to be removed, no QAbstractItemModel::dataChanged() signal is necessary to refresh views |
3847 | +} |
3848 | + |
3849 | + |
3850 | +void DirSelection::setIndex(int index, bool selected) |
3851 | +{ |
3852 | + if (VALID_INDEX(index)) |
3853 | + { |
3854 | + int old_selectedCounter = m_selectedCounter; |
3855 | + if (selected && m_mode == Single && m_selectedCounter > 0) |
3856 | + { |
3857 | + priv_clear(); |
3858 | + } |
3859 | + if ( priv_setIndex(index, selected) |
3860 | + || old_selectedCounter != m_selectedCounter |
3861 | + ) |
3862 | + { |
3863 | + notifyChanges(); |
3864 | + } |
3865 | + } |
3866 | +} |
3867 | + |
3868 | + |
3869 | +void DirSelection::toggleIndex(int index) |
3870 | +{ |
3871 | + if (VALID_INDEX(index)) |
3872 | + { |
3873 | + setIndex(index, !m_listItems->at(index).isSelected()); |
3874 | + } |
3875 | +} |
3876 | + |
3877 | + |
3878 | +void DirSelection::setMode(Mode m) |
3879 | +{ |
3880 | + if (m != m_mode) |
3881 | + { |
3882 | + m_mode = m; |
3883 | + emit modeChanged(m_mode); |
3884 | + } |
3885 | +} |
3886 | + |
3887 | + |
3888 | +void DirSelection::notifyChanges() |
3889 | +{ |
3890 | + emit selectionChanged(m_selectedCounter); |
3891 | +} |
3892 | + |
3893 | + |
3894 | +/*! |
3895 | + * \brief DirSelection::itemGoingToBeReplaced() it is supposed to control selection writable and readabble states |
3896 | + * |
3897 | + * So far it does nothing |
3898 | + * |
3899 | + * \param oldItemInfo |
3900 | + * \param newItemInfo |
3901 | + */ |
3902 | +void DirSelection::itemGoingToBeReplaced(const DirItemInfo &oldItemInfo, |
3903 | + const DirItemInfo &newItemInfo) |
3904 | +{ |
3905 | + if (oldItemInfo.isSelected()) |
3906 | + { |
3907 | + // we may add selection writable state in the future |
3908 | + Q_UNUSED(newItemInfo); |
3909 | + } |
3910 | +} |
3911 | + |
3912 | + |
3913 | +void DirSelection::selectRange(int indexClicked) |
3914 | +{ |
3915 | + bool changed = false; |
3916 | + if ( VALID_INDEX(indexClicked) |
3917 | + && m_selectedCounter > 0 |
3918 | + && indexClicked != m_lastSelectedItem |
3919 | + && VALID_INDEX(m_lastSelectedItem) |
3920 | + && !m_listItems->at(indexClicked).isSelected() |
3921 | + ) |
3922 | + { |
3923 | + //go from indexClicked to m_lastSelectedItem |
3924 | + int increment = indexClicked > m_lastSelectedItem? -1 : 1; |
3925 | + int nextItem = indexClicked; |
3926 | + int saved_lastSelectedItem = m_lastSelectedItem; |
3927 | + while (priv_setIndex(nextItem, true) && nextItem != saved_lastSelectedItem) |
3928 | + { |
3929 | + nextItem += increment; |
3930 | + changed = true; |
3931 | + } |
3932 | + } |
3933 | + if (changed) |
3934 | + { |
3935 | + notifyChanges(); |
3936 | + } |
3937 | +} |
3938 | + |
3939 | + |
3940 | +bool DirSelection::priv_setIndex(int index, bool selected) |
3941 | +{ |
3942 | + DirItemInfo *data = m_listItems->data(); |
3943 | + bool changed = false; |
3944 | + if ((changed = data[index].setSelection(selected))) |
3945 | + { |
3946 | + m_model->notifyItemChanged(index); |
3947 | + if (selected) |
3948 | + { |
3949 | + ++m_selectedCounter; |
3950 | + m_lastSelectedItem = index; |
3951 | + } |
3952 | + else |
3953 | + { |
3954 | + --m_selectedCounter; |
3955 | + } |
3956 | + } |
3957 | + return changed; |
3958 | +} |
3959 | + |
3960 | + |
3961 | +void DirSelection::select(int index, bool range, bool multiSelection ) |
3962 | +{ |
3963 | + if (range && VALID_INDEX(m_lastSelectedItem)) |
3964 | + { |
3965 | + selectRange(index); |
3966 | + } |
3967 | + else |
3968 | + { |
3969 | + if (multiSelection || m_mode == Multi) |
3970 | + { |
3971 | + Mode saveMode = m_mode; |
3972 | + //set Multi selection do not call clear() |
3973 | + m_mode = Multi; |
3974 | + toggleIndex(index); |
3975 | + m_mode = saveMode; |
3976 | + } |
3977 | + else |
3978 | + { |
3979 | + setIndex(index, true); |
3980 | + } |
3981 | + } |
3982 | +} |
3983 | |
3984 | === added file 'src/plugin/folderlistmodel/dirselection.h' |
3985 | --- src/plugin/folderlistmodel/dirselection.h 1970-01-01 00:00:00 +0000 |
3986 | +++ src/plugin/folderlistmodel/dirselection.h 2014-04-15 08:19:22 +0000 |
3987 | @@ -0,0 +1,116 @@ |
3988 | +/************************************************************************** |
3989 | + * |
3990 | + * Copyright 2014 Canonical Ltd. |
3991 | + * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com> |
3992 | + * |
3993 | + * This program is free software; you can redistribute it and/or modify |
3994 | + * it under the terms of the GNU Lesser General Public License as published by |
3995 | + * the Free Software Foundation; version 3. |
3996 | + * |
3997 | + * This program is distributed in the hope that it will be useful, |
3998 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3999 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4000 | + * GNU Lesser General Public License for more details. |
4001 | + * |
4002 | + * You should have received a copy of the GNU Lesser General Public License |
4003 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4004 | + * |
4005 | + * File: dirselection.h |
4006 | + * Date: 29/01/2014 |
4007 | + */ |
4008 | + |
4009 | +#ifndef DIRSELECTION_H |
4010 | +#define DIRSELECTION_H |
4011 | + |
4012 | +#include "diriteminfo.h" |
4013 | + |
4014 | +#include <QObject> |
4015 | +#include <QStringList> |
4016 | + |
4017 | + |
4018 | +class DirItemAbstractListModel; |
4019 | + |
4020 | +class DirSelection : public QObject |
4021 | +{ |
4022 | + Q_OBJECT |
4023 | +public: |
4024 | + explicit DirSelection(DirItemAbstractListModel *parent, DirItemInfoList *listItems); |
4025 | + explicit DirSelection(QObject *parent = 0); |
4026 | +public slots: |
4027 | + void selectRange(int indexClicked); |
4028 | + void selectAll(); |
4029 | + void clear(); |
4030 | + void toggleIndex(int index); |
4031 | + void setIndex(int index, bool selected); |
4032 | + |
4033 | +public: |
4034 | + Q_ENUMS(Mode) |
4035 | + enum Mode |
4036 | + { |
4037 | + Single, |
4038 | + Multi |
4039 | + }; |
4040 | + Q_PROPERTY(int counter READ counter NOTIFY selectionChanged) |
4041 | + Q_PROPERTY(Mode mode READ mode WRITE setMode NOTIFY modeChanged) |
4042 | + Q_INVOKABLE QStringList selectedNames() const; |
4043 | + Q_INVOKABLE void setMode(Mode m); |
4044 | + Q_INVOKABLE QStringList selectedAbsFilePaths() const; //full path |
4045 | + Q_INVOKABLE QList<int> selectedIndexes() const; |
4046 | + int counter() const; |
4047 | + Mode mode() const; |
4048 | + |
4049 | +public: |
4050 | + /*! |
4051 | + * It allows to pass Control Modifiers directly to perform the most common selection behaviour. |
4052 | + * |
4053 | + * Usage Example: |
4054 | + * \li 1 When selecting an item with Shit key pressed it selects the rage calling \ref selectRange() |
4055 | + * \li 2 When selecting an item with Crtl key pressed it temporarily forces Multi Selection Mode |
4056 | + * calling \ref toggleIndex() instead of \ref setIndex(); |
4057 | + * |
4058 | + * \param range when true it calls \ref selectRange() and does not consider the \a multiSelection parameter |
4059 | + * |
4060 | + * \param multiSelection when \a false it respects the current selection mode: calls \ref setIndex() |
4061 | + * for \ref Single selection mode or \ref toggleIndex() for \ref Multi selection mode. |
4062 | + * When \a true it calls \ref toggleIndex() |
4063 | + * |
4064 | + * QML example: |
4065 | + * \code |
4066 | + * property FolderListSelection selectionManager: pageModel.selectionObject() |
4067 | + * ... |
4068 | + * |
4069 | + * MouseArea { |
4070 | + * anchors.fill: parent |
4071 | + * onClicked: { |
4072 | + * selectionManager.select(model.index, |
4073 | + * (mouse.modifiers & Qt.ShiftModifier), |
4074 | + * (mouse.modifiers & Qt.ControlModifier) ); |
4075 | + * } |
4076 | + * } |
4077 | + * \endcode |
4078 | + * |
4079 | + */ |
4080 | + Q_INVOKABLE void select(int index, bool range, bool multiSelection ); |
4081 | + |
4082 | +public: |
4083 | + void itemGoingToBeRemoved(const DirItemInfo& item); |
4084 | + void itemGoingToBeReplaced(const DirItemInfo& oldItemInfo, const DirItemInfo& newItemInfo); |
4085 | + |
4086 | +private: |
4087 | + bool priv_clear(); |
4088 | + void notifyChanges(); |
4089 | + bool priv_setIndex(int index, bool selected); |
4090 | + |
4091 | +signals: |
4092 | + void selectionChanged(int); |
4093 | + void modeChanged(int); |
4094 | + |
4095 | +private: |
4096 | + int m_selectedCounter; |
4097 | + DirItemAbstractListModel* m_model; |
4098 | + DirItemInfoList * m_listItems; |
4099 | + Mode m_mode; |
4100 | + int m_lastSelectedItem; |
4101 | +}; |
4102 | + |
4103 | +#endif // DIRSELECTION_H |
4104 | |
4105 | === added file 'src/plugin/folderlistmodel/externalfswatcher.cpp' |
4106 | --- src/plugin/folderlistmodel/externalfswatcher.cpp 1970-01-01 00:00:00 +0000 |
4107 | +++ src/plugin/folderlistmodel/externalfswatcher.cpp 2014-04-15 08:19:22 +0000 |
4108 | @@ -0,0 +1,114 @@ |
4109 | +/************************************************************************** |
4110 | + * |
4111 | + * Copyright 2013 Canonical Ltd. |
4112 | + * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com> |
4113 | + * |
4114 | + * This program is free software; you can redistribute it and/or modify |
4115 | + * it under the terms of the GNU Lesser General Public License as published by |
4116 | + * the Free Software Foundation; version 3. |
4117 | + * |
4118 | + * This program is distributed in the hope that it will be useful, |
4119 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4120 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4121 | + * GNU Lesser General Public License for more details. |
4122 | + * |
4123 | + * You should have received a copy of the GNU Lesser General Public License |
4124 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4125 | + * |
4126 | + * File: externalfswatcher.cpp |
4127 | + * Date: 9/14/2013 |
4128 | + */ |
4129 | + |
4130 | +#include "externalfswatcher.h" |
4131 | + |
4132 | +#include <QTimer> |
4133 | +#include <QDateTime> |
4134 | +#include <QDebug> |
4135 | + |
4136 | +#if DEBUG_EXT_FS_WATCHER |
4137 | +# define DEBUG_FSWATCHER() \ |
4138 | + qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") \ |
4139 | + << Q_FUNC_INFO << "m_setPath:" << m_setPath \ |
4140 | + << "m_changedPath:" << m_changedPath \ |
4141 | + << "m_waitingEmit:" << m_waitingEmitCounter |
4142 | +#else |
4143 | +# define DEBUG_FSWATCHER() /**/ |
4144 | +#endif // |
4145 | + |
4146 | + |
4147 | +ExternalFSWatcher::ExternalFSWatcher(QObject *parent) : |
4148 | + QFileSystemWatcher(parent) |
4149 | + , m_waitingEmitCounter(0) |
4150 | + , m_msWaitTime(DEFAULT_NOTICATION_PERIOD) |
4151 | +{ |
4152 | + connect(this, SIGNAL(directoryChanged(QString)), |
4153 | + this, SLOT(slotDirChanged(QString))); |
4154 | +} |
4155 | + |
4156 | + |
4157 | +void ExternalFSWatcher::setCurrentPath(const QString &curPath) |
4158 | +{ |
4159 | + if (!curPath.isEmpty()) |
4160 | + { |
4161 | + if (m_setPath != curPath) |
4162 | + { |
4163 | + if (!m_setPath.isEmpty()) |
4164 | + { |
4165 | + removePath(m_setPath); |
4166 | + } |
4167 | + m_setPath = curPath; |
4168 | + addPath(m_setPath); |
4169 | + } |
4170 | + } |
4171 | + DEBUG_FSWATCHER(); |
4172 | +} |
4173 | + |
4174 | + |
4175 | +void ExternalFSWatcher::slotDirChanged(const QString &dir) |
4176 | +{ |
4177 | + DEBUG_FSWATCHER(); |
4178 | + if ( (m_setPath == dir) |
4179 | + && ( m_waitingEmitCounter == 0 || m_setPath != m_changedPath ) |
4180 | + ) |
4181 | + { |
4182 | + removePath(m_setPath); |
4183 | + ++m_waitingEmitCounter; |
4184 | + m_changedPath = m_setPath; |
4185 | + QTimer::singleShot(m_msWaitTime, this, SLOT(slotFireChanges())); |
4186 | + } |
4187 | +} |
4188 | + |
4189 | + |
4190 | +/*! |
4191 | + * \brief ExternalFSWatcher::slotFireChanges() emits \ref pathModified() only when it is sure |
4192 | + * that the current path was changed. |
4193 | + * |
4194 | + * A change for the current path (the last current) MUST be notified at least once. |
4195 | + */ |
4196 | +void ExternalFSWatcher::slotFireChanges() |
4197 | +{ |
4198 | + if (--m_waitingEmitCounter == 0) |
4199 | + { |
4200 | + addPath(m_setPath); |
4201 | + if (m_setPath == m_changedPath) |
4202 | + { |
4203 | + emit pathModified(); |
4204 | +#if DEBUG_EXT_FS_WATCHER |
4205 | + DEBUG_FSWATCHER() << "emit pathModified()"; |
4206 | +#endif |
4207 | + } |
4208 | + } |
4209 | +} |
4210 | + |
4211 | + |
4212 | + |
4213 | +void ExternalFSWatcher::setIntervalToNotifyChanges(int ms) |
4214 | +{ |
4215 | + m_msWaitTime = ms; |
4216 | +} |
4217 | + |
4218 | + |
4219 | +int ExternalFSWatcher::getIntervalToNotifyChanges() const |
4220 | +{ |
4221 | + return m_msWaitTime; |
4222 | +} |
4223 | |
4224 | === added file 'src/plugin/folderlistmodel/externalfswatcher.h' |
4225 | --- src/plugin/folderlistmodel/externalfswatcher.h 1970-01-01 00:00:00 +0000 |
4226 | +++ src/plugin/folderlistmodel/externalfswatcher.h 2014-04-15 08:19:22 +0000 |
4227 | @@ -0,0 +1,68 @@ |
4228 | +/************************************************************************** |
4229 | + * |
4230 | + * Copyright 2013 Canonical Ltd. |
4231 | + * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com> |
4232 | + * |
4233 | + * This program is free software; you can redistribute it and/or modify |
4234 | + * it under the terms of the GNU Lesser General Public License as published by |
4235 | + * the Free Software Foundation; version 3. |
4236 | + * |
4237 | + * This program is distributed in the hope that it will be useful, |
4238 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4239 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4240 | + * GNU Lesser General Public License for more details. |
4241 | + * |
4242 | + * You should have received a copy of the GNU Lesser General Public License |
4243 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4244 | + * |
4245 | + * File: externalfswatcher.h |
4246 | + * Date: 9/14/2013 |
4247 | + */ |
4248 | + |
4249 | +#ifndef EXTERNALFSWATCHER_H |
4250 | +#define EXTERNALFSWATCHER_H |
4251 | + |
4252 | +#include <QFileSystemWatcher> |
4253 | + |
4254 | +#define DEFAULT_NOTICATION_PERIOD 500 |
4255 | + |
4256 | + |
4257 | +/*! |
4258 | + * \brief The ExternalFSWatcher class notifies the owner when the File System when the current path \a m_setPath has changed |
4259 | + * emitting pathModified() signal. |
4260 | + * |
4261 | + * The current path \a m_setPath is set by using the slot \ref setCurrentPath() |
4262 | + * |
4263 | + * The idea of this class is to minimize notifications as the current path can change quickly. |
4264 | + * A notification will occur if it was requested for a path and this path is still the current at the moment |
4265 | + * of the notification. |
4266 | + * |
4267 | + * Once it detects a change it will wait \ref getIntervalToNotifyChanges() milliseconds to notify that change. |
4268 | + * At this moment it checks if no \ref setCurrentPath() has been called during this time and then notifies that change. |
4269 | + */ |
4270 | +class ExternalFSWatcher : public QFileSystemWatcher |
4271 | +{ |
4272 | + Q_OBJECT |
4273 | +public: |
4274 | + explicit ExternalFSWatcher(QObject *parent = 0); |
4275 | + int getIntervalToNotifyChanges() const; |
4276 | + |
4277 | +signals: |
4278 | + void pathModified(); |
4279 | + |
4280 | + public slots: |
4281 | + void setCurrentPath(const QString& curPath); |
4282 | + void setIntervalToNotifyChanges(int ms); |
4283 | + |
4284 | +private slots: |
4285 | + void slotDirChanged(const QString&); |
4286 | + void slotFireChanges(); |
4287 | + |
4288 | + private: |
4289 | + QString m_setPath; |
4290 | + QString m_changedPath; |
4291 | + unsigned m_waitingEmitCounter; |
4292 | + int m_msWaitTime; |
4293 | +}; |
4294 | + |
4295 | +#endif // EXTERNALFSWATCHER_H |
4296 | |
4297 | === added file 'src/plugin/folderlistmodel/filecompare.cpp' |
4298 | --- src/plugin/folderlistmodel/filecompare.cpp 1970-01-01 00:00:00 +0000 |
4299 | +++ src/plugin/folderlistmodel/filecompare.cpp 2014-04-15 08:19:22 +0000 |
4300 | @@ -0,0 +1,108 @@ |
4301 | +/************************************************************************** |
4302 | + * |
4303 | + * Copyright 2013 Canonical Ltd. |
4304 | + * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com> |
4305 | + * |
4306 | + * You may use this file under the terms of the BSD license as follows: |
4307 | + * |
4308 | + * "Redistribution and use in source and binary forms, with or without |
4309 | + * modification, are permitted provided that the following conditions are |
4310 | + * met: |
4311 | + * * Redistributions of source code must retain the above copyright |
4312 | + * notice, this list of conditions and the following disclaimer. |
4313 | + * * Redistributions in binary form must reproduce the above copyright |
4314 | + * notice, this list of conditions and the following disclaimer in |
4315 | + * the documentation and/or other materials provided with the |
4316 | + * distribution. |
4317 | + * * Neither the name of Nemo Mobile nor the names of its contributors |
4318 | + * may be used to endorse or promote products derived from this |
4319 | + * software without specific prior written permission. |
4320 | + * |
4321 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
4322 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
4323 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
4324 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
4325 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
4326 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
4327 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
4328 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
4329 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
4330 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
4331 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
4332 | + * |
4333 | + * File: filecompare.cpp |
4334 | + * Date: 6/25/2013 |
4335 | + */ |
4336 | + |
4337 | +#include "filecompare.h" |
4338 | +#include "diriteminfo.h" |
4339 | +#include <QString> |
4340 | +#include <QDateTime> |
4341 | +#include <QDebug> |
4342 | + |
4343 | + |
4344 | + |
4345 | +bool fileCompareExists(const DirItemInfo &a, const DirItemInfo &b) |
4346 | +{ |
4347 | + if (a.isDir() && !b.isDir()) |
4348 | + return true; |
4349 | + |
4350 | + if (b.isDir() && !a.isDir()) |
4351 | + return false; |
4352 | + |
4353 | + bool ret = QString::localeAwareCompare(a.fileName(), b.fileName()) < 0; |
4354 | +#if DEBUG_MESSAGES |
4355 | + qDebug() << Q_FUNC_INFO << ret << a.fileName() << b.fileName(); |
4356 | +#endif |
4357 | + |
4358 | + return ret; |
4359 | +} |
4360 | + |
4361 | + |
4362 | +bool fileCompareAscending(const DirItemInfo &a, const DirItemInfo &b) |
4363 | +{ |
4364 | + if (a.isDir() && !b.isDir()) |
4365 | + return true; |
4366 | + |
4367 | + if (b.isDir() && !a.isDir()) |
4368 | + return false; |
4369 | + |
4370 | + return QString::localeAwareCompare(a.fileName(), b.fileName()) < 0; |
4371 | +} |
4372 | + |
4373 | + |
4374 | +bool fileCompareDescending(const DirItemInfo &a, const DirItemInfo &b) |
4375 | +{ |
4376 | + if (a.isDir() && !b.isDir()) |
4377 | + return true; |
4378 | + |
4379 | + if (b.isDir() && !a.isDir()) |
4380 | + return false; |
4381 | + |
4382 | + return QString::localeAwareCompare(a.fileName(), b.fileName()) > 0; |
4383 | +} |
4384 | + |
4385 | + |
4386 | +bool dateCompareDescending(const DirItemInfo &a, const DirItemInfo &b) |
4387 | +{ |
4388 | + if (a.isDir() && !b.isDir()) |
4389 | + return true; |
4390 | + |
4391 | + if (b.isDir() && !a.isDir()) |
4392 | + return false; |
4393 | + |
4394 | + return a.lastModified() > b.lastModified(); |
4395 | +} |
4396 | + |
4397 | + |
4398 | +bool dateCompareAscending(const DirItemInfo &a, const DirItemInfo &b) |
4399 | +{ |
4400 | + if (a.isDir() && !b.isDir()) |
4401 | + return true; |
4402 | + |
4403 | + if (b.isDir() && !a.isDir()) |
4404 | + return false; |
4405 | + |
4406 | + return a.lastModified() < b.lastModified(); |
4407 | +} |
4408 | + |
4409 | |
4410 | === added file 'src/plugin/folderlistmodel/filecompare.h' |
4411 | --- src/plugin/folderlistmodel/filecompare.h 1970-01-01 00:00:00 +0000 |
4412 | +++ src/plugin/folderlistmodel/filecompare.h 2014-04-15 08:19:22 +0000 |
4413 | @@ -0,0 +1,51 @@ |
4414 | +/************************************************************************** |
4415 | + * |
4416 | + * Copyright 2013 Canonical Ltd. |
4417 | + * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com> |
4418 | + * |
4419 | + * You may use this file under the terms of the BSD license as follows: |
4420 | + * |
4421 | + * "Redistribution and use in source and binary forms, with or without |
4422 | + * modification, are permitted provided that the following conditions are |
4423 | + * met: |
4424 | + * * Redistributions of source code must retain the above copyright |
4425 | + * notice, this list of conditions and the following disclaimer. |
4426 | + * * Redistributions in binary form must reproduce the above copyright |
4427 | + * notice, this list of conditions and the following disclaimer in |
4428 | + * the documentation and/or other materials provided with the |
4429 | + * distribution. |
4430 | + * * Neither the name of Nemo Mobile nor the names of its contributors |
4431 | + * may be used to endorse or promote products derived from this |
4432 | + * software without specific prior written permission. |
4433 | + * |
4434 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
4435 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
4436 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
4437 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
4438 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
4439 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
4440 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
4441 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
4442 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
4443 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
4444 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
4445 | + * |
4446 | + * File: filecompare.h |
4447 | + * Date: 6/25/2013 |
4448 | + */ |
4449 | + |
4450 | +#ifndef FILECOMPARE_H |
4451 | +#define FILECOMPARE_H |
4452 | + |
4453 | +class DirItemInfo; |
4454 | + |
4455 | +typedef bool (*CompareFunction)(const DirItemInfo &a, const DirItemInfo &b); |
4456 | + |
4457 | +bool fileCompareExists(const DirItemInfo &a, const DirItemInfo &b); |
4458 | +bool fileCompareAscending(const DirItemInfo &a, const DirItemInfo &b); |
4459 | +bool fileCompareDescending(const DirItemInfo &a, const DirItemInfo &b); |
4460 | + |
4461 | +bool dateCompareDescending(const DirItemInfo &a, const DirItemInfo &b); |
4462 | +bool dateCompareAscending(const DirItemInfo &a, const DirItemInfo &b); |
4463 | + |
4464 | +#endif // FILECOMPARE_H |
4465 | |
4466 | === added file 'src/plugin/folderlistmodel/filesystemaction.cpp' |
4467 | --- src/plugin/folderlistmodel/filesystemaction.cpp 1970-01-01 00:00:00 +0000 |
4468 | +++ src/plugin/folderlistmodel/filesystemaction.cpp 2014-04-15 08:19:22 +0000 |
4469 | @@ -0,0 +1,1302 @@ |
4470 | +/************************************************************************** |
4471 | + * |
4472 | + * Copyright 2013 Canonical Ltd. |
4473 | + * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com> |
4474 | + * |
4475 | + * You may use this file under the terms of the BSD license as follows: |
4476 | + * |
4477 | + * "Redistribution and use in source and binary forms, with or without |
4478 | + * modification, are permitted provided that the following conditions are |
4479 | + * met: |
4480 | + * * Redistributions of source code must retain the above copyright |
4481 | + * notice, this list of conditions and the following disclaimer. |
4482 | + * * Redistributions in binary form must reproduce the above copyright |
4483 | + * notice, this list of conditions and the following disclaimer in |
4484 | + * the documentation and/or other materials provided with the |
4485 | + * distribution. |
4486 | + * * Neither the name of Nemo Mobile nor the names of its contributors |
4487 | + * may be used to endorse or promote products derived from this |
4488 | + * software without specific prior written permission. |
4489 | + * |
4490 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
4491 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
4492 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
4493 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
4494 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
4495 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
4496 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
4497 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
4498 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
4499 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
4500 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
4501 | + * |
4502 | + * File: filesystemaction.cpp |
4503 | + * Date: 3/13/2013 |
4504 | + */ |
4505 | + |
4506 | +#include "filesystemaction.h" |
4507 | +#include "clipboard.h" |
4508 | + |
4509 | +#if defined(Q_OS_UNIX) |
4510 | +#include <sys/statvfs.h> |
4511 | +#endif |
4512 | + |
4513 | +#include <errno.h> |
4514 | + |
4515 | +#include <QDirIterator> |
4516 | +#include <QDebug> |
4517 | +#include <QTimer> |
4518 | +#include <QFileInfo> |
4519 | +#include <QDir> |
4520 | +#include <QThread> |
4521 | +#include <QTemporaryFile> |
4522 | + |
4523 | +/*! |
4524 | + * number of the files to work on a step, when this number is reached a signal is emitted |
4525 | + */ |
4526 | +#define STEP_FILES 5 |
4527 | + |
4528 | +/*! |
4529 | + * buffer size to to single read/write operation |
4530 | + */ |
4531 | +#define COPY_BUFFER_SIZE 4096 |
4532 | + |
4533 | +/*! |
4534 | + * Auxiliar Actions do not emit progress() signal |
4535 | + * \sa moveDirToTempAndRemoveItLater() |
4536 | + */ |
4537 | +#define SHOULD_EMIT_PROGRESS_SIGNAL(action) (!action->isAux) |
4538 | + |
4539 | +#define COMMON_SIZE_ITEM 120 |
4540 | + |
4541 | + |
4542 | + |
4543 | + |
4544 | +void FileSystemAction::CopyFile::clear() |
4545 | +{ |
4546 | + bytesWritten = 0; |
4547 | + if (source) delete source; |
4548 | + if (target) delete target; |
4549 | + source = 0; |
4550 | + target = 0; |
4551 | +} |
4552 | + |
4553 | + |
4554 | + |
4555 | +//=============================================================================================== |
4556 | +/*! |
4557 | + * \brief FileSystemAction::FileSystemAction |
4558 | + * \param parent |
4559 | + */ |
4560 | +FileSystemAction::FileSystemAction(QObject *parent) : |
4561 | + QObject(parent) |
4562 | + , m_curAction(0) |
4563 | + , m_cancelCurrentAction(false) |
4564 | + , m_busy(false) |
4565 | + , m_clipboardChanged(false) |
4566 | +{ |
4567 | + |
4568 | +} |
4569 | + |
4570 | +//=============================================================================================== |
4571 | +/*! |
4572 | + * \brief FileSystemAction::~FileSystemAction |
4573 | + */ |
4574 | +FileSystemAction::~FileSystemAction() |
4575 | +{ |
4576 | + |
4577 | +} |
4578 | + |
4579 | +//=============================================================================================== |
4580 | +/*! |
4581 | + * \brief FileSystemAction::remove |
4582 | + * \param paths |
4583 | + */ |
4584 | +void FileSystemAction::remove(const QStringList &paths) |
4585 | +{ |
4586 | + createAndProcessAction(ActionRemove, paths); |
4587 | +} |
4588 | + |
4589 | +//=============================================================================================== |
4590 | +/*! |
4591 | + * \brief FileSystemAction::createAction |
4592 | + * \param type |
4593 | + * \param origBase |
4594 | + * \return |
4595 | + */ |
4596 | +FileSystemAction::Action* FileSystemAction::createAction(ActionType type, int origBase) |
4597 | +{ |
4598 | + Action * action = new Action(); |
4599 | + action->type = type; |
4600 | + action->baseOrigSize = origBase; |
4601 | + action->targetPath = m_path; |
4602 | + action->totalItems = 0; |
4603 | + action->currItem = 0; |
4604 | + action->currEntryIndex = 0; |
4605 | + action->totalBytes = 0; |
4606 | + action->bytesWritten = 0; |
4607 | + action->done = false; |
4608 | + action->auxAction = 0; |
4609 | + action->isAux = false; |
4610 | + action->currEntry = 0; |
4611 | + action->steps = 1; |
4612 | + |
4613 | + return action; |
4614 | +} |
4615 | + |
4616 | +//=============================================================================================== |
4617 | +/*! |
4618 | + * \brief FileSystemAction::addEntry |
4619 | + * \param action |
4620 | + * \param pathname |
4621 | + */ |
4622 | +void FileSystemAction::addEntry(Action* action, const QString& pathname) |
4623 | +{ |
4624 | +#if DEBUG_MESSAGES |
4625 | + qDebug() << Q_FUNC_INFO << pathname; |
4626 | +#endif |
4627 | + DirItemInfo info(pathname); |
4628 | + if (!info.isAbsolute()) |
4629 | + { |
4630 | + info.setFile(action->targetPath, pathname); |
4631 | + } |
4632 | + if (!info.exists()) |
4633 | + { |
4634 | + emit error(QObject::tr("File or Directory does not exist"), |
4635 | + pathname + QObject::tr(" does not exist") |
4636 | + ); |
4637 | + return; |
4638 | + } |
4639 | + ActionEntry * entry = new ActionEntry(); |
4640 | + //this is the item being handled |
4641 | + entry->reversedOrder.append(info); |
4642 | + // verify if the destination item already exists |
4643 | + if (action->type == ActionCopy || |
4644 | + action->type == ActionMove || |
4645 | + action->type == ActionHardMoveCopy) |
4646 | + { |
4647 | + DirItemInfo destination(targetFom(info.absoluteFilePath(), action)); |
4648 | + entry->alreadyExists = destination.exists(); |
4649 | + } |
4650 | + //ActionMove will perform a rename, so no Directory expanding is necessary |
4651 | + if (action->type != ActionMove && info.isDir() && !info.isSymLink()) |
4652 | + { |
4653 | + QDirIterator it(info.absoluteFilePath(), |
4654 | + QDir::AllEntries | QDir::System | |
4655 | + QDir::NoDotAndDotDot | QDir::Hidden, |
4656 | + QDirIterator::Subdirectories); |
4657 | + while (it.hasNext() && !it.next().isEmpty()) |
4658 | + { |
4659 | + entry->reversedOrder.prepend(it.fileInfo()); |
4660 | + } |
4661 | + } |
4662 | + //set steps and total bytes considering all items in the Entry |
4663 | + int counter = entry->reversedOrder.count(); |
4664 | + qint64 size = 0; |
4665 | + int sizeSteps = 0; |
4666 | + int bufferSize = (COPY_BUFFER_SIZE * STEP_FILES); |
4667 | + while (counter--) |
4668 | + { |
4669 | + const DirItemInfo & item = entry->reversedOrder.at(counter); |
4670 | + size = (item.isFile() && !item.isDir() && !item.isSymLink()) ? |
4671 | + item.size() : COMMON_SIZE_ITEM; |
4672 | + action->totalBytes += size; |
4673 | + if (action->type == ActionCopy || action->type == ActionHardMoveCopy) |
4674 | + { |
4675 | + if ( (sizeSteps = size / bufferSize) ) |
4676 | + { |
4677 | + if ( !(size % bufferSize) ) |
4678 | + { |
4679 | + --sizeSteps; |
4680 | + } |
4681 | + action->steps += sizeSteps ; |
4682 | + } |
4683 | + } |
4684 | + } |
4685 | + //set final steps for the Entry based on Items number |
4686 | + int entrySteps = entry->reversedOrder.count() / STEP_FILES; |
4687 | + if ( entry->reversedOrder.count() % STEP_FILES) entrySteps++; |
4688 | + action->steps += entrySteps; |
4689 | + action->totalItems += entry->reversedOrder.count(); |
4690 | +#if DEBUG_MESSAGES |
4691 | + qDebug() << "entrySteps" << entrySteps << "from entry counter" << entry->reversedOrder.count() |
4692 | + << "total steps" << action->steps; |
4693 | +#endif |
4694 | + //now put the Entry in the Action |
4695 | + action->entries.append(entry); |
4696 | +} |
4697 | + |
4698 | +//=============================================================================================== |
4699 | +/*! |
4700 | + * \brief FileSystemAction::processAction |
4701 | + */ |
4702 | +void FileSystemAction::processAction() |
4703 | +{ |
4704 | + if (m_curAction) |
4705 | + { |
4706 | + //it will be ActionHardMoveRemove only when switched from ActionHardMoveCopy |
4707 | + //in this case the move is done in two steps COPY and REMOVE |
4708 | + if (m_curAction->type != ActionHardMoveCopy) |
4709 | + { |
4710 | + delete m_curAction; |
4711 | + m_curAction = 0; |
4712 | + } |
4713 | + } |
4714 | + if (!m_curAction && m_queuedActions.count()) |
4715 | + { |
4716 | + m_curAction = m_queuedActions.at(0); |
4717 | + m_curAction->currEntry = static_cast<ActionEntry*> |
4718 | + ( m_curAction->entries.at(0)); |
4719 | + m_queuedActions.remove(0,1); |
4720 | + } |
4721 | + if (m_curAction) |
4722 | + { |
4723 | +#if DEBUG_MESSAGES |
4724 | + qDebug() << Q_FUNC_INFO << "performing action type" << m_curAction->type; |
4725 | +#endif |
4726 | + m_busy = true; |
4727 | + m_cancelCurrentAction = false; |
4728 | + m_errorMsg.clear(); |
4729 | + m_errorTitle.clear(); |
4730 | + scheduleSlot(SLOT(processActionEntry())); |
4731 | + if (SHOULD_EMIT_PROGRESS_SIGNAL(m_curAction)) |
4732 | + { |
4733 | + emit progress(0,m_curAction->totalItems, 0); |
4734 | + } |
4735 | + } |
4736 | + else |
4737 | + { |
4738 | + m_busy = false; |
4739 | + } |
4740 | +} |
4741 | + |
4742 | + |
4743 | +//=============================================================================================== |
4744 | +/*! |
4745 | + * \brief FileSystemAction::processActionEntry |
4746 | + */ |
4747 | +void FileSystemAction::processActionEntry() |
4748 | +{ |
4749 | +#if DEBUG_MESSAGES |
4750 | + qDebug() << Q_FUNC_INFO; |
4751 | +#endif |
4752 | + |
4753 | + ActionEntry * curEntry = m_curAction->currEntry; |
4754 | + |
4755 | +#if defined(SIMULATE_LONG_ACTION) |
4756 | + { |
4757 | + unsigned int delay = SIMULATE_LONG_ACTION; |
4758 | + if (delay == 1) |
4759 | + { |
4760 | + delay = 100; //each (10 * STEP_FILES) files will waits a second |
4761 | + QThread::currentThread()->wait(delay); |
4762 | + } |
4763 | + } |
4764 | +#endif |
4765 | + if (!m_cancelCurrentAction) |
4766 | + { |
4767 | + switch(m_curAction->type) |
4768 | + { |
4769 | + case ActionRemove: |
4770 | + case ActionHardMoveRemove: |
4771 | + removeEntry(curEntry); |
4772 | + endActionEntry(); |
4773 | + break; |
4774 | + case ActionCopy: |
4775 | + case ActionHardMoveCopy: |
4776 | + processCopyEntry(); // specially: this is a slot |
4777 | + break; |
4778 | + case ActionMove: |
4779 | + moveEntry(curEntry); |
4780 | + endActionEntry(); |
4781 | + break; |
4782 | + } |
4783 | + } |
4784 | +} |
4785 | + |
4786 | +//=============================================================================================== |
4787 | +/*! |
4788 | + * \brief FileSystemAction::endActionEntry |
4789 | + */ |
4790 | +void FileSystemAction::endActionEntry() |
4791 | +{ |
4792 | +#if DEBUG_MESSAGES |
4793 | + qDebug() << Q_FUNC_INFO; |
4794 | +#endif |
4795 | + ActionEntry * curEntry = m_curAction->currEntry; |
4796 | + |
4797 | + // first of all check for any error or a cancel issued by the user |
4798 | + if (m_cancelCurrentAction) |
4799 | + { |
4800 | + if (!m_errorTitle.isEmpty()) |
4801 | + { |
4802 | + emit error(m_errorTitle, m_errorMsg); |
4803 | + } |
4804 | + //it may have other actions to do |
4805 | + scheduleSlot(SLOT(processAction())); |
4806 | + return; |
4807 | + } |
4808 | + // check if the current entry has finished |
4809 | + // if so Views need to receive the notification about that |
4810 | + if (curEntry->currItem == curEntry->reversedOrder.count()) |
4811 | + { |
4812 | + const DirItemInfo & mainItem = curEntry->reversedOrder.at(curEntry->currItem -1); |
4813 | + m_curAction->currEntryIndex++; |
4814 | + switch(m_curAction->type) |
4815 | + { |
4816 | + case ActionRemove: |
4817 | + emit removed(mainItem); |
4818 | + break; |
4819 | + case ActionHardMoveRemove: // nothing to do |
4820 | + break; |
4821 | + case ActionHardMoveCopy: |
4822 | + //check if is doing a hard move and the copy part has finished |
4823 | + //if so switch the action to remove |
4824 | + if (m_curAction->currEntryIndex == m_curAction->entries.count()) |
4825 | + { |
4826 | + m_curAction->type = ActionHardMoveRemove; |
4827 | + m_curAction->currEntryIndex = 0; |
4828 | + int entryCounter = m_curAction->entries.count(); |
4829 | + ActionEntry * entry; |
4830 | + while (entryCounter--) |
4831 | + { |
4832 | + entry = m_curAction->entries.at(entryCounter); |
4833 | + entry->currItem = 0; |
4834 | + entry->currStep = 0; |
4835 | + } |
4836 | + } |
4837 | + case ActionCopy: // ActionHardMoveCopy is also checked here |
4838 | + case ActionMove: |
4839 | + { |
4840 | + QString addedItem = targetFom(mainItem.absoluteFilePath(), m_curAction); |
4841 | + if (!curEntry->added && !curEntry->alreadyExists) |
4842 | + { |
4843 | + emit added(addedItem); |
4844 | + curEntry->added = true; |
4845 | + } |
4846 | + else |
4847 | + { |
4848 | + emit changed(DirItemInfo(addedItem)); |
4849 | + } |
4850 | + } |
4851 | + break; |
4852 | + }//switch |
4853 | + |
4854 | + }//end if (curEntry->currItem == curEntry->reversedOrder.count()) |
4855 | + |
4856 | + if (curEntry->currStep == STEP_FILES) |
4857 | + { |
4858 | + curEntry->currStep = 0; |
4859 | + } |
4860 | + |
4861 | + int percent = notifyProgress(); |
4862 | + //Check if the current action has finished or cancelled |
4863 | + if (m_cancelCurrentAction || |
4864 | + m_curAction->currEntryIndex == m_curAction->entries.count()) |
4865 | + { |
4866 | + if (!m_cancelCurrentAction) |
4867 | + { |
4868 | + endCurrentAction(); |
4869 | + if (percent < 100) |
4870 | + { |
4871 | + notifyProgress(100); |
4872 | + } |
4873 | + } |
4874 | + //it may have other actions to do |
4875 | + scheduleSlot(SLOT(processAction())); |
4876 | + } |
4877 | + else |
4878 | + { |
4879 | + m_curAction->currEntry = static_cast<ActionEntry*> |
4880 | + ( m_curAction->entries.at(m_curAction->currEntryIndex) ); |
4881 | + //keep working on current Action maybe more entries |
4882 | + scheduleSlot(SLOT(processActionEntry())); |
4883 | + } |
4884 | +} |
4885 | + |
4886 | +//=============================================================================================== |
4887 | +/*! |
4888 | + * \brief FileSystemAction::cancel |
4889 | + */ |
4890 | +void FileSystemAction::cancel() |
4891 | +{ |
4892 | + m_cancelCurrentAction = true; |
4893 | +} |
4894 | + |
4895 | +//=============================================================================================== |
4896 | +/*! |
4897 | + * \brief FileSystemAction::removeEntry |
4898 | + * \param entry |
4899 | + */ |
4900 | +void FileSystemAction::removeEntry(ActionEntry *entry) |
4901 | +{ |
4902 | + QDir dir; |
4903 | + //do one step at least |
4904 | + for(; !m_cancelCurrentAction && |
4905 | + entry->currStep < STEP_FILES && |
4906 | + m_curAction->currItem < m_curAction->totalItems && |
4907 | + entry->currItem < entry->reversedOrder.count() |
4908 | + ; entry->currStep++, m_curAction->currItem++, entry->currItem++ |
4909 | + ) |
4910 | + |
4911 | + { |
4912 | + const DirItemInfo &fi = entry->reversedOrder.at(entry->currItem); |
4913 | + if (fi.isDir() && !fi.isSymLink()) |
4914 | + { |
4915 | + m_cancelCurrentAction = !dir.rmdir(fi.absoluteFilePath()); |
4916 | + } |
4917 | + else |
4918 | + { |
4919 | + m_cancelCurrentAction = !QFile::remove(fi.absoluteFilePath()); |
4920 | + } |
4921 | +#if DEBUG_REMOVE |
4922 | + qDebug() << Q_FUNC_INFO << "remove ret=" << !m_cancelCurrentAction << fi.absoluteFilePath(); |
4923 | +#endif |
4924 | + if (m_cancelCurrentAction) |
4925 | + { |
4926 | + m_errorTitle = QObject::tr("Could not remove the item ") + |
4927 | + fi.absoluteFilePath(); |
4928 | + m_errorMsg = ::strerror(errno); |
4929 | + } |
4930 | + } |
4931 | +} |
4932 | + |
4933 | + |
4934 | +//=============================================================================================== |
4935 | +/*! |
4936 | + * \brief FileSystemAction::copyEntry |
4937 | + * \param entry |
4938 | + */ |
4939 | +void FileSystemAction::processCopyEntry() |
4940 | +{ |
4941 | + ActionEntry * entry = m_curAction->currEntry; |
4942 | + |
4943 | +#if DEBUG_MESSAGES |
4944 | + qDebug() << Q_FUNC_INFO << "processing" |
4945 | + << entry->reversedOrder.at(entry->reversedOrder.count() -1).absoluteFilePath(); |
4946 | +#endif |
4947 | + /* |
4948 | + * This flag will be true when processCopySingleFile() has put any slot in the execution queue |
4949 | + * it will work to stop the loop. |
4950 | + * Later processCopyEntry() will be called again to continue working |
4951 | + */ |
4952 | + bool scheduleAnySlot = false; |
4953 | + |
4954 | + //first item from an Entry, |
4955 | + if (entry->currItem == 0 && entry->alreadyExists && entry->newName == 0) |
4956 | + { |
4957 | + //making backup only if the targetpath == origPath, otherwise the item is overwritten |
4958 | + if (m_curAction->targetPath == m_curAction->origPath) |
4959 | + { |
4960 | + //it will check again if the target exists |
4961 | + //if so, sets the entry->newName |
4962 | + //then targetFom() will use entry->newName for |
4963 | + // sub items in the Entry if the Entry is a directory |
4964 | + if (!makeBackupNameForCurrentItem(m_curAction) ) |
4965 | + { |
4966 | + m_cancelCurrentAction = true; |
4967 | + m_errorTitle = QObject::tr("Could not find a suitable name to backup"); |
4968 | + m_errorMsg = entry->reversedOrder.at( |
4969 | + entry->reversedOrder.count() -1 |
4970 | + ).absoluteFilePath(); |
4971 | + } |
4972 | + } |
4973 | +#if DEBUG_MESSAGES |
4974 | + else |
4975 | + { |
4976 | + qDebug() << entry->reversedOrder.at(entry->reversedOrder.count() -1).absoluteFilePath() |
4977 | + << " already exists and will be overwritten"; |
4978 | + } |
4979 | +#endif |
4980 | + } |
4981 | + |
4982 | + for(; !m_cancelCurrentAction && !scheduleAnySlot && |
4983 | + entry->currStep < STEP_FILES && |
4984 | + m_curAction->currItem < m_curAction->totalItems && |
4985 | + entry->currItem < entry->reversedOrder.count() |
4986 | + ; entry->currStep++, entry->currItem++ |
4987 | + ) |
4988 | + |
4989 | + { |
4990 | + const DirItemInfo &fi = entry->reversedOrder.at(entry->currItem); |
4991 | + QString orig = fi.absoluteFilePath(); |
4992 | + QString target = targetFom(orig, m_curAction); |
4993 | + QString path(target); |
4994 | + // do this here to allow progress send right item number, copySingleFile will emit progress() |
4995 | + m_curAction->currItem++; |
4996 | + //-- |
4997 | + if (fi.isFile() || fi.isSymLink()) |
4998 | + { |
4999 | + DirItemInfo t(target); |
5000 | + path = t.path(); |
FAILED: Continuous integration, rev:158 /code.launchpad .net/~dpm/ ubuntu- filemanager- app/include- plugin/ +merge/ 213368/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http:// 91.189. 93.70:8080/ job/ubuntu- filemanager- app-ci/ 149/ 91.189. 93.70:8080/ job/generic- mediumtests- trusty/ 1918/console 91.189. 93.70:8080/ job/ubuntu- filemanager- app-raring- amd64-ci/ 149/console 91.189. 93.70:8080/ job/ubuntu- filemanager- app-saucy- amd64-ci/ 149/console 91.189. 93.70:8080/ job/ubuntu- filemanager- app-trusty- amd64-ci/ 99/console
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/ubuntu- filemanager- app-ci/ 149/rebuild
http://