PDA

View Full Version : Suggestions/Ideas about a file browser



SkripT
4th April 2006, 09:49
Hi all, one of the options in my application is to browse all the images in a specified directory and move them to other directories (that could not exist). I have some ideas but I will be thankfully if you give me some other ideas before I program it. The only restriction is that the re-ubication of the image files has to be in a simple way like a drag-and-drop. I have thought in having a QListWidget with a thumbnailing of all the images in the "source" directory. This directory is inserted in a QLineEdit or chosen using a button connected to QFileDialog::getExistingDirectory. For the destination folder I have thought in having the same widgets: a list view, a line edit and the button. So the user only should has to select the destination folder and drag and drop all the files from the source directory to the destination. Another posssiblity could be in replacing the QListWidget in the destination for a tree showing the file system giving the possiblity to create new directories and drag the list widget items of the source directory to an entry of this tree. I don't know if this could be possible. I also have thought in having another tree in the source folder too... Anyway, what do you suggest me?

Thanks.

SkripT
4th April 2006, 12:43
Hi again, I've thought in another solution: having a QDirModel with a tree structure showing the dirs of the file system in one place and on the other place a QListWidget that will contains the thumbnailed images for the current/selected directory in the dir model. I have some questions about it:
1) To copy image files between directories, is possible to drag QListWidgetItems from the list widget to drop them in a directory entry of the dir model?
2) Is possible to show a menu when the user clicks with the right button of the mouse an entry of the dir model? This menu will show the actions to do with a directory: rename it, delete it, create sub-directory, view the images in the list widget, ...

jpn
4th April 2006, 13:06
I'd say, forget about the QListWidget and use a QDirModel+QListView instead..

SkripT
4th April 2006, 13:11
I'd say, forget about the QListWidget and use a QDirModel+QListView instead..

jpn I appreciate your suggestion but can you give me some reasons and how you think that I should use the list view?

jpn
4th April 2006, 14:08
Because it's this simple:


#include <QtGui>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

// a "file manager" at simplest :)
QSplitter* splitter = new QSplitter;
QDirModel* model = new QDirModel;
QTreeView* tree = new QTreeView(splitter);
tree->setModel(model);
QListView* list = new QListView(splitter);
list->setModel(model);
list->setDragEnabled(true);
splitter->show();

// tree navigation by click
QObject::connect(tree, SIGNAL(clicked(const QModelIndex&)),
list, SLOT(setRootIndex(const QModelIndex&)));
// list navigation by dbl click
QObject::connect(list, SIGNAL(doubleClicked(const QModelIndex&)),
list, SLOT(setRootIndex(const QModelIndex&)));
// update tree upon list change
QObject::connect(list, SIGNAL(doubleClicked(const QModelIndex&)),
tree, SLOT(setCurrentIndex(const QModelIndex&)));

a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
return a.exec();
}


Notice the amount of code :) ..with this, you can already drag'n drop a file from the list view to e.g. desktop..

SkripT
4th April 2006, 15:10
Cool jpn thanks :D , where have you get this example? Is it from your creation?

jpn
4th April 2006, 15:22
No problem. Yep, I did it myself..
It's not a complete solution, just a small example demonstrating the power of QDirModel :)

Lemming
4th April 2006, 15:22
You can further improve the above implementation by setting the file icon provider for your list to show the thumbnails for your images in the list. Refer to the QFileIconProvider class in QT documentation. Implementing the icon provider for the thumbnails will look like this:



QIcon MyIconProvider::icon ( const QFileInfo & info ) const
{
//Initializing the pixmap from file
QPixmap pixmap( info.filePath() );
//Processing the valid pixmap
if ( !pixmap.isNull() )
{
//Resizing the pixmap to the required thumbnail size
pixmap = pixmap.scaled( mySize );
return QIcon( pixmap );
}
else return QIcon();
}


You'll have to set-up the icon size of your list view to mySize by calling the setIconSize() method and set the icon provider for your QDirModel. This implementation can be further improved, but this is something to start with.

SkripT
4th April 2006, 17:05
Do you know if there's any documentation that shows detailed some examples on how to work with a QDirModel and its communication with a QListView or how to create a complete file manager with it?

