Merge lp:~carlos-mazieri/ubuntu-filemanager-app/app-devel-pre4 into lp:ubuntu-filemanager-app

Proposed by Carlos Jose Mazieri
Status: Merged
Approved by: David Planella
Approved revision: 175
Merged at revision: 182
Proposed branch: lp:~carlos-mazieri/ubuntu-filemanager-app/app-devel-pre4
Merge into: lp:ubuntu-filemanager-app
Prerequisite: lp:~carlos-mazieri/ubuntu-filemanager-app/app-devel-pre3
Diff against target: 1605 lines (+1155/-164)
14 files modified
src/plugin/folderlistmodel/CMakeLists.txt (+10/-0)
src/plugin/folderlistmodel/dirmodel.cpp (+106/-139)
src/plugin/folderlistmodel/dirmodel.h (+11/-16)
src/plugin/folderlistmodel/disk/disklocation.cpp (+222/-0)
src/plugin/folderlistmodel/disk/disklocation.h (+81/-0)
src/plugin/folderlistmodel/filecompare.cpp (+2/-3)
src/plugin/folderlistmodel/folderlistmodel.pri (+14/-5)
src/plugin/folderlistmodel/location.cpp (+140/-0)
src/plugin/folderlistmodel/location.h (+132/-0)
src/plugin/folderlistmodel/locationsfactory.cpp (+181/-0)
src/plugin/folderlistmodel/locationsfactory.h (+136/-0)
src/plugin/folderlistmodel/locationurl.cpp (+34/-0)
src/plugin/folderlistmodel/locationurl.h (+40/-0)
src/plugin/test_folderlistmodel/regression/tst_folderlistmodel.cpp (+46/-1)
To merge this branch: bzr merge lp:~carlos-mazieri/ubuntu-filemanager-app/app-devel-pre4
Reviewer Review Type Date Requested Status
Arto Jalkanen Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+218040@code.launchpad.net

Description of the change

Introduces Location, it basicaly handles Urls and their internal paths.

IORequest/DirListWorker and ExternalFSWatcher calls were moved from DirModel class to DiskLocation class

Location provides:
         current path/url -> Location::urlPath()
         its content -> Location::fetchItems()
         navigation -> up=Location::becomeParent() into sub-folders=Location::setFromInfoItem()
         notification about external changes in its current path.

Changed navigation in the file manager:
  DirModel::setPath() now calls LocationsFactory::setNewPath() which can change the location or set a path in the current location.
  DirModel::cdUp()
  DirModel::cdIntoIndex()
  DirModel::openPath()

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Pope 🍺🐧🐱 πŸ¦„ (popey) wrote :

I've asked Michael Spencer to take a look at this and the other related branches and review. If he has difficulty with that I've asked him to get back to me so we can find another reviewer.

173. By Carlos Jose Mazieri

Fixed using m_info when it can be null.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Arto Jalkanen (ajalkane) wrote :

1)

Non-virtual destructors on classes that either inherit or are inherited other classes with virtual functions, these should be virtual destructors:
~Location()
~DiskLocation()
~LocationsFactory()

Especially important are the Location ones and the classes deriving from it. A basic rule-of-thumb is to have a virtual destructor on any class that has virtual functions or that derives from a class that has virtual destructors. Deviating from this rule-of-thumb is sometimes acceptable but there should be heavy reasons for it, and some comment for why it is so would be appreciated. Right now I do not see anything in the code that would warrant them not-being virtual destructors.

It'd be good to check the code on the whole that there's not more than what I noticed in this code-review.

2)

There is const_cast<...> calls. It's a red flag, casting should only be used if definitely needed. Either document why it's needed or try to refactor the code to get rid of it. For example:
const Location * LocationsFactory::setNewPath(const QString& uPath)

Why does it need to return const pointer as it's used in such a way that it's modified? Why not have it return non-const pointer and get rid of the const_casts.

3)

in someplaces when checking pointer there is:
if (m_somePointer == 0)
and other times just:
if (m_somePointer)

Either is fine IMO, but it'd be good to keep the code-base consistent. So use one or the other.

4)

This perplexes me:

void Location::setFromInfoItem(const DirItemInfo *itemInfo)
917 +{
918 + if (m_info)
919 + {
920 + delete m_info;
921 + }
922 + m_info = const_cast<DirItemInfo*> (itemInfo);
923 +}

the name of the function, setFromInfoItem, along with the const parameter to me gives an impression that it will make a copy for the class to use. Instead it does a cast and uses the pointer directly. Perhaps do not use parameter as "const" and rename the function to setInfoItem(DireItemInfo *itemInfo) ? Here I may not understand some details, so feel free to correct me.

5)

Typos:

LocationsFactory::stringAfterSlahes() -> LocationsFactory::stringAfterSlashes()
DiskLocation::stoptExternalFsWatcher() -> DiskLocation::stopExternalFsWatcher()

review: Needs Fixing
174. By Carlos Jose Mazieri

* changed destructor to virtual from classes Location() and DiskLocation
* changed Location::setFromInfoItem(const DirItemInfo *itemInfo) to:
          Location::setInfoItem(DireItemInfo *itemInfo)
* changed const Location * LocationsFactory::setNewPath(const QString& uPath) to
                Location * LocationsFactory::setNewPath(const QString& uPath)
* changed const Location * LocationsFactory::parse(const QString& urlPath) to
                Location * LocationsFactory::parse(const QString& urlPath)
* changed const Location * LocationsFactory::location() const to
                Location * LocationsFactory::location() const

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Carlos Jose Mazieri (carlos-mazieri) wrote :

> 1)
>
> Non-virtual destructors on classes that either inherit or are inherited other
> classes with virtual functions, these should be virtual destructors:
> ~Location()
> ~DiskLocation()
> ~LocationsFactory()
>
> Especially important are the Location ones and the classes deriving from it. A
> basic rule-of-thumb is to have a virtual destructor on any class that has
> virtual functions or that derives from a class that has virtual destructors.
> Deviating from this rule-of-thumb is sometimes acceptable but there should be
> heavy reasons for it, and some comment for why it is so would be appreciated.
> Right now I do not see anything in the code that would warrant them not-being
> virtual destructors.
>

> It'd be good to check the code on the whole that there's not more than what I
> noticed in this code-review

DONE. added virtual for destructors. LocationsFactory does not have any virtual method nor any descendent class.

.
>
> 2)
>
> There is const_cast<...> calls. It's a red flag, casting should only be used
> if definitely needed. Either document why it's needed or try to refactor the
> code to get rid of it. For example:
> const Location * LocationsFactory::setNewPath(const QString& uPath)
>
> Why does it need to return const pointer as it's used in such a way that it's
> modified? Why not have it return non-const pointer and get rid of the
> const_casts.

DONE. removed const

>
> 3)
>
> in someplaces when checking pointer there is:
> if (m_somePointer == 0)
> and other times just:
> if (m_somePointer)
>
> Either is fine IMO, but it'd be good to keep the code-base consistent. So use
> one or the other.

I am used to use "if (pointer)" when asking for avalid address and "if (pointer == 0)" when asking if a pointer is NULL, I could use "if (pointer != 0)" when asking for avalid address, but not "if (!pointer)" which looks like the variable is a bool.

>
> 4)
>
> This perplexes me:
>
> void Location::setFromInfoItem(const DirItemInfo *itemInfo)
> 917 +{
> 918 + if (m_info)
> 919 + {
> 920 + delete m_info;
> 921 + }
> 922 + m_info = const_cast<DirItemInfo*> (itemInfo);
> 923 +}
>

DONE. Changed to Location::setInfoItem(DireItemInfo *itemInfo) (const removed)

>
> the name of the function, setFromInfoItem, along with the const parameter to
> me gives an impression that it will make a copy for the class to use. Instead
> it does a cast and uses the pointer directly. Perhaps do not use parameter as
> "const" and rename the function to setInfoItem(DireItemInfo *itemInfo) ? Here
> I may not understand some details, so feel free to correct me.
>
> 5)
>
> Typos:
>
> LocationsFactory::stringAfterSlahes() ->
> LocationsFactory::stringAfterSlashes()
> DiskLocation::stoptExternalFsWatcher() ->
> DiskLocation::stopExternalFsWatcher()

DONE. Changed.

Revision history for this message
Arto Jalkanen (ajalkane) wrote :

Thanks for the fixes! A couple of things anymore:

> > It'd be good to check the code on the whole that there's not more than what
> I
> > noticed in this code-review
>
>
> DONE. added virtual for destructors. LocationsFactory does not have any
> virtual method nor any descendent class.

But LocationsFactory inherits QObject which does have virtual methods so it's a potential hard to find error even if it's not a problem in code-base currently. Consider for example Qt's resource management where parent QObject is responsible for deleting its children. If LocationsFactory (or any other similar class) is set as a child of some other QObject (practically speaking using the new LocationsFactory(QObject *parent) constructor where parent is not null), then when the parent QObject is deleted then LocationsFactory's destructor is not called - unless you make it virtual.

