Merge lp:~fboucault/camera-app/photo_roll_reliable_indexes into lp:camera-app

Proposed by Florian Boucault
Status: Merged
Approved by: Ugo Riboni
Approved revision: 369
Merged at revision: 373
Proposed branch: lp:~fboucault/camera-app/photo_roll_reliable_indexes
Merge into: lp:camera-app
Diff against target: 300 lines (+120/-20)
5 files modified
CameraApp/foldersmodel.cpp (+81/-11)
CameraApp/foldersmodel.h (+2/-1)
GalleryView.qml (+11/-2)
PhotogridView.qml (+2/-1)
SlideshowView.qml (+24/-5)
To merge this branch: bzr merge lp:~fboucault/camera-app/photo_roll_reliable_indexes
Reviewer Review Type Date Requested Status
Ugo Riboni (community) Approve
PS Jenkins bot continuous-integration Needs Fixing
Review via email: mp+233052@code.launchpad.net

Commit message

Photo roll: more fine grained media folder monitoring as to properly forward deletions to the view. Workarounded a couple of Qt bugs related to snapMode SnapOneItem.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ugo Riboni (uriboni) wrote :

Fixes all the mentioned bugs and doesn't seem to introduce any regression. The code is also sensible even though I can't fully understand the QT workaround.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CameraApp/foldersmodel.cpp'
2--- CameraApp/foldersmodel.cpp 2014-08-11 17:42:41 +0000
3+++ CameraApp/foldersmodel.cpp 2014-09-02 13:20:32 +0000
4@@ -78,19 +78,17 @@
5
6 void FoldersModel::updateFileInfoList()
7 {
8+ beginResetModel();
9 m_fileInfoList.clear();
10 Q_FOREACH (QString folder, m_folders) {
11 QDir currentDir(folder);
12 QFileInfoList fileInfoList = currentDir.entryInfoList(QDir::Files | QDir::Readable,
13 QDir::Time | QDir::Reversed);
14 Q_FOREACH (QFileInfo fileInfo, fileInfoList) {
15+ if (fileInfo.isDir()) continue;
16 m_watcher->addPath(fileInfo.absoluteFilePath());
17- QString type = m_mimeDatabase.mimeTypeForFile(fileInfo).name();
18- Q_FOREACH (QString filterType, m_typeFilters) {
19- if (type.startsWith(filterType)) {
20- insertFileInfo(fileInfo);
21- break;
22- }
23+ if (fileMatchesTypeFilters(fileInfo)) {
24+ insertFileInfo(fileInfo, false);
25 }
26 }
27 }
28@@ -104,19 +102,45 @@
29 return fileInfo1.lastModified() < fileInfo2.lastModified();
30 }
31
32+bool FoldersModel::fileMatchesTypeFilters(const QFileInfo& newFileInfo)
33+{
34+ QString type = m_mimeDatabase.mimeTypeForFile(newFileInfo).name();
35+ Q_FOREACH (QString filterType, m_typeFilters) {
36+ if (type.startsWith(filterType)) {
37+ return true;
38+ }
39+ }
40+ return false;
41+}
42+
43 // inserts newFileInfo into m_fileInfoList while keeping m_fileInfoList sorted by
44 // file modification time with the files most recently modified first
45-void FoldersModel::insertFileInfo(const QFileInfo& newFileInfo)
46+void FoldersModel::insertFileInfo(const QFileInfo& newFileInfo, bool emitChange)
47 {
48 QFileInfoList::iterator i;
49 for (i = m_fileInfoList.begin(); i != m_fileInfoList.end(); ++i) {
50 QFileInfo fileInfo = *i;
51 if (!moreRecentThan(newFileInfo, fileInfo)) {
52- m_fileInfoList.insert(i, newFileInfo);
53+ if (emitChange) {
54+ int index = m_fileInfoList.indexOf(*i);
55+ beginInsertRows(QModelIndex(), index, index);
56+ m_fileInfoList.insert(i, newFileInfo);
57+ endInsertRows();
58+ } else {
59+ m_fileInfoList.insert(i, newFileInfo);
60+ }
61 return;
62 }
63 }
64- m_fileInfoList.append(newFileInfo);
65+
66+ if (emitChange) {
67+ int index = m_fileInfoList.size();
68+ beginInsertRows(QModelIndex(), index, index);
69+ m_fileInfoList.append(newFileInfo);
70+ endInsertRows();
71+ } else {
72+ m_fileInfoList.append(newFileInfo);
73+ }
74 }
75
76 QHash<int, QByteArray> FoldersModel::roleNames() const
77@@ -177,12 +201,58 @@
78
79 void FoldersModel::directoryChanged(const QString &directoryPath)
80 {
81- updateFileInfoList();
82+ /* Only react when a file is added. Ignore when a file was modified or
83+ * deleted as this is taken care of by FoldersModel::fileChanged()
84+ * To do so we go through all the files in directoryPath and add
85+ * all the ones we were not watching before.
86+ */
87+ QStringList watchedFiles = m_watcher->files();
88+ QDir directory(directoryPath);
89+ QStringList files = directory.entryList(QDir::Files | QDir::Readable,
90+ QDir::Time | QDir::Reversed);
91+
92+ Q_FOREACH (QString fileName, files) {
93+ QString filePath = directory.absoluteFilePath(fileName);
94+ if (!watchedFiles.contains(filePath)) {
95+ QFileInfo fileInfo(filePath);
96+ if (fileInfo.isDir()) continue;
97+ m_watcher->addPath(filePath);
98+ if (fileMatchesTypeFilters(fileInfo)) {
99+ insertFileInfo(fileInfo, true);
100+ }
101+ }
102+ }
103 }
104
105 void FoldersModel::fileChanged(const QString &filePath)
106 {
107- updateFileInfoList();
108+ /* Act appropriately upon file change or removal */
109+ bool exists = QFileInfo::exists(filePath);
110+ int fileIndex = m_fileInfoList.indexOf(QFileInfo(filePath));
111+
112+ if (exists) {
113+ // file's content has changed
114+ QFileInfo fileInfo = QFileInfo(filePath);
115+ if (fileIndex == -1) {
116+ // file's type might have changed and file might have to be included
117+ if (fileMatchesTypeFilters(fileInfo)) {
118+ insertFileInfo(fileInfo, true);
119+ }
120+ } else {
121+ // update file information
122+ QModelIndex modelIndex = this->index(fileIndex);
123+ m_fileInfoList[fileIndex] = fileInfo;
124+ Q_EMIT dataChanged(modelIndex, modelIndex);
125+ }
126+ } else {
127+ // file has either been removed or renamed
128+ if (fileIndex != -1) {
129+ // FIXME: handle the renamed case
130+ beginRemoveRows(QModelIndex(), fileIndex, fileIndex);
131+ m_fileInfoList.removeAt(fileIndex);
132+ endRemoveRows();
133+ }
134+ }
135 }
136
137 void FoldersModel::toggleSelected(int row)
138
139=== modified file 'CameraApp/foldersmodel.h'
140--- CameraApp/foldersmodel.h 2014-08-11 17:42:20 +0000
141+++ CameraApp/foldersmodel.h 2014-09-02 13:20:32 +0000
142@@ -52,7 +52,8 @@
143 void setSingleSelectionOnly(bool singleSelectionOnly);
144
145 void updateFileInfoList();
146- void insertFileInfo(const QFileInfo& newFileInfo);
147+ bool fileMatchesTypeFilters(const QFileInfo& newFileInfo);
148+ void insertFileInfo(const QFileInfo& newFileInfo, bool emitChange);
149
150 QHash<int, QByteArray> roleNames() const;
151 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
152
153=== modified file 'GalleryView.qml'
154--- GalleryView.qml 2014-08-11 17:20:01 +0000
155+++ GalleryView.qml 2014-09-02 13:20:32 +0000
156@@ -35,10 +35,13 @@
157 }
158
159 property bool gridMode: false
160+ property bool showLastPhotoTakenPending: false
161
162 function showLastPhotoTaken() {
163 galleryView.gridMode = false;
164- slideshowView.showLastPhotoTaken();
165+ // do not immediately try to show the photo in the slideshow as it
166+ // might not be in the photo roll model yet
167+ showLastPhotoTakenPending = true;
168 }
169
170 onExit: {
171@@ -54,6 +57,7 @@
172 anchors.fill: parent
173 model: galleryView.model
174 visible: opacity != 0.0
175+ inView: galleryView.inView
176 onToggleHeader: header.toggle();
177 }
178
179@@ -63,6 +67,7 @@
180 headerHeight: header.height
181 model: galleryView.model
182 visible: opacity != 0.0
183+ inView: galleryView.inView
184 onPhotoClicked: {
185 if (main.contentExportMode) {
186 model.toggleSelected(index);
187@@ -102,7 +107,11 @@
188
189 onInViewChanged: {
190 if (inView) {
191- header.show();
192+ header.show();
193+ if (showLastPhotoTakenPending) {
194+ slideshowView.showLastPhotoTaken();
195+ showLastPhotoTakenPending = false;
196+ }
197 }
198 }
199
200
201=== modified file 'PhotogridView.qml'
202--- PhotogridView.qml 2014-07-31 18:41:17 +0000
203+++ PhotogridView.qml 2014-09-02 13:20:32 +0000
204@@ -27,6 +27,7 @@
205 property var model
206 signal photoClicked(int index)
207 property real headerHeight
208+ property bool inView
209 property list<Action> actions
210
211 function showPhotoAtIndex(index) {
212@@ -83,7 +84,7 @@
213
214 asynchronous: true
215 cache: false
216- source: "image://thumbnailer/" + fileURL.toString()
217+ source: photogridView.inView ? "image://thumbnailer/" + fileURL.toString() : ""
218 sourceSize {
219 width: width
220 height: height
221
222=== modified file 'SlideshowView.qml'
223--- SlideshowView.qml 2014-08-15 17:28:36 +0000
224+++ SlideshowView.qml 2014-09-02 13:20:32 +0000
225@@ -29,7 +29,7 @@
226 property var model
227 property int currentIndex: listView.currentIndex
228 property bool touchAcquired: listView.currentItem ? listView.currentItem.pinchInProgress : false
229-
230+ property bool inView
231 signal toggleHeader
232 property list<Action> actions: [
233 Action {
234@@ -49,7 +49,7 @@
235 }
236
237 function showLastPhotoTaken() {
238- listView.positionViewAtBeginning();
239+ listView.currentIndex = 0;
240 }
241
242 function exit() {
243@@ -74,11 +74,23 @@
244 boundsBehavior: Flickable.StopAtBounds
245 cacheBuffer: width
246 highlightRangeMode: ListView.StrictlyEnforceRange
247+ // FIXME: this disables the animation introduced by highlightRangeMode
248+ // happening setting currentIndex; it is necessary at least because we
249+ // were hitting https://bugreports.qt-project.org/browse/QTBUG-41035
250+ highlightMoveDuration: 0
251 snapMode: ListView.SnapOneItem
252 spacing: units.gu(1)
253 interactive: currentItem ? !currentItem.pinchInProgress : true
254 property real maxDimension: Math.max(width, height)
255
256+ removeDisplaced: Transition {
257+ UbuntuNumberAnimation { property: "x" }
258+ }
259+ remove: Transition {
260+ ParallelAnimation {
261+ UbuntuNumberAnimation { property: "opacity"; to: 0 }
262+ }
263+ }
264 delegate: Item {
265 id: delegate
266 property bool pinchInProgress: zoomPinchArea.active
267@@ -167,7 +179,7 @@
268 anchors.fill: parent
269 asynchronous: true
270 cache: false
271- source: "image://thumbnailer/" + fileURL.toString()
272+ source: slideshowView.inView ? "image://thumbnailer/" + fileURL.toString() : ""
273 sourceSize {
274 width: listView.maxDimension
275 height: listView.maxDimension
276@@ -175,7 +187,6 @@
277 fillMode: Image.PreserveAspectFit
278 opacity: status == Image.Ready ? 1.0 : 0.0
279 Behavior on opacity { UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration} }
280-
281 }
282
283 Image {
284@@ -301,7 +312,15 @@
285 text: i18n.tr("Delete")
286 color: UbuntuColors.orange
287 onClicked: {
288- var currentFilePath = slideshowView.model.get(slideshowView.currentIndex, "filePath");
289+ // FIXME: workaround bug in ListView with snapMode: ListView.SnapOneItem
290+ // whereby after deleting the last item in the list the first
291+ // item would be shown even though the currentIndex was not set to 0
292+ var toBeDeleted = listView.currentIndex;
293+ if (listView.currentIndex == listView.count - 1) {
294+ listView.currentIndex = listView.currentIndex - 1;
295+ }
296+
297+ var currentFilePath = slideshowView.model.get(toBeDeleted, "filePath");
298 fileOperations.remove(currentFilePath);
299 PopupUtils.close(deleteDialog);
300 }

Subscribers

People subscribed via source and target branches