jpn
4th April 2006, 18:25
Not that I know. The only example of QDirModel usage provided with Qt is the Dir View (http://doc.trolltech.com/4.1/itemviews-dirview.html) example.
Neither does the QDirModel documentation provide much of example usage, but the common model/view programming concept applies here too..

Lemming
4th April 2006, 20:34
From my experience of implementing the full-scale file browser, QT documentation is sufficient to get things working if you're familiar with Model/View architecture. If not, you probably shold start with reading the Model/View tutorial that is supplied with QT.

BTW, there was a nice file browser example in QT3 solutions. Unfortunately it is not yet ported to QT4, causing a lot of troubles for those who need a file browser in their application.

nupul
5th April 2006, 09:43
The simple file browser provided by jpn is a great example..but it does not have the drop facility within the listview itself...(both, on the left as well as right col. of the splitter)...ummm how would you achieve this!!

Nupul

Lemming
5th April 2006, 14:39
You'll have to subclass from QListView and overload the dropEvent



//Enabling the drops for the list viewport
list->viewport()->setAcceptDrops( true );

void FileExplorerList::dropEvent( QDropEvent *event )
{

if ( event->mimeData()->hasUrls() )
{


//Getting the dir model of the list
QDirModel *dirModel = qobject_cast<QDirModel*>( list->model() );
//Dropping the mime data
dirModel->dropMimeData( event->mimeData(), event->proposedAction(), parentIndex );
//Note: it's up to you to get the parent index for the drop operation

}}


This should work fine. Actually, there is QDirModel::setReadOnly( bool ) method as well. I'm not sure about it, but setting it to on might possible enable the default drop functionality for the dir model.

invictus
4th November 2007, 15:34
Because it's this simple:


#include <QtGui>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

// a "file manager" at simplest :)
QSplitter* splitter = new QSplitter;
QDirModel* model = new QDirModel;
QTreeView* tree = new QTreeView(splitter);
tree->setModel(model);
QListView* list = new QListView(splitter);
list->setModel(model);
list->setDragEnabled(true);
splitter->show();

// tree navigation by click
QObject::connect(tree, SIGNAL(clicked(const QModelIndex&)),
list, SLOT(setRootIndex(const QModelIndex&)));
// list navigation by dbl click
QObject::connect(list, SIGNAL(doubleClicked(const QModelIndex&)),
list, SLOT(setRootIndex(const QModelIndex&)));
// update tree upon list change
QObject::connect(list, SIGNAL(doubleClicked(const QModelIndex&)),
tree, SLOT(setCurrentIndex(const QModelIndex&)));

a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
return a.exec();
}


Notice the amount of code :) ..with this, you can already drag'n drop a file from the list view to e.g. desktop..

Nice... is there any way you can go back to the parent of the "current" modelindex? Or does setRootIndex() overwrite everything "above" the defined index?

I am using a QTreeView with
view->setRootIsDecorated(false);
view->setItemsExpandable(false);

So I can only see the top level list.

jpn
4th November 2007, 15:43
You can get the parent via QModelIndex::parent(). If you want to provide a button with "go one level up" -functionality, the slot connected to button's SIGNAL(clicked()) would do roughly:


QModelIndex parent = view->rootIndex().parent();
view->setRootIndex(parent);
button->setEnabled(parent.parent().isValid());

invictus
4th November 2007, 17:00
You can get the parent via QModelIndex::parent(). If you want to provide a button with "go one level up" -functionality, the slot connected to button's SIGNAL(clicked()) would do roughly:


QModelIndex parent = view->currentIndex().parent();
view->setCurrentIndex(parent);
button->setEnabled(parent.parent().isValid());


This seem to work fine...until I select an item. Then the up-action will no longer work for some reason. Although I am using setRootIndex instead of setCurrentIndex in order to show a flat structure instead of a tree.

jpn
4th November 2007, 17:12
This seem to work fine...until I select an item. Then the up-action will no longer work for some reason. Although I am using setRootIndex instead of setCurrentIndex in order to show a flat structure instead of a tree.
Oops, sorry. Those should've been rootIndex() and setRootIndex(). Thanks for pointing it out. ;) I have corrected it to my previous post..

invictus
4th November 2007, 22:55
Oops, sorry. Those should've been rootIndex() and setRootIndex(). Thanks for pointing it out. ;) I have corrected it to my previous post..