> I am used to use "if (pointer)" when asking for avalid address and "if
> (pointer == 0)" when asking if a pointer is NULL, I could use "if (pointer !=
> 0)" when asking for avalid address, but not "if (!pointer)" which looks like
> the variable is a bool.

That makes sense, I misread that line. It's good.

> >
> > 4)
> >
> > This perplexes me:
> >
> > void Location::setFromInfoItem(const DirItemInfo *itemInfo)
> > 917 +{
> > 918 + if (m_info)
> > 919 + {
> > 920 + delete m_info;
> > 921 + }
> > 922 + m_info = const_cast<DirItemInfo*> (itemInfo);
> > 923 +}
> >
>
> DONE. Changed to Location::setInfoItem(DireItemInfo *itemInfo) (const removed)

There's still two places with unnecessary const_casts:

143 + mCurLocation = const_cast<Location*> (location);
235 + mCurLocation = const_cast<Location*> (location);

review: Needs Fixing
Revision history for this message
Carlos Jose Mazieri (carlos-mazieri) wrote :

> Thanks for the fixes! A couple of things anymore:
>
> > > It'd be good to check the code on the whole that there's not more than
> what
> > I
> > > noticed in this code-review
> >
> >
> > DONE. added virtual for destructors. LocationsFactory does not have any
> > virtual method nor any descendent class.
>
> But LocationsFactory inherits QObject which does have virtual methods so it's
> a potential hard to find error even if it's not a problem in code-base
> currently. Consider for example Qt's resource management where parent QObject
> is responsible for deleting its children. If LocationsFactory (or any other
> similar class) is set as a child of some other QObject (practically speaking
> using the new LocationsFactory(QObject *parent) constructor where parent is
> not null), then when the parent QObject is deleted then LocationsFactory's
> destructor is not called - unless you make it virtual.
>

  I agree that it is a good programming practice and I can do it, no problem.
  But I am not sure it happens, QObject DOES HAVE virtual destructor which in my opinion makes all descendant destructors to be called.

> > I am used to use "if (pointer)" when asking for avalid address and "if
> > (pointer == 0)" when asking if a pointer is NULL, I could use "if (pointer
> !=
> > 0)" when asking for avalid address, but not "if (!pointer)" which looks like
> > the variable is a bool.
>
> That makes sense, I misread that line. It's good.
>
> > >
> > > 4)
> > >
> > > This perplexes me:
> > >
> > > void Location::setFromInfoItem(const DirItemInfo *itemInfo)
> > > 917 +{
> > > 918 + if (m_info)
> > > 919 + {
> > > 920 + delete m_info;
> > > 921 + }
> > > 922 + m_info = const_cast<DirItemInfo*> (itemInfo);
> > > 923 +}
> > >
> >
> > DONE. Changed to Location::setInfoItem(DireItemInfo *itemInfo) (const
> removed)
>
> There's still two places with unnecessary const_casts:
>
> 143 + mCurLocation = const_cast<Location*> (location);
> 235 + mCurLocation = const_cast<Location*> (location);

Revision history for this message
Arto Jalkanen (ajalkane) wrote :

> > Thanks for the fixes! A couple of things anymore:
> >
> > > > It'd be good to check the code on the whole that there's not more than
> > what
> > > I
> > > > noticed in this code-review
> > >
> > >
> > > DONE. added virtual for destructors. LocationsFactory does not have any
> > > virtual method nor any descendent class.
> >
> > But LocationsFactory inherits QObject which does have virtual methods so
> it's
> > a potential hard to find error even if it's not a problem in code-base
> > currently. Consider for example Qt's resource management where parent
> QObject
> > is responsible for deleting its children. If LocationsFactory (or any other
> > similar class) is set as a child of some other QObject (practically speaking
> > using the new LocationsFactory(QObject *parent) constructor where parent is
> > not null), then when the parent QObject is deleted then LocationsFactory's
> > destructor is not called - unless you make it virtual.
> >
>
> I agree that it is a good programming practice and I can do it, no problem.
> But I am not sure it happens, QObject DOES HAVE virtual destructor which in
> my opinion makes all descendant destructors to be called.

You're right. Shame on me forgetting that when base class has virtual destructor, it makes all descendant classes destructors virtual automatic even without specifically declaring them such.

So yes, it's not a problem.

>
> > > I am used to use "if (pointer)" when asking for avalid address and "if
> > > (pointer == 0)" when asking if a pointer is NULL, I could use "if (pointer
> > !=
> > > 0)" when asking for avalid address, but not "if (!pointer)" which looks
> like
> > > the variable is a bool.
> >
> > That makes sense, I misread that line. It's good.
> >
> > > >
> > > > 4)
> > > >
> > > > This perplexes me:
> > > >
> > > > void Location::setFromInfoItem(const DirItemInfo *itemInfo)
> > > > 917 +{
> > > > 918 + if (m_info)
> > > > 919 + {
> > > > 920 + delete m_info;
> > > > 921 + }
> > > > 922 + m_info = const_cast<DirItemInfo*> (itemInfo);
> > > > 923 +}
> > > >
> > >
> > > DONE. Changed to Location::setInfoItem(DireItemInfo *itemInfo) (const
> > removed)
> >
> > There's still two places with unnecessary const_casts:
> >
> > 143 + mCurLocation = const_cast<Location*> (location);
> > 235 + mCurLocation = const_cast<Location*> (location);

175. By Carlos Jose Mazieri

removed row no necessary const_cast<Location*>

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Carlos Jose Mazieri (carlos-mazieri) wrote :

revision 175 removes:
  143 + mCurLocation = const_cast<Location*> (location);
  235 + mCurLocation = const_cast<Location*> (location);

I think that completes those 5 items, they all have been solved.

Revision history for this message
Arto Jalkanen (ajalkane) wrote :

Thank you for doing these!

review: Approve
Revision history for this message
David Planella (dpm) wrote :

Thanks guys, top-approving as per Arto's last comment.