Yeah, but thats when it is not working, unfortunately :(

mchara
5th November 2007, 11:05
hello all,
and what about providing custom class inherited from QFileIconProvider (QDirModel::setIconProvider()) that generates thumbnails? My app generates them in separate thread & stores thumbnails in xmlfile in each directory it works great, maybe with similar ithumbsProvider you could have only one QTreeView with thumbnails inside & drag&drop functionalities?

jpn
5th November 2007, 15:14
QtCentreWiki: Extended Dir View example (http://wiki.qtcentre.org/index.php?title=Extended_Dir_View_example)

invictus
5th November 2007, 23:55
QtCentreWiki: Extended Dir View example (http://wiki.qtcentre.org/index.php?title=Extended_Dir_View_example)

Nice example. Thanks.

But one question. When you doubleclick the treeview it will enter the clicked item...but if the item selected isnt the first column it will not enter the correct directory. Any thoughts on that?

mchara
6th November 2007, 07:37
connect clicked(const QModelIndex &) or doubleClicked(const QModelIndex &) signal to slot that setRootIndex ( const QModelIndex & ) for index in first column & the same row as passed in signal...

jpn
6th November 2007, 08:20
But one question. When you doubleclick the treeview it will enter the clicked item...but if the item selected isnt the first column it will not enter the correct directory. Any thoughts on that?
Thanks for the bug report. It's fixed now.

invictus
7th November 2007, 22:47
Speaking of problems...

This is my goTo slot (much like your setRootIndex):


void goTo(const QModelIndex &dir)
{
if(dirModel->isDir(dir))
{
dirView->setRootIndex(dir);
addressField->setText(dirModel->filePath(dir));
upAction->setEnabled(dir.isValid());
}
}

dirView is a QTreeView. The problem is that when the up method is run (which run goTo() with the parent() of the dirView rootIndex like in your example) the program just quits/crashes. If I comment the if(dirView->isDir()) line it works.

jpn
7th November 2007, 23:05
Did you notice that I modified the statement which enables/disables "upAction" in the example from

upAction->setEnabled(listView->rootIndex().isValid());
to

upAction->setEnabled(!dirModel->fileInfo(listView->rootIndex()).isRoot());
? The former works on Windows but not on Linux. On Linux, I experienced the same crash youre' talking about. The latter should work on both environments. Unfortunately I don't have a Mac so I don't know for sure if there's any pitfalls on that matter but I believe the latter should take care of it on Mac too.. ;)

invictus
7th November 2007, 23:12
Yeah, but its on the isDir() that it crashes. I am using windows btw.

Perhaps the problem is that on Windows there is another level above the root ? its a list of partitions like "C:", "D:", etc...

jpn
7th November 2007, 23:40
To me this suggests that goTo() get called with an invalid index and QDirModel is missing sufficient checks. Does the example crash too?

invictus
9th November 2007, 09:45
To me this suggests that goTo() get called with an invalid index and QDirModel is missing sufficient checks. Does the example crash too?

No...but then again, the example doesn't run model->isDir() on the level above the root (level above root is the list of filesystems on windows). Looks to me that this is a QT problem or something.

jpn
9th November 2007, 10:00
No...but then again, the example doesn't run model->isDir() on the level above the root (level above root is the list of filesystems on windows). Looks to me that this is a QT problem or something.
Drives are "root" on Windows:


qDebug() << QFileInfo("C:\\").isRoot(); // "true"

Notice that QDirModel::isDir() is basically a shortcut for QDirModel::fileInfo().isDir(). Also, calling QDirModel::fileInfo() or QDirModel::isDir() throws an assert when passed an invalid index:


QDirModel model;
QModelIndex index = model.index(0, 0);
model.fileInfo(index.parent()); // "ASSERT: "d->indexValid(index)" in file itemviews\qdirmodel.cpp"

So you will have to take care of it yourself that you don't call QDirModel::fileInfo() or QDirModel::isDir() with an invalid index.

mchara
9th November 2007, 10:46
Hi,
i had similar problems, when i was writing dirModel with Desktop myComputer & MyDocuments on top level and i'm quite sure that jpn has right there's no bugs on qt and errors you got are caused by passing unexisting modelIndexes to model...

try to check hasIndex() for each QModelIndex you are using - it might be useful to find the error.

astrude
11th February 2011, 21:01
hello.// how an i load the files from the file list so that i an get its directory to load the file itself to transfer it to another device..thanks!

giacomelli.fabio
7th April 2011, 00:17
Hi I'm doing that thing with the contents of clipboard.. ( a simple enumeration )

const QMimeData *mime = QApplication::clipboard()->mimeData();
if (mime && mime->hasUrls()) {
QStringList fileList;
foreach(QUrl url, mime->urls())
fileList.append(url.toLocalFile());
........

But If clipboard was filled by a windows application I can't know if I I need to copy or cut ..... do you know a trick ????