@Arto, in the future, please feel free to top-approve the merge proposal yourself if you think it's ready to land. Thanks!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/plugin/folderlistmodel/CMakeLists.txt'
2--- src/plugin/folderlistmodel/CMakeLists.txt 2014-04-28 10:21:05 +0000
3+++ src/plugin/folderlistmodel/CMakeLists.txt 2014-05-15 23:31:23 +0000
4@@ -1,5 +1,7 @@
5 include_directories(
6 ${CMAKE_CURRENT_SOURCE_DIR}
7+ disk
8+ trash
9 )
10
11 set(PLUGIN_DIR org/nemomobile/folderlistmodel)
12@@ -32,6 +34,14 @@
13 ioworkerthread.h
14 plugin.cpp
15 plugin.h
16+ location.cpp
17+ location.h
18+ locationsfactory.cpp
19+ locationsfactory.h
20+ locationurl.cpp
21+ locationurl.h
22+ disk/disklocation.cpp
23+ disk/disklocation.h
24 trash/qtrashdir.cpp
25 trash/qtrashdir.h
26 )
27
28=== modified file 'src/plugin/folderlistmodel/dirmodel.cpp'
29--- src/plugin/folderlistmodel/dirmodel.cpp 2014-05-15 23:31:22 +0000
30+++ src/plugin/folderlistmodel/dirmodel.cpp 2014-05-15 23:31:23 +0000
31@@ -31,12 +31,13 @@
32
33 #include "dirselection.h"
34 #include "dirmodel.h"
35-#include "iorequest.h"
36-#include "ioworkerthread.h"
37 #include "filesystemaction.h"
38-#include "externalfswatcher.h"
39 #include "clipboard.h"
40 #include "fmutil.h"
41+#include "locationsfactory.h"
42+#include "location.h"
43+#include "locationurl.h"
44+#include "disklocation.h"
45
46
47 #ifndef DO_NOT_USE_TAG_LIB
48@@ -75,7 +76,6 @@
49 #define IS_FILE_MANAGER_IDLE() (!mAwaitingResults)
50
51
52-Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread)
53
54 namespace {
55 QHash<QByteArray, int> roleMapping;
56@@ -108,9 +108,11 @@
57 , mSortBy(SortByName)
58 , mSortOrder(SortAscending)
59 , mCompareFunction(0)
60- , mExtFSWatcher(0)
61- , mClipboard(new Clipboard(this))
62- , m_fsAction(new FileSystemAction(this) )
63+ , mExtFSWatcher(false)
64+ , mClipboard(new Clipboard(this))
65+ , mLocationFactory(new LocationsFactory(this))
66+ , mCurLocation(0)
67+ , m_fsAction(new FileSystemAction(this) )
68 {
69 mNameFilters = QStringList() << "*";
70
71@@ -155,13 +157,40 @@
72 {
73 FMUtil::setThemeName();
74 }
75+
76+ foreach (const Location* l, mLocationFactory->availableLocations())
77+ {
78+ connect(l, SIGNAL(itemsAdded(DirItemInfoList)),
79+ this, SLOT(onItemsAdded(DirItemInfoList)));
80+
81+ connect(l, SIGNAL(itemsFetched()),
82+ this, SLOT(onItemsFetched()));
83+
84+ connect(l, SIGNAL(extWatcherItemAdded(DirItemInfo)),
85+ this, SLOT(onItemAddedOutsideFm(DirItemInfo)));
86+
87+ connect(l, SIGNAL(extWatcherItemRemoved(DirItemInfo)),
88+ this, SLOT(onItemRemovedOutSideFm(DirItemInfo)));
89+
90+ connect(l, SIGNAL(extWatcherItemChanged(DirItemInfo)),
91+ this, SLOT(onItemChangedOutSideFm(DirItemInfo)));
92+
93+ connect(l, SIGNAL(extWatcherChangesFetched(int)),
94+ this, SLOT(onExternalFsWorkerFinished(int)));
95+
96+ connect(l, SIGNAL(extWatcherPathChanged(QString)),
97+ this, SLOT(onThereAreExternalChanges(QString)));
98+
99+ connect(this, SIGNAL(enabledExternalFSWatcherChanged(bool)),
100+ l, SLOT(setUsingExternalWatcher(bool)));
101+ }
102 }
103
104
105
106 DirModel::~DirModel()
107 {
108- stoptExternalFsWatcher();
109+
110 }
111
112
113@@ -371,38 +400,48 @@
114 if (pathName.isEmpty())
115 return;
116
117- if (!canReadDir(pathName))
118- {
119- emit error(tr("cannot read path"), pathName);
120- return;
121- }
122-
123- if (mAwaitingResults) {
124+ if (mAwaitingResults) {
125 // TODO: handle the case where pathName != our current path, cancel old
126 // request, start a new one
127- qDebug() << Q_FUNC_INFO << this << "Ignoring path change request, request already running";
128- return;
129- }
130-
131+ qDebug() << Q_FUNC_INFO << this << "Ignoring path change request, request already running in" << pathName;
132+ return;
133+ }
134+
135+ Location *location = mLocationFactory->setNewPath(pathName);
136+ if (location == 0)
137+ {
138+ emit error(tr("path or url may not exist or cannot be read"), pathName);
139+ qDebug() << Q_FUNC_INFO << this << "path or url may not exist or cannot be read:" << pathName;
140+ return;
141+ }
142+
143+ mCurLocation = location;
144+ setPathFromCurrentLocation();
145+}
146+
147+/*!
148+ * \brief DirModel::setPathFromCurrentLocation() changes current Path using current Location
149+ *
150+ * Used in \ref cdUp() and \ref cdIntoIndex()
151+ */
152+void DirModel::setPathFromCurrentLocation()
153+{
154 mAwaitingResults = true;
155 emit awaitingResultsChanged();
156 #if DEBUG_MESSAGES
157- qDebug() << Q_FUNC_INFO << this << "Changing to " << pathName << " on " << QThread::currentThreadId();
158+ qDebug() << Q_FUNC_INFO << this << "Changing to " << mCurLocation->urlPath();
159 #endif
160
161 clear();
162
163- DirListWorker *dlw = createWorkerRequest(IORequest::DirList, pathName);
164- connect(dlw, SIGNAL(itemsAdded(DirItemInfoList)), SLOT(onItemsAdded(DirItemInfoList)));
165- connect(dlw, SIGNAL(workerFinished()), SLOT(onResultsFetched()));
166- ioWorkerThread()->addRequest(dlw);
167+ mCurLocation->fetchItems(currentDirFilter(), mIsRecursive);
168
169- mCurrentDir = pathName;
170- emit pathChanged(pathName);
171+ mCurrentDir = mCurLocation->urlPath();
172+ emit pathChanged(mCurLocation->urlPath());
173 }
174
175
176-void DirModel::onResultsFetched() {
177+void DirModel::onItemsFetched() {
178 if (mAwaitingResults) {
179 #if DEBUG_MESSAGES
180 qDebug() << Q_FUNC_INFO << this << "No longer awaiting results";
181@@ -611,7 +650,9 @@
182 }
183 ExternalFSWatcher * DirModel::getExternalFSWatcher() const
184 {
185- return mExtFSWatcher;
186+ const Location *l = mLocationFactory->availableLocations().at(LocationsFactory::LocalDisk);
187+ const DiskLocation *disk = static_cast<const DiskLocation*> (l);
188+ return disk->getExternalFSWatcher();
189 }
190 #endif
191
192@@ -624,15 +665,10 @@
193
194 bool DirModel::cdUp()
195 {
196- int ret = false;
197- if (!mCurrentDir.isEmpty()) // we are in any dir
198+ int ret = mCurLocation && mCurLocation->becomeParent();
199+ if (ret)
200 {
201- QDir current(mCurrentDir);
202- if (current.cdUp())
203- {
204- setPath(current.absolutePath());
205- ret = true;
206- }
207+ setPathFromCurrentLocation();
208 }
209 return ret;
210 }
211@@ -720,7 +756,9 @@
212 mDirectoryContents.at(row).isDir() &&
213 mDirectoryContents.at(row).isContentReadable())
214 {
215- ret = cdInto(mDirectoryContents.at(row));
216+ mCurLocation->setInfoItem(mDirectoryContents.at(row));
217+ setPathFromCurrentLocation();
218+ ret = true;
219 }
220 else
221 {
222@@ -1114,8 +1152,28 @@
223
224 bool DirModel::openPath(const QString &filename)
225 {
226- DirItemInfo fi(setParentIfRelative(filename));
227- return openItem(fi);
228+ bool ret = false;
229+ //first void any relative path when is root
230+ if ( !(mCurLocation && mCurLocation->isRoot() && filename.startsWith(QLatin1String(".."))) )
231+ {
232+ Location *location = mLocationFactory->setNewPath(filename);
233+ if (location)
234+ {
235+ mCurLocation = location;
236+ setPathFromCurrentLocation();
237+ ret = true;
238+ }
239+ else
240+ {
241+ const DirItemInfo *item = mLocationFactory->lastValidFileInfo();
242+ // DirItemInfo fi(setParentIfRelative(filename));
243+ if (item && item->isFile())
244+ {
245+ ret = openItem(*item);
246+ }
247+ }
248+ }
249+ return ret;
250 }
251
252 /*!
253@@ -1144,76 +1202,8 @@
254 return ret;
255 }
256
257-/*!
258- * \brief DirModel::createWorkerRequest() create a request for IORequestWorker
259- * \param requestType the common IORequest::DirList to fill a directory content
260- * or IORequest::DirAutoRefresh that will verify any external File System modification
261- * \param pathName the path to get content
262- * \return the thread object
263- */
264-DirListWorker * DirModel::createWorkerRequest(IORequest::RequestType requestType,
265- const QString& pathName)
266-{
267- DirListWorker * reqThread = 0;
268- QDir::Filter dirFilter = currentDirFilter();
269- if (requestType == IORequest::DirList)
270- {
271- // TODO: we need to set a spinner active before we start getting results from DirListWorker
272- reqThread = new DirListWorker(pathName, dirFilter, mIsRecursive);
273- }
274- else
275- {
276- reqThread = new ExternalFileSystemChangesWorker(mDirectoryContents,
277- pathName,
278- dirFilter, mIsRecursive);
279- }
280- return reqThread;
281-}
282-
283-
284-
285-/*!
286- * \brief DirModel::startExternalFsWatcher() starts the External File System Watcher
287- */
288-void DirModel::startExternalFsWatcher()
289-{
290-#if DEBUG_EXT_FS_WATCHER
291- qDebug() << "[extFsWorker]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
292- << Q_FUNC_INFO << this;
293-
294-#endif
295- if (!mExtFSWatcher)
296- {
297- mExtFSWatcher = new ExternalFSWatcher(this);
298- mExtFSWatcher->setIntervalToNotifyChanges(EX_FS_WATCHER_TIMER_INTERVAL);
299- connect(this, SIGNAL(pathChanged(QString)),
300- mExtFSWatcher, SLOT(setCurrentPath(QString)));
301-
302- connect(mExtFSWatcher, SIGNAL(pathModified(QString)),
303- this, SLOT(onThereAreExternalChanges(QString)));
304-
305- //setCurrentPath() checks for empty paths
306- mExtFSWatcher->setCurrentPath(mCurrentDir);
307- }
308-}
309-
310-
311-
312-/*!
313- * \brief DirModel::stoptExternalFsWatcher stops the External File System Watcher
314- */
315-void DirModel::stoptExternalFsWatcher()
316-{
317-#if DEBUG_EXT_FS_WATCHER
318- qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
319- << Q_FUNC_INFO << this;
320-#endif
321- if (mExtFSWatcher)
322- {
323- delete mExtFSWatcher;
324- mExtFSWatcher = 0;
325- }
326-}
327+
328+
329
330
331 void DirModel::onThereAreExternalChanges(const QString& pathModifiedOutside)
332@@ -1222,27 +1212,11 @@
333 {
334 #if DEBUG_EXT_FS_WATCHER
335 qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
336- << Q_FUNC_INFO << this << "File System modified" << pathModifiedOutside;
337-#else
338- Q_UNUSED(pathModifiedOutside);
339+ << Q_FUNC_INFO << this << "File System modified in" << pathModifiedOutside;
340 #endif
341- DirListWorker *w =
342- createWorkerRequest(IORequest::DirListExternalFSChanges,
343- mCurrentDir
344- );
345- ExternalFileSystemChangesWorker *extFsWorker =
346- static_cast<ExternalFileSystemChangesWorker*> (w);
347-
348- connect(extFsWorker, SIGNAL(added(DirItemInfo)),
349- this, SLOT(onItemAddedOutsideFm(DirItemInfo)));
350- connect(extFsWorker, SIGNAL(removed(DirItemInfo)),
351- this, SLOT(onItemRemovedOutSideFm(DirItemInfo)));
352- connect(extFsWorker, SIGNAL(changed(DirItemInfo)),
353- this, SLOT(onItemChangedOutSideFm(DirItemInfo)));
354- connect(extFsWorker, SIGNAL(finished(int)),
355- this, SLOT(onExternalFsWorkerFinished(int)));
356-
357- ioWorkerThread()->addRequest(extFsWorker);
358+ mCurLocation->fetchExternalChanges(pathModifiedOutside,
359+ mDirectoryContents,
360+ currentDirFilter());
361 }
362 #if DEBUG_EXT_FS_WATCHER
363 else
364@@ -1342,7 +1316,7 @@
365 */
366 bool DirModel::getEnabledExternalFSWatcher() const
367 {
368- return mExtFSWatcher ? true : false;
369+ return mExtFSWatcher;
370 }
371
372
373@@ -1351,15 +1325,8 @@
374 * \param enable
375 */
376 void DirModel::setEnabledExternalFSWatcher(bool enable)
377-{
378- if(enable)
379- {
380- startExternalFsWatcher();
381- }
382- else
383- {
384- stoptExternalFsWatcher();
385- }
386+{
387+ emit enabledExternalFSWatcherChanged(enable);
388 }
389
390
391
392=== modified file 'src/plugin/folderlistmodel/dirmodel.h'
393--- src/plugin/folderlistmodel/dirmodel.h 2014-05-15 23:31:22 +0000
394+++ src/plugin/folderlistmodel/dirmodel.h 2014-05-15 23:31:23 +0000
395@@ -42,17 +42,11 @@
396 #include "diriteminfo.h"
397
398 class FileSystemAction;
399-class ExternalFSWatcher;
400 class Clipboard;
401 class DirSelection;
402-
403-/*!
404- * When the External File System Wathcer is enabled,
405- * this is the interval used to check if there has been any change in the current path
406- *
407- * \sa setEnabledExternalFSWatcher()
408- */
409-#define EX_FS_WATCHER_TIMER_INTERVAL 900
410+class LocationsFactory;
411+class Location;
412+class ExternalFSWatcher;
413
414 class DirModel : public DirItemAbstractListModel
415 {
416@@ -150,7 +144,7 @@
417
418 public slots:
419 void onItemsAdded(const DirItemInfoList &newFiles);
420- void onResultsFetched();
421+ void onItemsFetched();
422
423 signals:
424 void awaitingResultsChanged();
425@@ -206,7 +200,7 @@
426 Q_PROPERTY(int clipboardUrlsCounter READ getClipboardUrlsCounter NOTIFY clipboardChanged)
427 int getClipboardUrlsCounter() const;
428
429- Q_PROPERTY(bool enableExternalFSWatcher READ getEnabledExternalFSWatcher WRITE setEnabledExternalFSWatcher)
430+ Q_PROPERTY(bool enableExternalFSWatcher READ getEnabledExternalFSWatcher WRITE setEnabledExternalFSWatcher NOTIFY enabledExternalFSWatcherChanged)
431 bool getEnabledExternalFSWatcher() const;
432
433 Q_INVOKABLE QString homePath() const;
434@@ -360,8 +354,8 @@
435 void showHiddenFilesChanged();
436 void sortByChanged();
437 void sortOrderChanged();
438-
439 void clipboardChanged();
440+ void enabledExternalFSWatcherChanged(bool);
441
442 private slots:
443 void onItemRemoved(const QString&);
444@@ -377,12 +371,11 @@
445 QDir::Filter currentDirFilter() const;
446 QString dirItems(const DirItemInfo& fi) const;
447 bool cdInto(const DirItemInfo& fi);
448- bool openItem(const DirItemInfo& fi);
449- DirListWorker * createWorkerRequest(IORequest::RequestType requestType,
450- const QString& pathName);
451+ bool openItem(const DirItemInfo& fi);
452 bool canReadDir(const QFileInfo& d) const;
453 bool canReadFile(const QFileInfo& f) const;
454 QFileInfo setParentIfRelative(const QString &fileOrDir) const;
455+ void setPathFromCurrentLocation();
456
457 private:
458 void startExternalFsWatcher();
459@@ -401,9 +394,11 @@
460 SortBy mSortBy;
461 SortOrder mSortOrder;
462 CompareFunction mCompareFunction;
463- ExternalFSWatcher* mExtFSWatcher;
464+ bool mExtFSWatcher;
465 Clipboard * mClipboard;
466 DirSelection * mSelection;
467+ LocationsFactory * mLocationFactory;
468+ Location * mCurLocation;
469
470
471 private:
472
473=== added directory 'src/plugin/folderlistmodel/disk'
474=== added file 'src/plugin/folderlistmodel/disk/disklocation.cpp'
475--- src/plugin/folderlistmodel/disk/disklocation.cpp 1970-01-01 00:00:00 +0000
476+++ src/plugin/folderlistmodel/disk/disklocation.cpp 2014-05-15 23:31:23 +0000
477@@ -0,0 +1,222 @@
478+/**************************************************************************
479+ *
480+ * Copyright 2014 Canonical Ltd.
481+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
482+ *
483+ * This program is free software; you can redistribute it and/or modify
484+ * it under the terms of the GNU Lesser General Public License as published by
485+ * the Free Software Foundation; version 3.
486+ *
487+ * This program is distributed in the hope that it will be useful,
488+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
489+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
490+ * GNU Lesser General Public License for more details.
491+ *
492+ * You should have received a copy of the GNU Lesser General Public License
493+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
494+ *
495+ * File: disklocation.cpp
496+ * Date: 08/03/2014
497+ */
498+
499+#include "disklocation.h"
500+#include "iorequest.h"
501+#include "ioworkerthread.h"
502+#include "externalfswatcher.h"
503+
504+#include <QDebug>
505+
506+#if defined(DEBUG_EXT_FS_WATCHER)
507+# define DEBUG_WATCHER() qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") \
508+ << Q_FUNC_INFO << this
509+#else
510+# define DEBUG_WATCHER() /**/
511+#endif
512+
513+DiskLocation::DiskLocation(int type, QObject *parent)
514+ : Location(type, parent)
515+ , m_extWatcher(0)
516+{
517+}
518+
519+
520+DiskLocation::~ DiskLocation()
521+{
522+ stopExternalFsWatcher();
523+}
524+
525+
526+void DiskLocation::fetchItems(QDir::Filter dirFilter, bool recursive)
527+{
528+ DirListWorker *dlw = new DirListWorker(m_info->absoluteFilePath(), dirFilter, recursive);
529+ connect(dlw, SIGNAL(itemsAdded(DirItemInfoList)),
530+ this, SIGNAL(itemsAdded(DirItemInfoList)));
531+ connect(dlw, SIGNAL(workerFinished()),
532+ this, SLOT(onItemsFetched()));
533+ workerThread()->addRequest(dlw);
534+}
535+
536+
537+bool DiskLocation::becomeParent()
538+{
539+ bool ret = false;
540+ if (m_info && !m_info->isRoot())
541+ {
542+ DirItemInfo *other = new DirItemInfo(m_info->absolutePath());
543+ if (other->isValid())
544+ {
545+ delete m_info;
546+ m_info = other;
547+ ret = true;
548+ }
549+ else
550+ {
551+ delete other;
552+ }
553+ }
554+ return ret;
555+}
556+
557+
558+void DiskLocation::refreshInfo()
559+{
560+ if (m_info)
561+ {
562+ DirItemInfo *item = new DirItemInfo(m_info->absoluteFilePath());
563+ delete m_info;
564+ m_info = item;
565+ }
566+}
567+
568+
569+/*!
570+ * \brief DiskLocation::stopExternalFsWatcher() stops the External File System Watcher
571+ */
572+void DiskLocation::stopExternalFsWatcher()
573+{
574+ if (m_extWatcher)
575+ {
576+ DEBUG_WATCHER();
577+ delete m_extWatcher;
578+ m_extWatcher = 0;
579+ }
580+}
581+
582+
583+/*!
584+ * \brief DiskLocation::startExternalFsWatcher() starts the External File System Watcher
585+ */
586+void DiskLocation::startExternalFsWatcher()
587+{
588+ if (m_extWatcher == 0)
589+ {
590+ DEBUG_WATCHER();
591+ m_extWatcher = new ExternalFSWatcher(this);
592+ m_extWatcher->setIntervalToNotifyChanges(EX_FS_WATCHER_TIMER_INTERVAL);
593+
594+ connect(m_extWatcher, SIGNAL(pathModified(QString)),
595+ this, SIGNAL(extWatcherPathChanged(QString)));
596+ if (m_info)
597+ { //setCurrentPath() checks for empty paths
598+ m_extWatcher->setCurrentPath(m_info->absoluteFilePath());
599+ }
600+ }
601+}
602+
603+
604+void DiskLocation::onItemsFetched()
605+{
606+ if (m_extWatcher)
607+ {
608+ m_extWatcher->setCurrentPath(m_info->absoluteFilePath());
609+ }
610+ emit itemsFetched();
611+}
612+
613+
614+void DiskLocation::startWorking()
615+{
616+ if (m_usingExternalWatcher)
617+ {
618+ startExternalFsWatcher();
619+ }
620+}
621+
622+
623+void DiskLocation::stopWorking()
624+{
625+ stopExternalFsWatcher();
626+}
627+
628+
629+void DiskLocation::fetchExternalChanges(const QString &path,
630+ const DirItemInfoList &list,
631+ QDir::Filter dirFilter)
632+{
633+ ExternalFileSystemChangesWorker *extFsWorker =
634+ new ExternalFileSystemChangesWorker(list,
635+ path,
636+ dirFilter, false);
637+ addExternalFsWorkerRequest(extFsWorker);
638+
639+
640+}
641+
642+void DiskLocation::addExternalFsWorkerRequest(ExternalFileSystemChangesWorker *extFsWorker)
643+{
644+ connect(extFsWorker, SIGNAL(added(DirItemInfo)),
645+ this, SIGNAL(extWatcherItemAdded(DirItemInfo)));
646+
647+ connect(extFsWorker, SIGNAL(removed(DirItemInfo)),
648+ this, SIGNAL(extWatcherItemRemoved(DirItemInfo)));
649+
650+ connect(extFsWorker, SIGNAL(changed(DirItemInfo)),
651+ this, SIGNAL(extWatcherItemChanged(DirItemInfo)));
652+
653+ connect(extFsWorker, SIGNAL(finished(int)),
654+ this, SIGNAL(extWatcherChangesFetched(int)));
655+
656+ workerThread()->addRequest(extFsWorker);
657+}
658+
659+
660+ExternalFSWatcher * DiskLocation::getExternalFSWatcher() const
661+{
662+ return m_extWatcher;
663+}
664+
665+
666+void DiskLocation::setUsingExternalWatcher(bool use)
667+{
668+ Location::setUsingExternalWatcher(use);
669+ if (m_usingExternalWatcher)
670+ {
671+ startExternalFsWatcher();
672+ }
673+ else
674+ {
675+ stopExternalFsWatcher();
676+ }
677+}
678+
679+
680+DirItemInfo * DiskLocation::validateUrlPath(const QString& uPath)
681+{
682+ QString myPath(uPath);
683+ QFileInfo tmpUrl(uPath);
684+ if (tmpUrl.isRelative() && m_info)
685+ {
686+ tmpUrl.setFile(m_info->absoluteFilePath(), uPath);
687+ myPath = tmpUrl.absoluteFilePath();
688+ }
689+#if DEBUG_MESSAGES
690+ qDebug() << Q_FUNC_INFO << "path:" << myPath;
691+#endif
692+ DirItemInfo * item = new DirItemInfo(myPath);
693+ if (!item->isValid() || !item->exists() || !item->isContentReadable())
694+ {
695+ delete item;
696+ item = 0;
697+ }
698+ return item;
699+}
700
701=== added file 'src/plugin/folderlistmodel/disk/disklocation.h'
702--- src/plugin/folderlistmodel/disk/disklocation.h 1970-01-01 00:00:00 +0000
703+++ src/plugin/folderlistmodel/disk/disklocation.h 2014-05-15 23:31:23 +0000
704@@ -0,0 +1,81 @@
705+/**************************************************************************
706+ *
707+ * Copyright 2014 Canonical Ltd.
708+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
709+ *
710+ * This program is free software; you can redistribute it and/or modify
711+ * it under the terms of the GNU Lesser General Public License as published by
712+ * the Free Software Foundation; version 3.
713+ *
714+ * This program is distributed in the hope that it will be useful,
715+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
716+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
717+ * GNU Lesser General Public License for more details.
718+ *
719+ * You should have received a copy of the GNU Lesser General Public License
720+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
721+ *
722+ * File: disklocation.h
723+ * Date: 08/03/2014
724+ */
725+
726+#ifndef DISKLOCATION_H
727+#define DISKLOCATION_H
728+
729+#include "location.h"
730+#include <QList>
731+
732+/*!
733+ * When the External File System Wathcer is enabled,
734+ * this is the interval used to check if there has been any change in the current path
735+ *
736+ * \sa setEnabledExternalFSWatcher()
737+ */
738+#define EX_FS_WATCHER_TIMER_INTERVAL 900
739+
740+
741+class ExternalFSWatcher;
742+class ExternalFileSystemChangesWorker;
743+
744+/*!
745+ * \brief The DiskLocation class extends \ref Location for Local Disk and provides a External File System watcher
746+ */
747+class DiskLocation : public Location
748+{
749+ Q_OBJECT
750+public:
751+ explicit DiskLocation(int type, QObject *parent=0);
752+ virtual ~DiskLocation();
753+
754+ ExternalFSWatcher * getExternalFSWatcher() const;
755+
756+ virtual void fetchItems(QDir::Filter dirFilter, bool recursive = false) ;
757+ virtual void fetchExternalChanges(const QString& urlPath,
758+ const DirItemInfoList& list,
759+ QDir::Filter dirFilter) ;
760+ virtual bool becomeParent();
761+ virtual void refreshInfo();
762+
763+ virtual void startExternalFsWatcher();
764+ virtual void stopExternalFsWatcher();
765+
766+ virtual void startWorking();
767+ virtual void stopWorking();
768+
769+ virtual DirItemInfo *validateUrlPath(const QString& urlPath);
770+
771+protected:
772+ void addExternalFsWorkerRequest(ExternalFileSystemChangesWorker *);
773+
774+public slots:
775+ virtual void setUsingExternalWatcher(bool use);
776+
777+protected slots:
778+ void onItemsFetched();
779+
780+protected:
781+ ExternalFSWatcher * m_extWatcher ;
782+
783+};
784+
785+#endif // DISKLOCATION_H
786
787=== modified file 'src/plugin/folderlistmodel/filecompare.cpp'
788--- src/plugin/folderlistmodel/filecompare.cpp 2014-02-05 15:31:44 +0000
789+++ src/plugin/folderlistmodel/filecompare.cpp 2014-05-15 23:31:23 +0000
790@@ -50,11 +50,10 @@
791 if (b.isDir() && !a.isDir())
792 return false;
793
794- bool ret = QString::localeAwareCompare(a.fileName(), b.fileName()) < 0;
795+ bool ret = QString::localeAwareCompare(a.absoluteFilePath(), b.absoluteFilePath()) < 0;
796 #if DEBUG_MESSAGES
797- qDebug() << Q_FUNC_INFO << ret << a.fileName() << b.fileName();
798+ qDebug() << Q_FUNC_INFO << ret << a.absoluteFilePath() << b.absoluteFilePath();
799 #endif
800-
801 return ret;
802 }
803
804
805=== modified file 'src/plugin/folderlistmodel/folderlistmodel.pri'
806--- src/plugin/folderlistmodel/folderlistmodel.pri 2014-02-10 23:41:50 +0000
807+++ src/plugin/folderlistmodel/folderlistmodel.pri 2014-05-15 23:31:23 +0000
808@@ -9,7 +9,12 @@
809 $$PWD/fmutil.cpp \
810 $$PWD/dirselection.cpp \
811 $$PWD/diriteminfo.cpp \
812- $$PWD/trash/qtrashdir.cpp
813+ $$PWD/trash/qtrashdir.cpp \
814+ $$PWD/location.cpp \
815+ $$PWD/locationsfactory.cpp \
816+ $$PWD/disk/disklocation.cpp \
817+ $$PWD/locationurl.cpp \
818+
819
820
821 HEADERS += $$PWD/dirmodel.h \
822@@ -24,10 +29,14 @@
823 $$PWD/dirselection.h \
824 $$PWD/diritemabstractlistmodel.h \
825 $$PWD/diriteminfo.h \
826- $$PWD/trash/qtrashdir.h
827-
828-
829-INCLUDEPATH += $$PWD $$PWD/trash
830+ $$PWD/trash/qtrashdir.h \
831+ $$PWD/location.h \
832+ $$PWD/locationsfactory.h \
833+ $$PWD/disk/disklocation.h \
834+ $$PWD/locationurl.h \
835+
836+
837+INCLUDEPATH += $$PWD $$PWD/trash $$PWD/disk
838
839 greaterThan(QT_MAJOR_VERSION, 4) {
840 QT += qml
841
842=== added file 'src/plugin/folderlistmodel/location.cpp'
843--- src/plugin/folderlistmodel/location.cpp 1970-01-01 00:00:00 +0000
844+++ src/plugin/folderlistmodel/location.cpp 2014-05-15 23:31:23 +0000
845@@ -0,0 +1,140 @@
846+/**************************************************************************
847+ *
848+ * Copyright 2014 Canonical Ltd.
849+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
850+ *
851+ * This program is free software; you can redistribute it and/or modify
852+ * it under the terms of the GNU Lesser General Public License as published by
853+ * the Free Software Foundation; version 3.
854+ *
855+ * This program is distributed in the hope that it will be useful,
856+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
857+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
858+ * GNU Lesser General Public License for more details.
859+ *
860+ * You should have received a copy of the GNU Lesser General Public License
861+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
862+ *
863+ * File: location.cpp
864+ * Date: 08/03/2014
865+ */
866+/**************************************************************************
867+ *
868+ * Copyright 2014 Canonical Ltd.
869+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
870+ *
871+ * This program is free software; you can redistribute it and/or modify
872+ * it under the terms of the GNU Lesser General Public License as published by
873+ * the Free Software Foundation; version 3.
874+ *
875+ * This program is distributed in the hope that it will be useful,
876+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
877+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
878+ * GNU Lesser General Public License for more details.
879+ *
880+ * You should have received a copy of the GNU Lesser General Public License
881+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
882+ *
883+ * File: locations.cpp
884+ * Date: 04/03/2014
885+ */
886+
887+#include "location.h"
888+#include "ioworkerthread.h"
889+
890+Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread)
891+
892+
893+Location::Location(int type, QObject *parent)
894+ : QObject(parent)
895+ , m_info(0)
896+ , m_type(type)
897+ , m_usingExternalWatcher(false)
898+{
899+
900+}
901+
902+Location::~Location()
903+{
904+ if (m_info)
905+ {
906+ delete m_info;
907+ m_info = 0;
908+ }
909+}
910+
911+
912+bool Location::isRoot() const
913+{
914+ return m_info ? m_info->isRoot() : false;
915+}
916+
917+
918+bool Location::isWritable() const
919+{
920+ return m_info->isWritable();
921+}
922+
923+
924+bool Location::isReadable() const
925+{
926+ return m_info ? m_info->isContentReadable() : false;
927+}
928+
929+void Location::setInfoItem(const DirItemInfo &itemInfo)
930+{
931+ setInfoItem (new DirItemInfo(itemInfo));
932+}
933+
934+void Location::setInfoItem(DirItemInfo *itemInfo)
935+{
936+ if (m_info)
937+ {
938+ delete m_info;
939+ }
940+ m_info = itemInfo;
941+}
942+
943+
944+QString Location::urlPath() const
945+{
946+ return m_info ? m_info->urlPath(): QString();
947+}
948+
949+
950+void Location::startWorking()
951+{
952+
953+}
954+
955+void Location::stopWorking()
956+{
957+
958+}
959+
960+bool Location::becomeParent()
961+{
962+ return false;
963+}
964+
965+IOWorkerThread * Location::workerThread() const
966+{
967+ return ioWorkerThread();
968+}
969+
970+
971+//providing an empty method
972+void Location::fetchExternalChanges(const QString &path,
973+ const DirItemInfoList &list,
974+ QDir::Filter dirFilter)
975+{
976+ Q_UNUSED(path);
977+ Q_UNUSED(list);
978+ Q_UNUSED(dirFilter);
979+}
980+
981+
982+void Location::setUsingExternalWatcher(bool use)
983+{
984+ m_usingExternalWatcher = use;
985+}
986
987=== added file 'src/plugin/folderlistmodel/location.h'
988--- src/plugin/folderlistmodel/location.h 1970-01-01 00:00:00 +0000
989+++ src/plugin/folderlistmodel/location.h 2014-05-15 23:31:23 +0000
990@@ -0,0 +1,132 @@
991+/**************************************************************************
992+ *
993+ * Copyright 2014 Canonical Ltd.
994+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
995+ *
996+ * This program is free software; you can redistribute it and/or modify
997+ * it under the terms of the GNU Lesser General Public License as published by
998+ * the Free Software Foundation; version 3.
999+ *
1000+ * This program is distributed in the hope that it will be useful,
1001+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1002+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1003+ * GNU Lesser General Public License for more details.
1004+ *
1005+ * You should have received a copy of the GNU Lesser General Public License
1006+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1007+ *
1008+ * File: location.h
1009+ * Date: 08/03/2014
1010+ */
1011+
1012+#ifndef LOCATION_H
1013+#define LOCATION_H
1014+
1015+#include "diriteminfo.h"
1016+
1017+#include <QObject>
1018+
1019+class IOWorkerThread;
1020+
1021+/*!
1022+ * \brief The Location class represents any location (full path) where there are items to browse: directories, shares, from Disk and from Network.
1023+ *
1024+ * It is an abstract class the must be inherited for specific Location handling as example: \ref DiskLocation and \ref TrashLocation
1025+ *
1026+ * The location must be able to:
1027+ * \li provide the browsing for the location in \ref fetchItems()
1028+ * \li become itself its parent in \ref becomeParent() it will allow easy \ref DirModel::cdUp()
1029+ * \li refresh its information in \ref refreshInfo()
1030+ * \li validate its location (creates a valid DirItemInfo object or any descendent) from a url string
1031+ *
1032+ * The \ref startWorking() is called by \ref LocationsFactory just before this location becomes the current in the File Manager
1033+ * In the same way the \ref stopWorking() is called by \ref LocationsFactory just before this location no longer be the current in the File Manager
1034+ */
1035+class Location : public QObject
1036+{
1037+ Q_OBJECT
1038+public:
1039+ explicit Location( int type, QObject *parent=0);
1040+ virtual ~Location();
1041+
1042+ IOWorkerThread * workerThread() const;
1043+
1044+signals:
1045+ void itemsAdded(const DirItemInfoList &files);
1046+ void itemsFetched();
1047+ void extWatcherPathChanged(const QString&);
1048+ void extWatcherItemRemoved(const DirItemInfo&);
1049+ void extWatcherItemChanged(const DirItemInfo&);
1050+ void extWatcherItemAdded(const DirItemInfo&);
1051+ void extWatcherChangesFetched(int);
1052+
1053+public slots:
1054+ virtual void setUsingExternalWatcher(bool use);
1055+
1056+public: //pure functions
1057+ /*!
1058+ * \brief fetchItems() gets the content of the Location
1059+ *
1060+ * \param dirFilter current Filter
1061+ * \param recursive should get the content all sub dirs or not, (hardly ever it is true)
1062+ */
1063+ virtual void fetchItems(QDir::Filter dirFilter, bool recursive=0) = 0;
1064+
1065+ /*!
1066+ * \brief refreshInfo() It must refresh the DirItemInfo
1067+ *
1068+ * It can be used for example after receiving the signal about external disk file system changes
1069+ * due to the current path permissions might have changed.
1070+ */
1071+ virtual void refreshInfo() = 0;
1072+
1073+ /*!
1074+ * \brief becomeParent() The current path location becomes the parent Location
1075+ *
1076+ * When \ref isRoot() returns false the current path location becomes the parent path location
1077+ * in order to make it the current.
1078+ * It acts like a cdUp, but without fetching items; then calling \ref fetchItems() may get contents.
1079+ *
1080+ * \note It must take care of deleting \ref m_info when creating a new DirItemInfo/TrashItemInfo etc.
1081+ *
1082+ * \return true if it is possible to do like a cdUp.
1083+ */
1084+ virtual bool becomeParent() = 0;
1085+
1086+ /*!
1087+ * \brief validateUrlPath() Validates the urlPath (file or Directory) and creates a new Obeject from this path
1088+ *
1089+ * If urlPath is a valid Directory it can be used later to set a new Location.
1090+ *
1091+ * \param urlPath
1092+ * \return a valid pointer to DirItemInfo object or NULL indicating something wrong with the path
1093+ */
1094+ virtual DirItemInfo * validateUrlPath(const QString& urlPath) = 0;
1095+
1096+public:
1097+ virtual void fetchExternalChanges(const QString& urlPath,
1098+ const DirItemInfoList& list,
1099+ QDir::Filter dirFilter) ;
1100+ virtual void setInfoItem(const DirItemInfo &itemInfo);
1101+ virtual void setInfoItem(DirItemInfo *itemInfo);
1102+ virtual bool isRoot() const;
1103+ virtual bool isWritable() const;
1104+ virtual bool isReadable() const;
1105+ virtual QString urlPath() const;
1106+ virtual void startWorking();
1107+ virtual void stopWorking();
1108+
1109+ inline const DirItemInfo* info() const { return m_info; }
1110+ inline int type() const { return m_type; }
1111+
1112+protected:
1113+ DirItemInfo * m_info;
1114+ int m_type;
1115+ bool m_usingExternalWatcher;
1116+
1117+#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
1118+ friend class TestDirModel;
1119+#endif
1120+
1121+};
1122+#endif // LOCATION_H
1123
1124=== added file 'src/plugin/folderlistmodel/locationsfactory.cpp'
1125--- src/plugin/folderlistmodel/locationsfactory.cpp 1970-01-01 00:00:00 +0000
1126+++ src/plugin/folderlistmodel/locationsfactory.cpp 2014-05-15 23:31:23 +0000
1127@@ -0,0 +1,181 @@
1128+/**************************************************************************
1129+ *
1130+ * Copyright 2014 Canonical Ltd.
1131+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1132+ *
1133+ * This program is free software; you can redistribute it and/or modify
1134+ * it under the terms of the GNU Lesser General Public License as published by
1135+ * the Free Software Foundation; version 3.
1136+ *
1137+ * This program is distributed in the hope that it will be useful,
1138+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1139+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1140+ * GNU Lesser General Public License for more details.
1141+ *
1142+ * You should have received a copy of the GNU Lesser General Public License
1143+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1144+ *
1145+ * File: locationsfactory.cpp
1146+ * Date: 05/03/2014
1147+ */
1148+
1149+#include "diriteminfo.h"
1150+#include "locationsfactory.h"
1151+#include "location.h"
1152+#include "locationurl.h"
1153+#include "disklocation.h"
1154+
1155+
1156+#include <QDir>
1157+#include <QDebug>
1158+
1159+
1160+
1161+LocationsFactory::LocationsFactory(QObject *parent)
1162+ : QObject(parent)
1163+ , m_curLoc(0)
1164+ , m_lastValidFileInfo(0)
1165+{
1166+ m_locations.append(new DiskLocation(LocalDisk));
1167+}
1168+
1169+
1170+LocationsFactory::~LocationsFactory()
1171+{
1172+ ::qDeleteAll(m_locations);
1173+ m_locations.clear();
1174+}
1175+
1176+
1177+/*!
1178+ * \brief LocationsFactory::parse() identifies what main location that path/url refers to
1179+ * \param path it is supposed to be always a full path like: file:///myDir /myDir trash:/// trash:///myDir
1180+ * \return
1181+ */
1182+
1183+Location * LocationsFactory::parse(const QString& uPath)
1184+{
1185+ int index = -1;
1186+ int type = -1;
1187+ Location * location = 0;
1188+ if ( (index = uPath.indexOf(QChar(':'))) != -1 )
1189+ {
1190+#if defined(Q_OS_WIN)
1191+#else
1192+#if defined(Q_OS_UNIX)
1193+ if (uPath.startsWith(LocationUrl::TrashRootURL.midRef(0,6)))
1194+ {
1195+ type = TrashDisk;
1196+ m_tmpPath = LocationUrl::TrashRootURL + stringAfterSlashes(uPath, index+1);
1197+ }
1198+ else
1199+#endif //Q_OS_UNIX
1200+#endif //Q_OS_UNIX
1201+ if (uPath.startsWith(LocationUrl::DiskRootURL.midRef(0,5)))
1202+ {
1203+ type = LocalDisk;
1204+ m_tmpPath = QDir::rootPath() + stringAfterSlashes(uPath, index+1);
1205+ }
1206+ }
1207+ else
1208+ {
1209+ m_tmpPath = stringAfterSlashes(uPath, -1);
1210+ type = LocalDisk;
1211+ if (!m_tmpPath.startsWith(QDir::rootPath()) && m_curLoc)
1212+ {
1213+ //it can be any, check current location
1214+ type = m_curLoc->type();
1215+ }
1216+ }
1217+ if (!m_tmpPath.isEmpty() && type != -1)
1218+ {
1219+ location = m_locations.at(type);
1220+ }
1221+#if DEBUG_MESSAGES
1222+ qDebug() << Q_FUNC_INFO << "input path:" << uPath << "location result:" << location;
1223+#endif
1224+ return location;
1225+}
1226+
1227+
1228+Location * LocationsFactory::setNewPath(const QString& uPath)
1229+{
1230+ storeValidFileInfo(0);
1231+ Location *location = parse(uPath);
1232+ if (location)
1233+ {
1234+ DirItemInfo *item = location->validateUrlPath(m_tmpPath);
1235+ if (item)
1236+ {
1237+ //isContentReadable() must already carry execution permission
1238+ if (item->isValid() && item->isDir() && item->isContentReadable())
1239+ {
1240+ location->setInfoItem(item);
1241+ if (location != m_curLoc)
1242+ {
1243+ if (m_curLoc)
1244+ {
1245+ m_curLoc->stopWorking();
1246+ }
1247+ emit locationChanged(m_curLoc, location);
1248+ location->startWorking();
1249+ m_curLoc = location;
1250+ }
1251+ }
1252+ else
1253+ {
1254+ storeValidFileInfo(item);
1255+ }
1256+ }
1257+ else
1258+ { // not valid
1259+ location = 0;
1260+ }
1261+ }
1262+#if DEBUG_MESSAGES
1263+ qDebug() << Q_FUNC_INFO << "input path:" << uPath << "location result:" << location;
1264+#endif
1265+ return location;
1266+}
1267+
1268+
1269+QString LocationsFactory::stringAfterSlashes(const QString &url, int firstSlashIndex) const
1270+{
1271+ QString ret;
1272+ if (firstSlashIndex >=0)
1273+ {
1274+ while ( firstSlashIndex < url.length() && url.at(firstSlashIndex) == QDir::separator())
1275+ {
1276+ ++firstSlashIndex;
1277+ }
1278+ if (firstSlashIndex < url.length())
1279+ {
1280+ ret = url.mid(firstSlashIndex);
1281+ }
1282+ }
1283+ else
1284+ {
1285+ ret = url;
1286+ firstSlashIndex = 0;
1287+ }
1288+ //replace any double slashes by just one
1289+ for(int charCounter = ret.size() -1; charCounter > 0; --charCounter)
1290+ {
1291+ if (ret.at(charCounter) == QDir::separator() &&
1292+ ret.at(charCounter-1) == QDir::separator())
1293+ {
1294+ ret.remove(charCounter,1);
1295+ }
1296+ }
1297+ return ret;
1298+}
1299+
1300+
1301+void LocationsFactory::storeValidFileInfo(const DirItemInfo *item)
1302+{
1303+ if (m_lastValidFileInfo)
1304+ {
1305+ delete m_lastValidFileInfo;
1306+ }
1307+ m_lastValidFileInfo = item;
1308+}
1309
1310=== added file 'src/plugin/folderlistmodel/locationsfactory.h'
1311--- src/plugin/folderlistmodel/locationsfactory.h 1970-01-01 00:00:00 +0000
1312+++ src/plugin/folderlistmodel/locationsfactory.h 2014-05-15 23:31:23 +0000
1313@@ -0,0 +1,136 @@
1314+/**************************************************************************
1315+ *
1316+ * Copyright 2014 Canonical Ltd.
1317+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1318+ *
1319+ * This program is free software; you can redistribute it and/or modify
1320+ * it under the terms of the GNU Lesser General Public License as published by
1321+ * the Free Software Foundation; version 3.
1322+ *
1323+ * This program is distributed in the hope that it will be useful,
1324+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1325+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1326+ * GNU Lesser General Public License for more details.
1327+ *
1328+ * You should have received a copy of the GNU Lesser General Public License
1329+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1330+ *
1331+ * File: locationsfactory.h
1332+ * Date: 05/03/2014
1333+ */
1334+
1335+#ifndef LOCATIONSFACTORY_H
1336+#define LOCATIONSFACTORY_H
1337+
1338+#include <QObject>
1339+#include <QList>
1340+
1341+
1342+class Location;
1343+class DirItemInfo;
1344+
1345+/*!
1346+ * \brief The LocationsFactory class represents the set of main
1347+ * URL locations the File Manager supports.
1348+ *
1349+ * It is basically devided into main groups:
1350+ * \li Disk: \ref LocalDisk and \ref TrashDisk
1351+ * \li Net: \ref NetSambaShare and NetFishShare
1352+ *
1353+ * smb:// browses workgroup
1354+ *
1355+ * Location parser: \ref parser()
1356+ * \li \\workkgroup becomes smb://workgroup
1357+ * \li \\ becomes smb://
1358+ * \li trash:/ and trash:// becomes trash:///
1359+ * \li fish:/ and fish:// becomes fish:///
1360+ * \li file:/ , file:// and file:/// becomes /
1361+ *
1362+ * \note Due to current File Manager UI typing method both: "file:" and "trash:" are supported
1363+ */
1364+class LocationsFactory : public QObject
1365+{
1366+ Q_OBJECT
1367+public:
1368+ explicit LocationsFactory(QObject *parent = 0);
1369+ ~LocationsFactory();
1370+
1371+ Q_ENUMS(Locations)
1372+ enum Locations
1373+ {
1374+ LocalDisk, //<! any mounted file system
1375+ TrashDisk //<! special trash location in the disk
1376+#if 0
1377+ NetSambaShare //<! SAMBA or CIFS shares
1378+ NetFishShare //<! FISH protocol over ssh that provides file sharing
1379+#endif
1380+ };
1381+
1382+ inline const Location * getLocation(Locations index) const {return m_locations.at(index);}
1383+
1384+
1385+ /*!
1386+ * \brief parse() Just parses (does not set/change the current location) according to \a urlPath
1387+ * \param urlPath urlPath the url like: file:///Item trash:///item /item, it MUST point to a valid Directory
1388+ * \return The location which supports the \a urlPath
1389+ */
1390+ Location * parse(const QString& urlPath);
1391+
1392+ /*!
1393+ * \brief setNewPath() Sets a new path, it can be in the current location or on another location
1394+ *
1395+ * When the location changes, the signal \ref locationChanged() is fired.
1396+ *
1397+ * \param urlPath the url like: file:///Item trash:///item /item, it MUST point to a valid Directory
1398+ * \return the location that supports the urlPath or NULL when \a urlPath is NOT a valid url or it is not a valid Directory
1399+ *
1400+ * \sa \ref parse() \ref location()
1401+ */
1402+ Location * setNewPath(const QString& urlPath);
1403+
1404+ /*!
1405+ * \brief location()
1406+ * \return The current location
1407+ */
1408+ Location * location() const { return m_curLoc; }
1409+
1410+ /*!
1411+ * \brief availableLocations()
1412+ * \return
1413+ */
1414+ const QList<Location*>&
1415+ availableLocations() const { return m_locations; }
1416+
1417+ /*!
1418+ * \brief lastValidFileInfo()
1419+ *
1420+ * When calling setNewPath(file_path) using a path to a File instead of a Directory
1421+ * the setNewPath() is not able to set a new path (current location or other), however it uses
1422+ * Location::validateUrlPath() which validates the path for files also, then this valid DirItemInfo object
1423+ * is saved using \ref storeValidFileInfo() for further use.
1424+ *
1425+ * \return The last valid DirItemInfo parsed which is not a Directory
1426+ */
1427+ const DirItemInfo* lastValidFileInfo() const { return m_lastValidFileInfo; }
1428+
1429+ void storeValidFileInfo(const DirItemInfo *item);
1430+
1431+signals:
1432+ void locationChanged(const Location *old, const Location *current);
1433+
1434+private:
1435+ QString stringAfterSlashes(const QString& url, int firstSlashIndex) const;
1436+
1437+private:
1438+ Location * m_curLoc;
1439+ QList<Location*> m_locations;
1440+ QString m_tmpPath;
1441+ const DirItemInfo * m_lastValidFileInfo;
1442+
1443+#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
1444+ friend class TestDirModel;
1445+#endif
1446+
1447+};
1448+
1449+#endif // LOCATIONSFACTORY_H
1450
1451=== added file 'src/plugin/folderlistmodel/locationurl.cpp'
1452--- src/plugin/folderlistmodel/locationurl.cpp 1970-01-01 00:00:00 +0000
1453+++ src/plugin/folderlistmodel/locationurl.cpp 2014-05-15 23:31:23 +0000
1454@@ -0,0 +1,34 @@
1455+/**************************************************************************
1456+ *
1457+ * Copyright 2014 Canonical Ltd.
1458+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1459+ *
1460+ * This program is free software; you can redistribute it and/or modify
1461+ * it under the terms of the GNU Lesser General Public License as published by
1462+ * the Free Software Foundation; version 3.
1463+ *
1464+ * This program is distributed in the hope that it will be useful,
1465+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1466+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1467+ * GNU Lesser General Public License for more details.
1468+ *
1469+ * You should have received a copy of the GNU Lesser General Public License
1470+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1471+ *
1472+ * File: locationurl.cpp
1473+ * Date: 11/03/2014
1474+ */
1475+
1476+#include "locationurl.h"
1477+
1478+const QString LocationUrl::TrashRootURL("trash:///");
1479+const QString LocationUrl::DiskRootURL("file:///");
1480+#if 0
1481+QString LocationURL::SmbURL("smb://");
1482+QString LocationURL::FishURL("fish:///");
1483+#endif
1484+
1485+
1486+LocationUrl::LocationUrl()
1487+{
1488+}
1489
1490=== added file 'src/plugin/folderlistmodel/locationurl.h'
1491--- src/plugin/folderlistmodel/locationurl.h 1970-01-01 00:00:00 +0000
1492+++ src/plugin/folderlistmodel/locationurl.h 2014-05-15 23:31:23 +0000
1493@@ -0,0 +1,40 @@
1494+/**************************************************************************
1495+ *
1496+ * Copyright 2014 Canonical Ltd.
1497+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1498+ *
1499+ * This program is free software; you can redistribute it and/or modify
1500+ * it under the terms of the GNU Lesser General Public License as published by
1501+ * the Free Software Foundation; version 3.
1502+ *
1503+ * This program is distributed in the hope that it will be useful,
1504+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1505+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1506+ * GNU Lesser General Public License for more details.
1507+ *
1508+ * You should have received a copy of the GNU Lesser General Public License
1509+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1510+ *
1511+ * File: locationurl.h
1512+ * Date: 11/03/2014
1513+ */
1514+
1515+#ifndef LOCATIONURL_H
1516+#define LOCATIONURL_H
1517+
1518+#include <QString>
1519+
1520+class LocationUrl
1521+{
1522+public:
1523+ static const QString DiskRootURL;
1524+ static const QString TrashRootURL;
1525+#if 0
1526+ static const QString SmbURL;
1527+ static const QString FishURL;
1528+#endif
1529+private:
1530+ LocationUrl();
1531+};
1532+
1533+#endif // LOCATIONURL_H
1534
1535=== modified file 'src/plugin/test_folderlistmodel/regression/tst_folderlistmodel.cpp'
1536--- src/plugin/test_folderlistmodel/regression/tst_folderlistmodel.cpp 2014-05-15 23:31:22 +0000
1537+++ src/plugin/test_folderlistmodel/regression/tst_folderlistmodel.cpp 2014-05-15 23:31:23 +0000
1538@@ -3,7 +3,11 @@
1539 #include "tempfiles.h"
1540 #include "externalfswatcher.h"
1541 #include "dirselection.h"
1542-#include "trash/qtrashdir.h"
1543+#include "qtrashdir.h"
1544+#include "location.h"
1545+#include "locationurl.h"
1546+#include "locationsfactory.h"
1547+#include "disklocation.h"
1548
1549 #if defined(Q_OS_UNIX)
1550 #include <stdio.h>
1551@@ -143,6 +147,8 @@
1552 void modelSelectionItemsRange();
1553
1554 void trashDiretories();
1555+ void locationFactory();
1556+
1557
1558 private:
1559 void initDeepDirs();
1560@@ -2389,6 +2395,45 @@
1561 }
1562
1563
1564+void TestDirModel::locationFactory()
1565+{
1566+ LocationsFactory factoryLocations(this);
1567+ const Location *location = 0;
1568+
1569+ //Due to current File Manager UI typing method both: "file:" and "trash:" are supported
1570+ // location = factoryLocations.setNewPath("trash:");
1571+ // QVERIFY(location == 0);
1572+
1573+ location = factoryLocations.setNewPath("file://////");
1574+ QVERIFY(location);
1575+ QVERIFY(location->type() == LocationsFactory::LocalDisk);
1576+ QCOMPARE(location->info()->absoluteFilePath(), QDir::rootPath());
1577+ QCOMPARE(location->urlPath(), QDir::rootPath());
1578+ QCOMPARE(location->isRoot(), true);
1579+
1580+ location = factoryLocations.setNewPath("/");
1581+ QVERIFY(location);
1582+ QVERIFY(location->type() == LocationsFactory::LocalDisk);
1583+ QCOMPARE(location->info()->absoluteFilePath(), QDir::rootPath());
1584+ QCOMPARE(location->urlPath(), QDir::rootPath());
1585+ QCOMPARE(location->isRoot(), true);
1586+
1587+ location = factoryLocations.setNewPath("//");
1588+ QVERIFY(location);
1589+ QVERIFY(location->type() == LocationsFactory::LocalDisk);
1590+ QCOMPARE(location->info()->absoluteFilePath(), QDir::rootPath());
1591+ QCOMPARE(location->urlPath(), QDir::rootPath());
1592+ QCOMPARE(location->isRoot(), true);
1593+
1594+ location = factoryLocations.setNewPath("//bin");
1595+ QVERIFY(location);
1596+ QVERIFY(location->type() == LocationsFactory::LocalDisk);
1597+ QCOMPARE(location->info()->absoluteFilePath(), QLatin1String("/bin"));
1598+ QCOMPARE(location->urlPath(), QLatin1String("/bin"));
1599+ QCOMPARE(location->isRoot(), false);
1600+}
1601+
1602+
1603 int main(int argc, char *argv[])
1604 {
1605 QApplication app(argc, argv);

Subscribers

People subscribed via source and target branches