summaryrefslogtreecommitdiffstats
path: root/kio/kfile
diff options
context:
space:
mode:
Diffstat (limited to 'kio/kfile')
-rw-r--r--kio/kfile/ChangeLog725
-rw-r--r--kio/kfile/Makefile.am78
-rw-r--r--kio/kfile/NOTES100
-rw-r--r--kio/kfile/TODO17
-rw-r--r--kio/kfile/config-kfile.h32
-rw-r--r--kio/kfile/images.h277
-rw-r--r--kio/kfile/kacleditwidget.cpp1054
-rw-r--r--kio/kfile/kacleditwidget.h60
-rw-r--r--kio/kfile/kacleditwidget_p.h200
-rw-r--r--kio/kfile/kcombiview.cpp371
-rw-r--r--kio/kfile/kcombiview.h133
-rw-r--r--kio/kfile/kcustommenueditor.cpp242
-rw-r--r--kio/kfile/kcustommenueditor.h67
-rw-r--r--kio/kfile/kdiroperator.cpp1740
-rw-r--r--kio/kfile/kdiroperator.h950
-rw-r--r--kio/kfile/kdirselectdialog.cpp481
-rw-r--r--kio/kfile/kdirselectdialog.h131
-rw-r--r--kio/kfile/kdirsize.cpp166
-rw-r--r--kio/kfile/kdirsize.h106
-rw-r--r--kio/kfile/kdiskfreesp.cpp169
-rw-r--r--kio/kfile/kdiskfreesp.h89
-rw-r--r--kio/kfile/kencodingfiledialog.cpp223
-rw-r--r--kio/kfile/kencodingfiledialog.h313
-rw-r--r--kio/kfile/kfile.h129
-rw-r--r--kio/kfile/kfilebookmarkhandler.cpp81
-rw-r--r--kio/kfile/kfilebookmarkhandler.h63
-rw-r--r--kio/kfile/kfiledetailview.cpp686
-rw-r--r--kio/kfile/kfiledetailview.h219
-rw-r--r--kio/kfile/kfiledialog.cpp2372
-rw-r--r--kio/kfile/kfiledialog.h989
-rw-r--r--kio/kfile/kfilefiltercombo.cpp203
-rw-r--r--kio/kfile/kfilefiltercombo.h104
-rw-r--r--kio/kfile/kfileiconview.cpp942
-rw-r--r--kio/kfile/kfileiconview.h265
-rw-r--r--kio/kfile/kfilemetainfowidget.cpp375
-rw-r--r--kio/kfile/kfilemetainfowidget.h95
-rw-r--r--kio/kfile/kfilemetapreview.cpp196
-rw-r--r--kio/kfile/kfilemetapreview.h56
-rw-r--r--kio/kfile/kfilepreview.cpp279
-rw-r--r--kio/kfile/kfilepreview.h122
-rw-r--r--kio/kfile/kfilesharedlg.cpp286
-rw-r--r--kio/kfile/kfilesharedlg.h67
-rw-r--r--kio/kfile/kfilespeedbar.cpp99
-rw-r--r--kio/kfile/kfilespeedbar.h41
-rw-r--r--kio/kfile/kfiletreebranch.cpp528
-rw-r--r--kio/kfile/kfiletreebranch.h242
-rw-r--r--kio/kfile/kfiletreeview.cpp677
-rw-r--r--kio/kfile/kfiletreeview.h273
-rw-r--r--kio/kfile/kfiletreeviewitem.cpp83
-rw-r--r--kio/kfile/kfiletreeviewitem.h106
-rw-r--r--kio/kfile/kfileview.cpp429
-rw-r--r--kio/kfile/kfileview.h444
-rw-r--r--kio/kfile/kicondialog.cpp772
-rw-r--r--kio/kfile/kicondialog.h350
-rw-r--r--kio/kfile/kimagefilepreview.cpp187
-rw-r--r--kio/kfile/kimagefilepreview.h77
-rw-r--r--kio/kfile/kmetaprops.cpp268
-rw-r--r--kio/kfile/kmetaprops.h69
-rw-r--r--kio/kfile/knotifydialog.cpp1191
-rw-r--r--kio/kfile/knotifydialog.h341
-rw-r--r--kio/kfile/knotifywidgetbase.ui469
-rw-r--r--kio/kfile/kopenwith.cpp851
-rw-r--r--kio/kfile/kopenwith.h209
-rw-r--r--kio/kfile/kopenwith_p.h101
-rw-r--r--kio/kfile/kpreviewprops.cpp89
-rw-r--r--kio/kfile/kpreviewprops.h57
-rw-r--r--kio/kfile/kpreviewwidgetbase.cpp49
-rw-r--r--kio/kfile/kpreviewwidgetbase.h92
-rw-r--r--kio/kfile/kpropertiesdesktopadvbase.ui279
-rw-r--r--kio/kfile/kpropertiesdesktopbase.ui316
-rw-r--r--kio/kfile/kpropertiesdialog.cpp4157
-rw-r--r--kio/kfile/kpropertiesdialog.h918
-rw-r--r--kio/kfile/kpropertiesmimetypebase.ui70
-rw-r--r--kio/kfile/kpropsdlg.h4
-rw-r--r--kio/kfile/kpropsdlgplugin.desktop87
-rw-r--r--kio/kfile/krecentdirs.cpp99
-rw-r--r--kio/kfile/krecentdirs.h70
-rw-r--r--kio/kfile/krecentdocument.cpp177
-rw-r--r--kio/kfile/krecentdocument.h105
-rw-r--r--kio/kfile/kurlbar.cpp1036
-rw-r--r--kio/kfile/kurlbar.h660
-rw-r--r--kio/kfile/kurlcombobox.cpp363
-rw-r--r--kio/kfile/kurlcombobox.h229
-rw-r--r--kio/kfile/kurlrequester.cpp430
-rw-r--r--kio/kfile/kurlrequester.h301
-rw-r--r--kio/kfile/kurlrequesterdlg.cpp135
-rw-r--r--kio/kfile/kurlrequesterdlg.h114
-rw-r--r--kio/kfile/tests/Makefile.am41
-rw-r--r--kio/kfile/tests/kcustommenueditortest.cpp19
-rw-r--r--kio/kfile/tests/kdirselectdialogtest.cpp17
-rw-r--r--kio/kfile/tests/kfdtest.cpp34
-rw-r--r--kio/kfile/tests/kfdtest.h28
-rw-r--r--kio/kfile/tests/kfiletreeviewtest.cpp165
-rw-r--r--kio/kfile/tests/kfiletreeviewtest.h42
-rw-r--r--kio/kfile/tests/kfstest.cpp183
-rw-r--r--kio/kfile/tests/kicondialogtest.cpp19
-rw-r--r--kio/kfile/tests/knotifytest.cpp10
-rw-r--r--kio/kfile/tests/kopenwithtest.cpp67
-rw-r--r--kio/kfile/tests/kurlrequestertest.cpp16
99 files changed, 33538 insertions, 0 deletions
diff --git a/kio/kfile/ChangeLog b/kio/kfile/ChangeLog
new file mode 100644
index 000000000..bb43f16da
--- /dev/null
+++ b/kio/kfile/ChangeLog
@@ -0,0 +1,725 @@
+Sat Feb 26 00:26:55 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kdiroperator.cpp:
+ lottsa changes, e.g. action handling more clear now.
+ fixed completed item not clearning the previous selection
+
+ * kfileviewitem.cpp:
+ fixed unreadable pixmap not shown, when files were deleted
+
+ * kfiledialog.cpp (selectedURLs):
+ re-enabled the hack to support multi-selection, until we have something
+ better
+
+ * kcombiview.*:
+ forward the sorting to the right view (or should it apply to the dir-
+ view as well?) Sort of broken tho.
+
+Sun Feb 20 01:50:44 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kdiroperator.*, kfiledialog.* (saveConfig):
+ implemented loading, saving and applying configuration
+
+ * kfiledialog.cpp (setURL):
+ KDirComboBox is now a combo for recent directories as well as the
+ root-dir, home-dir and Desktop-dir.
+ Recent dirs will be saved in kdeglobals.
+
+Fri Feb 18 23:35:04 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfilefilter.cpp (eventFilter):
+ intercept Key_Return and Key_Enter in the filter-combo and emit
+ filterChanged instead of letting the dialog close
+
+Thu Feb 17 19:09:54 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfiledialog.{cpp,h} (KDirComboBox):
+ Added KDirComboBox and replaced the directory combobox with it. It
+ even does something now :) Items need to be indented tho.
+
+ * kfilereader.cpp, kdiroperator.{cpp,h}:
+ fixed showHidden default
+
+Tue Feb 15 14:21:41 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfile.h (class KFile):
+ added a small class that contains all the enums now.
+ cleaned up the enums (hope not too many apps will be broken)
+ added flags for "Existing files only" and "local files only"
+
+ * all views (setSelected()):
+ replaced highlightItem(item) with setSelected(item, bool) which makes
+ it more suitable and more consistent with Qt.
+ added selectionChanged() method (necessary for multiselection)
+
+ * kfileview.*:
+ added invertSelection()
+
+ * kfiledialog.cpp:
+ made it work with multiselection
+ added static methods for multiselection
+ added getOpenURL(), getOpenURLs and getSaveURL()
+
+ * kdiroperator.cpp (setSorting):
+ added setSorting() and sorting() to keep sorting when switching views
+ a few cosmetic and KAction changes
+
+Sun Feb 13 00:45:12 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfiledialog.cpp (completion):
+ small fix: completion and auto-directory following works also
+ without protocol-part in the location.
+
+Sat Feb 12 15:30:40 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfileview.h:
+ made setSorting() and sortReversed() virtual so that subclasses
+ can intercept that to show sorting order
+
+ * kfiledetailview.cpp,h (setSortIndicator):
+ enable header-clicking again to set the sorting
+
+Fri Feb 11 12:17:59 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfiledialog.cpp (KFileDialog):
+ fixed filefilter not being applied in constructor
+
+Thu Feb 10 17:06:36 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kdiroperator.cpp (connectView):
+ - Now that KToggleAction is fixed, I can commit the new stuff:
+ Offer Actions for all the common functionality, i.e. sorting, setting
+ the view, home(), cdUp(), back, forward, etc.
+ All actions are exposed through a QActionCollection
+
+ BTW, I'd really like to have a way to change the state of an action
+ without it calling the associated slot. For now I use blockSignals()
+ (thanks, Simon), but this sucks.
+
+ - renamed fileList to fileView (that was an old relic of KDE 1)
+
+ * kfiledialog.*:
+ - make use of the new Actions and fill the toolbar again (up, back,
+ forward, reload, home).
+
+ - the combo in the toolbar is going to change, it does nothing now
+ (only shows the Root and Desktop dirs with a nice icon).
+
+Thu Feb 10 12:59:29 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kdiroperator.cpp (insertNewFiles):
+ aahhh, finally fixed that infinite loop in KFileView::mergeLists
+ clear the view before calling view->addItemList( currentContents );
+
+ * kfilereader.cpp (setURL):
+ don't disable dirWatch update (setAutoUpdate) when setting a remote URL
+
+Fri Feb 4 12:42:37 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfiledetailview.cpp (insertItem):
+ - don't let QListView sort the items
+ I disabled clicking at the headers for now, will fix that later
+ - don't flicker on mimetype-pixmap update
+
+Thu Feb 3 12:15:16 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfileview.h + all views where necessary
+ added selectAll()
+ added isSelected( const KFileViewItem * )
+ added const KFileViewItemList * selectedItems()
+ added const KFileViewItemList * items()
+
+ spiced up documentation of KFileView a bit
+
+Sun Jan 30 22:20:14 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfileviewitem.cpp (pixmap):
+ fixed some issues for different pixmap sizes
+
+ * kfileiconview.{h,cpp} (setPixmapSize):
+ added configurability for different pixmap sizes
+
+Sun Jan 30 16:49:12 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfileview.h + all views:
+ A view can now have a name (setViewName() and viewName())
+ This is useful to differentiate views and to display the names in a
+ popupmenu for switching between views.
+
+Sun Jan 30 12:41:04 2000 Werner Trobin <wtrobin@carinthia.com>
+ The preview mode works again. It's very similar to the Qt-2.1 QFD
+ preview mode - but it's not totally the same. There are some rough
+ edges which have to be ironed out, but it works :)
+ For further information, see kfilepreview.*
+ Note: kpreview and so on are obsolete (IMHO)
+
+Sat Jan 29 15:33:37 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ Time to add some changelogs again, all the recent hard work of the
+ restructuring is only in CVS-log...
+
+ * kfileview.cpp (compareItems):
+ - added support to disable sorting directories first (QDir::DirsFirst)
+ - added support to sort by date and to sort reversed
+ - removed unused findCompletion method
+ - sort case insensitive by default
+ - some optimization for mergeList
+ - fixed infinite loop in mergeLists, when the lists are the same
+ (I think another one is still there, but I'm tired now)
+ - changed setSortMode stuff: Switching-mode replaced with
+ sortReversed(). The enum Switching will be removed, soon.
+ - made setSortMode public
+
+ * kfileviewitem.cpp:
+ - added time_t mTime() to enable sorting by modification time
+
+ * kdiroperator.cpp:
+ - offer sorting options in popupmenu
+ - use checkAccess before creating directories. I guess this will again
+ change when the new kio will be used, tho.
+ - show progress widget at the bottom (otherwise the header of e.g.
+ the detail-view would be covered).
+ - Added LGPL copyright header
+
+ * kfilewidget.cpp (connectSignals):
+ - connect to all signals of KDirOperator
+ - directly connect SIGNAL to SIGNAL -> removed slotFileHighlighted etc.
+ - fixed some sorting/merging bugs
+
+ * {kfiledialog,kdiroperator}.{cpp,h};
+ - support for disabling chdir (some apps may not want KFileDialog /
+ KFileReader change the working directory under their feet)
+ - Added LGPL header in cpp-file
+
+ * kfilereader.cpp (stat):
+ - fixed: some special files were recognized as directories
+
+ * kfstest.cpp:
+ - added test for KFileWidget (widget -> KFileWidget,
+ diroperator -> KDirOperator)
+
+Sun Oct 31 00:56:23 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfileinfo.cpp (readUserInfo): Don't call getpwnam() and getgrgid()
+ all the time over and over again! This opens and parses /etc/passwd
+ or /etc/group with every call!
+ Now we load /etc/passwd and /etc/group once and store the interesting
+ stuff in static QMaps, which need to be freed with KFileInfo::cleanup()
+ cleanup() is called from KFileBaseDialog's destructor.
+
+ This speeds up KFileDialog a LOT!
+
+Sat Oct 23 01:55:00 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfiledetaillist.cpp (key): hopefully implemented correct mapping
+ from KFileInfo to QListViewItem and back. I had a hard time convincing
+ QListView that KFileInfoContents knows best where to insert an item
+ Now the detaillist is even usable :)
+ Fixed a problem with selection and highlighting
+ Disable clicking on listview headers that can't be used for sorting
+
+ * kfileinfocontents.cpp (setSorting): call insertItem() with a correct
+ (is it?) index, instead of -1
+
+Thu Oct 21 23:18:54 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfiledialog.cpp (init): removed "[development only] from tooltip
+ (sorry to break the translations, but this HAD to go)
+
+ * don't update anything when leaving the configure-dialog with Cancel
+
+Wed Oct 20 15:07:16 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfileinfo.cpp,h: implemented KFileInfo::filePath() and fixed
+ KFileInfo::absURL() not being set in some cases
+
+ * kdir.cpp: fixed a buglet in the path (double slashes)
+
+ * kfiledetaillist.cpp (KFileDetailList): improved selecting files
+ (single click, double click, Return-key)
+ but the mapping from QListViewItem to KFileInfo is still quite broken
+
+1999-06-09 Woohyun JANG <louis@mizi.co.kr>
+
+ * kdir.cpp: used QString::local8Bit() instead of QString::ascii()
+ for file names and directory names.
+
+ * kfiledialog.cpp: used QStringList instead of QStrIList.
+
+1999-01-14 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: fixed some GUI problems and moved all default
+ configurations into config-kfile.h.
+ Changed some default values, so that users that never looked into
+ the config dialog gets a nice suprise with 1.1 ;-)
+
+ * kfiledialog.cpp: changed selectedFile to return decoded path instead
+ of encoded one
+
+Thu Jan 7 23:14:39 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfilesimpleview.cpp (keyPressEvent): fixed segfault on keypress,
+ when there were no files at all in the list
+
+1998-12-19 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: fixing an ugly bug when "." is used as argument
+
+Mon Dec 14 23:00:41 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfilebookmark.cpp: renamed class KBookmark to KFileBookmark to
+ avoid problems with KFM's KBookmark class. Renamed bookmark.* to
+ kfilebookmark.*, too and changed all occurrences of bookmark.* to
+ kfilebookmark.* (especially all the .po-files)
+
+Wed Dec 2 15:59:13 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kfilesimpleview.cpp: Fixed some more keyboard navigation bugs.
+ Added method isColCompletelyVisible( int col ), now you can scroll
+ perfectly to make items completely visible.
+ Moreover, in resizeEvent() the number of columns was not calculated
+ correctly in a special case.
+ And the currently selected item is rehighlighted correctly after
+ resizing, now.
+
+1998-10-12 Jochen Küpper <jochen@uni-duesseldorf.de>
+
+ * kfiledialog.cpp (okPressed): Changed okPressed to store the correct
+ filename before leaving the dialog.
+
+1998-06-07 Stephan Kulow <coolo@kde.org>
+
+ * kfilesimpleview.cpp: added some checks to prevent division with
+ zero using the latest qt snapshots
+
+ * kfilesimpleview.cpp: added a repaint call after a resize
+
+ * kfiledialog.cpp: new experimental button order
+
+ * kfiledialog.cpp: added lastDirectory to remember the last visited
+ directory for next open
+
+1998-05-24 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: use setSelection also for the initial filename
+ given
+
+ * kfiledialog.cpp: introduced KFileFilter to make an abstraction
+ for the used filter widget. Currently only QComboBox is supported,
+ but this may change in the future
+
+1998-05-20 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: changed the accelerator for completion
+ to CTRL-T
+
+ * kfiledialog.cpp: fixed the setSelection() feature
+
+1998-05-19 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.h: added setSelection
+
+1998-05-18 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: bugfixes
+
+1998-05-15 Stephan Kulow <coolo@kde.org>
+
+ * kfileinfocontents.cpp: some more changes and speed ups
+ (caching and some other little things)
+
+1998-05-14 Stephan Kulow <coolo@kde.org>
+
+ * kfileinfocontents.cpp: added addItemList
+
+ * kfileinfocontents.h: introduced KFileInfoContentsSignaler
+
+ * kfileinfocontents.cpp: some more speed improvment
+
+1998-05-10 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: tried to speed up the refresh
+
+1998-04-17 Stephan Kulow <coolo@kde.org>
+
+ * kfiledetaillist.cpp: implemented the date field
+
+ * kfiledetaillist.cpp: made the columns wider
+
+ * kfileinfocontents.cpp: use the new icons by Mark
+
+Thu Apr 16 10:51:24 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * kfiledialog.*: some small fixes concerning preview
+
+ * kfileinfocontents.cpp: fixed sorting bug in preview
+
+ * kfilepreview.*: small bug fixes
+
+ * kpreview.*: small bug fixes
+
+ * added some documentation
+
+1998-04-15 Stephan Kulow <coolo@kde.org>
+
+ * kfilepreview.cpp: use a list box instead of simple view
+
+ * kfiledialog.cpp: fixed an ugly bug
+
+1998-04-14 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialogconf.cpp: removed the width/height sliders
+
+ * kfiledialog.cpp: save the width and height on exit
+
+ * kfiledialogconf.cpp: added more guys to the about box
+
+ * kfiledialog.h: removed init*Children. They were useless
+
+ * kfiledialog.cpp: set the default size to a useful value
+
+Mon Apr 6 17:30:18 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * kfilepreview.*: restructured previewing, one can now easily
+ use custom previewers, dynamically
+
+ * kpreview.*: changes for allowing custom previewers, two previewers
+ are hardcoded so far
+
+ * kfiledialog.*: changes changes for allowing custom previewers
+
+ * kfstest.cpp: changes to preview mode
+
+ * xview.*: QimageIO module allowing the visual-schnauzer generated
+ images to be loaded
+
+1998-04-06 Stephan Kulow <coolo@kde.org>
+
+ * debug.h: added debugC. An empty macro to hide debug output
+
+Thu Apr 2 19:39:37 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * kpreview.*: widget which for now shows some info about a
+ file/folder along with the first 20-30 lines of it
+
+ * kfilepreview.*: added a new view which has a preview of any text
+ file in the right part
+
+ * kfstest.cpp: added the new mode "preview" which shows the above
+ view
+
+1998-03-30 Stephan Kulow <coolo@kde.org>
+
+ * kfilesimpleview.cpp: fixed highlightning
+
+ * kfiledialog.cpp: some fixes for the dir selection
+
+ * kfiledialog.h: Moved KFileDialog into KFileBaseDialog and made
+ KFileDialog and KDirDialog a derived class of KFileBaseDialog to
+ make this virtual functions work
+
+Mon Mar 30 17:53:20 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * kcombiview.cpp: bug fixes for completion & corresponding
+ highlighting
+
+ * kfiledialog.cpp: small bug fix, too much copying into location
+
+ * kfileinfocontents.cpp: completion slightly remodeled, should
+ work in all views now
+
+ * kfileinfocontents.h: changed nameList to case insensitive
+ list
+
+1998-03-28 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: changed the filter separator to \n.
+ This looks nicer in the source code of the call
+
+Sat Mar 28 14:49:00 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: changed the meaning of the dirName argument
+
+ * kfiledialog.h: added getShowFilter
+
+Thu Mar 26 12:47:42 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfilesimpleview.cpp: improved scrolling in simple view
+
+ * kfileinfocontents.cpp: add a / after a found dir
+
+ * kfiledialog.cpp: fixed bug for !showFilter
+
+Wed Mar 25 18:39:09 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * kfileinfocontents.cpp: completion now working
+
+ * kcombiview.cpp: changed behavior for completion, it
+ now highlights completed directory and file
+
+Tue Mar 24 16:08:46 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * kfileinfocontents.cpp: sorting now fully working
+
+ * kfiledialog.cpp: modifications for sorting in the on the
+ fly reconfiguration
+
+ * kfileinfocontents.*: modification to the constructor
+ to pass along the sorting
+
+ * kfiledetaillist.*: modification to the constructor
+ to pass along the sorting
+
+ * kcombiview.*: modification to the constructor
+ to pass along the sorting
+
+ * kfilesimpleview.*: modification to the constructor
+ to pass along the sorting
+
+Tue Mar 24 10:45:15 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * kfileinfocontents.cpp: sorting fixed, the feature of keeping
+ directories grouped is still missing though
+
+Mon Mar 23 22:59:18 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledetaillist.h: added acceptsFiles() and acceptsDirs() to
+ make dirs-only views useful
+
+ * kfileinfocontents.cpp: OK, completion is back again, but
+ currently not working, because the code is missing ;-)
+
+Mon Mar 23 00:08:02 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: moved all GM related things into initGUI() to
+ make recreation possible
+
+Sun Mar 22 00:22:46 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: use KShellProcess now
+
+ * kfiledialog.h: added virtual function initFileList to made
+ KFileDialog customable
+
+ * kfiledialog.cpp: show a combo box, in case more filters are given
+
+ * kfiledialog.cpp: some bug fixes. I can't get the sorting to work
+
+ * Makefile.am: install some toolbar pixmaps
+
+ * kfiledetailview.cpp: added pixmaps to the detail view
+
+ * Kfiledialog.cpp: made KComboView customable through virtual
+ functions
+
+ * kcombiview.cpp: took out the completion for now, added
+ kcombiview and some little changes in setCurrentItem
+
+ * kdirlistbox.cpp: fixed the use of single click
+
+ * kdir.h: moved the header files a little bit to remove
+ some dependencies
+
+ * kdirlistbox.cpp: KDirListBox is now a KFileInfoContents too
+
+ * kfiledialog.cpp: another change in the API. It uses now QSignal.
+ I didn't liked the old way
+
+1998-03-21 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: implemented mixDirsAndFiles. Need some work and currently
+ only supported by the simple view
+
+Sat Mar 21 01:00:48 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfilesimpleview.cpp: added pixmaps to indicate access on the file
+
+ * kfilesimpleview.cpp: improved keyboard navigation
+
+ * kfilesimpleview.cpp: first almost working simple view
+
+ * kfilesimpleview.cpp: started implementing a simple view. Needs
+ still some work
+
+
+Fri Mar 20 22:42:31 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfileinfocontents.h: bugfixes
+
+ * kfileinfo.cpp: KFileInfo is no longer a derived class of
+ QFileInfo. This should reduce memory use too
+
+ * kfileinfocontents.h: moved the actual sorting in
+ KFileInfoContents. Derived classes are for viewing only
+
+ * kfiledialog.h: fixed some header files locations
+
+1998-03-20 Stephan Kulow <coolo@kde.org>
+
+ * kfileinfo.cpp: show lockedfolder.xpm for folders, that are not
+ allowed to enter or read
+
+ * kfiledialog.cpp: bug fixes
+
+Fri Mar 20 13:10:11 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ * kfilgdialog.*, remodeled the configuration dialog to reflect the
+ current possible settings
+ * kfiledetailList.cpp: added the PageUp PageDown navigation
+
+1998-03-19 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: fixed the forward/back back reported by
+ Stefan Tafener
+
+1998-03-18 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: set the initial focus to the line edit
+
+ * kfiledialog.cpp: use kapp->invokeHTMLHelp now
+
+ * kfiledialog.h: removed treeList, since it's not implemented
+
+Wed Mar 18 02:56:32 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledetaillist.cpp: fixed sorting again
+
+1998-03-17 Stephan Kulow <coolo@kde.org>
+
+ * added a virtual class KInfoListContent to make an abstraction
+ for the file contents. Currently there is just one implementation
+ KFileDetailList
+
+1998-03-16 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: don't accept the first entry of the combo
+ box as a file name
+
+ * kfiledialog.cpp: added an accelerator for completion, since
+ KCombo no longer emits such a thing (currently CTRL-A)
+
+ * kdir.cpp: disable parent button in /
+
+ * kfiledialog.cpp: fixed layout of mkdir dialog
+
+ * kdir.cpp: use currentDir instead of homeDir as default
+
+ * kfiledialog.cpp: added member acceptOnlyExisting and set it
+ for now to always false. I guess, we need an extra parameter for this
+
+ * kfiledialog.cpp: changed dirList and fileList to fix the
+ focus handling
+
+ * kfileinfolistwidget.cpp: added focus handling
+
+ * kfileinfolistwidget.cpp: added keyevent handling to handle
+ cursor and enter
+
+ * kfiledialog.cpp: changed the filter edit to a QLineEdit, since
+ we don't need the completion, but the tabing for focus changes
+
+Mon Mar 16 11:36:07 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ * added create directory, pops up a modal dialog, should add
+ a mkdir method to kdir in near future
+
+Mon Mar 16 20:04:00 1998 Martin Jones <mjones@kde.org>
+ * Added booktoken.* to remove dependancy on khtmlw and jscript
+
+Thu Mar 12 09:32:06 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ * worked on the dir and file completion, should do both now,
+ text in the location box will be added as much as possible
+ (right now it's the lowest denominator of dir&file&location-text)
+ * added sorting for the detailed list, so far only name and size
+ sorting implemented
+ * added single click selection for directories
+ * added a status line, which shows the number of directories and
+ files showed
+
+Thu Mar 12 00:36:05 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: made a library out of the file selector
+ * kfiledialog.cpp: added an extra parameter acceptURLs to seperate
+ between getOpenFileName and getOpenFileURL
+
+Sun Feb 15 23:13:47 1998 Richard Moore <rich@kde.org>
+
+ * More work on the bookmarks - they should work properly now, you
+ must create the directory ~/.kde/share/apps/kdeui to store the
+ bookmarks in.
+
+ * Regenerated docs
+
+Thu Feb 12 17:27:51 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfileinfo.cpp: added determination of group and other things to
+ be display the correct values in the kfileinfolistwidget
+
+Thu Feb 12 16:01:44 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: removed the #ifdef code. Now the combo box for
+ the path is the only option
+
+Tue Feb 10 01:09:16 1998 Richard Moore <rich@kde.org>
+
+ * Added details widget - this is currently selected by a config
+ file entry, but it there should be a toolbar button. Many changes
+ to kfiledialog to allow the switch (need an abstract fileview class).
+
+Fri Feb 6 18:08:14 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: replaced the location lineedit with an combo
+ box. Currently configurable with a compiler define.
+
+Fri Feb 6 17:07:26 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: fixed the en- and decoding of URLs. Now it's
+ possible to move into directories called "sdasd#sdsd" for example
+
+Sat Jan 24 17:18:10 1998 Mario Weilguni <mweilguni@sime.com>
+
+ * fixed a bug in kdir.cpp/parsePermissions()
+
+ * implemented error handling for KFM URL errors
+
+Tue Jan 20 00:51:55 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: some fixes to make kfm support more robust
+
+Mon Jan 19 01:10:11 1998 Stephan Kulow <coolo@kde.org>
+
+ * kdir.cpp: re-added ftp support
+
+ * kfiledialog.cpp: take care of the case, when the user enters a
+ complete filename
+
+ * kdir.cpp: added isReadable() to indicate, that the dir is not
+ correct
+
+ * kfiledialog.cpp: played a little bit with the geometry management
+
+
+Sun Jan 18 15:00:06 1998 Stephan Kulow <coolo@kde.org>
+
+ * kfiledialog.cpp: - back/forward work now as expected
+ - show the correct filter
+ - the combo box works now as expected
+
+ * kdir.cpp: check if the directory is correct (for local
+ files). If not, go back to the old value
+
+ * kfiledialog.cpp: - disable parent button, when in root
+ - treat the case, that the URL ends with "/"
+ - strip white spaces out of the location text
+
+ * kfileinfo.cpp: don't insert broken links
+
+ * kfiledialog.cpp: just set the dir, if it's different
+ from the already set one
+
+Sun Jan 18 11:53:32 1998 Mario Weilguni <mweilguni@sime.com>
+
+ * symbolic links to subdirectories are now correctly reported as
+ directories
+
+ * symbolic links are show as italic text
+
+ * The toolbar button "Home" works now as expected
diff --git a/kio/kfile/Makefile.am b/kio/kfile/Makefile.am
new file mode 100644
index 000000000..a63306189
--- /dev/null
+++ b/kio/kfile/Makefile.am
@@ -0,0 +1,78 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1997 Stephan Kulow (coolo@kde.org)
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this library; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+
+INCLUDES= -I$(srcdir)/../libltdl/ -I$(top_srcdir) -I$(top_srcdir)/kdefx \
+ -I$(top_builddir)/kio/kio -I$(top_srcdir)/kio/bookmarks $(all_includes) $(LIBART_CFLAGS)
+
+noinst_LTLIBRARIES = libkfile.la
+
+METASOURCES = AUTO
+
+#SUBDIRS = . acl_prop_page
+
+include_HEADERS = kfiledialog.h kencodingfiledialog.h\
+ kdiroperator.h kfileview.h kfilefiltercombo.h \
+ kfiledetailview.h kcombiview.h kdiskfreesp.h \
+ kfileiconview.h krecentdocument.h \
+ kurlrequester.h kfilepreview.h kfile.h \
+ kurlcombobox.h kurlrequesterdlg.h kopenwith.h kpropsdlg.h \
+ kicondialog.h kdirsize.h kpreviewwidgetbase.h kimagefilepreview.h kfilesharedlg.h \
+ kfiletreeview.h kfiletreeviewitem.h kfiletreebranch.h \
+ kdirselectdialog.h kurlbar.h kpropertiesdialog.h knotifydialog.h \
+ kcustommenueditor.h knotifywidgetbase.h
+
+noinst_HEADERS = config-kfile.h krecentdirs.h kmetaprops.h \
+ kfilebookmarkhandler.h kfilemetainfowidget.h kopenwith_p.h \
+ kfilespeedbar.h kpreviewprops.h kacleditwidget.h kacleditwidget_p.h images.h
+
+libkfile_la_SOURCES = \
+ kfilefiltercombo.cpp \
+ kfileview.cpp kfileiconview.cpp \
+ krecentdocument.cpp kfiledialog.cpp kdiroperator.cpp \
+ kfiledetailview.cpp kcombiview.cpp kurlrequester.cpp \
+ kfilepreview.cpp kurlcombobox.cpp kurlrequesterdlg.cpp \
+ kopenwith.cpp kpropertiesdialog.cpp kicondialog.cpp kdirsize.cpp \
+ krecentdirs.cpp kdiskfreesp.cpp kimagefilepreview.cpp kfilesharedlg.cpp \
+ kurlbar.cpp kmetaprops.cpp kpreviewprops.cpp \
+ kfiletreeview.cpp kfiletreeviewitem.cpp kfiletreebranch.cpp \
+ kdirselectdialog.cpp kfilebookmarkhandler.cpp \
+ kfilemetainfowidget.cpp kcustommenueditor.cpp knotifywidgetbase.ui \
+ knotifydialog.cpp kfilespeedbar.cpp kpreviewwidgetbase.cpp \
+ kfilemetapreview.cpp kpropertiesdesktopbase.ui \
+ kpropertiesdesktopadvbase.ui kpropertiesmimetypebase.ui \
+ kencodingfiledialog.cpp kacleditwidget.cpp
+
+libkfile_la_COMPILE_FIRST = $(srcdir)/../kio/kdirnotify_stub.h
+
+EXTRA_DIST = NOTES
+
+# convenience lib - no _LDFLAGS or _LIBADD !
+
+servicetype_DATA = kpropsdlgplugin.desktop
+servicetypedir = $(kde_servicetypesdir)
+
+
+#Can't be a module, we need to link to it for readConfig
+#kde_module_LTLIBRARIES = libkfileshare.la
+#libkfileshare_la_SOURCES = kfileshare.cpp
+#libkfileshare_la_LIBADD = libkfile.la
+#libkfileshare_la_LDFLAGS = -module $(KDE_PLUGIN)
+#kde_services_DATA = kfilesharepropsplugin.desktop
+
+include $(top_srcdir)/admin/Doxyfile.am
diff --git a/kio/kfile/NOTES b/kio/kfile/NOTES
new file mode 100644
index 000000000..c3fb6fbcb
--- /dev/null
+++ b/kio/kfile/NOTES
@@ -0,0 +1,100 @@
+Rewrite
+=======
+
+Here is the result of a long discussion between the kfile developers
+(Carsten) and the konqueror developers (Simon and David), about the plans
+for more integration between kfile and konqueror. 16/08/2000.
+
+
+
+ KDirLister -----(1)---------------------> KFileView (3)
+ <----(2)------ [Signaller] --- | |
+ | |
+ | |
+ | |
+ | |
+ KFileIconView KFileListView
+ (4) (5)
+
+
+(1) Gives items found when listing, and the key for each item
+ (KDirLister has all the sorting code)
+(2) KFileView inherited classes emit requests for listing a new
+ directory (with a bool for treeviews), and emit requests for
+ the mimetype of a given item. If all KFileView inherited classes
+ are QScrollViews, then it could even implement the "ask for mimetype
+ of the visible icons first" algorithm, currently in KonqIconView.
+(3) KFileView, the base class for any view, knows about KFileItem, has
+ signals for dropped(), popupMenu(list of actions provided by the view),
+ has a QWidget * canvas() method, xOffset() and yOffset()
+(4) KFileIconView holds a QPtrDict to look up a QIconViewItem quickly from a
+ given KFileItem. This will help for e.g. deleteItems and refreshItems.
+(5) KFileListView holds a QPtrDict to find the QListViewItem for a
+ KFileItem. It implements different modes if we want the tree view in
+ kfile ?
+
+
+ KFileChooserWidget
+
+This (base) class is the container widget that can contain any kfileview and
+switch between them. It is embeddable into an application that wants a widget
+for choosing a file or directory. Features listing, selecting, popupmenu for
+switching modes, and a virtual createView( viewmode ) method, which
+only knows about the builtin views, in this class.
+It knows the current URL, has setURL(), and triggers the listing, connecting
+KFileView's requests to KDirLister's methods.
+
+ KFileManagerWidget
+
+This class inherits from KFileChooserWidget and adds the file management
+operations. It uses a KFileOperations class (taken from the current
+KonqOperations) for all KIO operations, and it uses KFileUndo, taken from
+the KonqUndo stuff. The popupMenu method is reimplemented to add those
+operations to it.
+
+ KFileWidget
+
+This class is the full widget that can be seen in the dialog. It has the
+toolbar buttons, the combo, etc. It embeds a KFileChooserWidget or a
+KFileManagerWidget, the latter being a specialisation of the former.
+
+The Konqueror side of things
+============================
+
+ KonqFileIconView
+
+Inherits KFileIconView and adds image preview - unless we want it in
+KFileIconView, and the line-up-icons algorithm, etc.
+
+ KonqFileListView
+
+Inherits KFileListView to add more stuff if needed. The mc-like text view
+could be implemented here as well, unless we want it in kfile. Same for the
+tree view.
+
+ KonqFileManagerWidget
+
+This class inherits KFileManagerWidget and adds the konqueror stuff, like
+the enableAction signal. It also reimplements createView to create the
+konqueror versions of the views.
+
+ KonqDirPart
+
+This class inherits KParts::ReadOnlyPart, and provides a BrowserExtension.
+It integrates KonqFileManagerWidget as its KParts widget, and provides
+KActions for it.
+
+Important :
+
+Make sure to take kfind into account. It would be nice if it could use the
+same views as konqueror, to have access to all the view modes, as well as
+image preview, etc.
+
+Unrelated:
+To Add
+======
+
+Mime Mappings?
+
+Filter= ( Mime Type | shell glob list )
+Mime Type -> shell glob list
diff --git a/kio/kfile/TODO b/kio/kfile/TODO
new file mode 100644
index 000000000..b7bf74ea5
--- /dev/null
+++ b/kio/kfile/TODO
@@ -0,0 +1,17 @@
+TODO-List for the KFileDialog and associated classes (in order of importance)
+
+- are more messageboxes necessary?
+- KFD's default dirs configurable
+- drag&drop support for the views (somehow into baseclass KFileView?
+- KFileView::setSelected( const QRegExp& )
+- separate KDirOperator, location-combo, filter-combo etc. from KFileDialog
+ to another widget (everything besides OK/Cancel buttons).
+- implement in-place editing (rename) + make it configurable in all views
+- make a simple fileview based on QListBox
+- implement KFile::PreviewInfo
+- signal KFileView::selectionCleared()
+
+If anyone wants to implement some of those, please do. In case of questions,
+don't hesitate to ask me.
+
+Carsten Pfeiffer <pfeiffer@kde.org>
diff --git a/kio/kfile/config-kfile.h b/kio/kfile/config-kfile.h
new file mode 100644
index 000000000..3666c571b
--- /dev/null
+++ b/kio/kfile/config-kfile.h
@@ -0,0 +1,32 @@
+#ifndef CONFIG_KFILE_H
+#define CONFIG_KFILE_H
+
+const int kfile_area = 250;
+
+#define DefaultViewStyle QString::fromLatin1("SimpleView")
+#define DefaultPannerPosition 40
+#define DefaultMixDirsAndFiles false
+#define DefaultShowStatusLine false
+#define DefaultShowHidden false
+#define DefaultCaseInsensitive true
+#define DefaultDirsFirst true
+#define DefaultSortReversed false
+#define DefaultRecentURLsNumber 15
+#define DefaultDirectoryFollowing true
+#define DefaultAutoSelectExtChecked true
+#define ConfigGroup QString::fromLatin1("KFileDialog Settings")
+#define RecentURLs QString::fromLatin1("Recent URLs")
+#define RecentFiles QString::fromLatin1("Recent Files")
+#define RecentURLsNumber QString::fromLatin1("Maximum of recent URLs")
+#define RecentFilesNumber QString::fromLatin1("Maximum of recent files")
+#define DialogWidth QString::fromLatin1("Width (%1)")
+#define DialogHeight QString::fromLatin1("Height (%1)")
+#define ConfigShowStatusLine QString::fromLatin1("ShowStatusLine")
+#define AutoDirectoryFollowing QString::fromLatin1("Automatic directory following")
+#define PathComboCompletionMode QString::fromLatin1("PathCombo Completionmode")
+#define LocationComboCompletionMode QString::fromLatin1("LocationCombo Completionmode")
+#define ShowSpeedbar QString::fromLatin1("Show Speedbar")
+#define ShowBookmarks QString::fromLatin1("Show Bookmarks")
+#define AutoSelectExtChecked QString::fromLatin1("Automatically select filename extension")
+
+#endif
diff --git a/kio/kfile/images.h b/kio/kfile/images.h
new file mode 100644
index 000000000..0c7bd1c37
--- /dev/null
+++ b/kio/kfile/images.h
@@ -0,0 +1,277 @@
+#ifdef USE_POSIX_ACL
+#ifndef _QEMBED_1804289383
+#define _QEMBED_1804289383
+#include <qimage.h>
+#include <qdict.h>
+static const QRgb group_grey_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x42484848,0xc39b9b9b,0xeab1b1b1,0xce9d9d9d,0x5a4d4d4d,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x563b3b3b,0xfdaeaeae,0xffcfcfcf,0xffcccccc,0xffcecece,
+ 0xffbababa,0x62393939,0x0,0x0,0x0,0x0,0x0,0x0,0x4525252,0x9383838,0x0,0xd0515151,0xff969696,0xff959595,
+ 0xff969696,0xff959595,0xff969696,0xdd505050,0x6000000,0x0,0x0,0x0,0xa191919,0x908f8f8f,0xebc1c1c1,0xf6c6c6c6,0xc0a1a1a1,0xf74f4f4f,
+ 0xff626262,0xff6a6a6a,0xff6c6c6c,0xff6a6a6a,0xff636363,0xfb4a4a4a,0x1a000000,0x0,0x0,0x0,0xa3828282,0xffdfdfdf,0xffdedede,0xffdddddd,
+ 0xffe0e0e0,0xffa4a4a4,0xff636363,0xff666666,0xff6a6a6a,0xff676767,0xff5f5f5f,0xe6494949,0xd000000,0x0,0x0,0x21232323,0xfca2a2a2,0xffc3c3c3,
+ 0xffc6c6c6,0xffc6c6c6,0xffc4c4c4,0xffbababa,0xff717171,0xff7e7e7e,0xff7e7e7e,0xff7d7d7d,0xfe6f6f6f,0x812b2b2b,0x0,0x0,0x0,0x3e303030,
+ 0xffa6a6a6,0xffb7b7b7,0xffbdbdbd,0xffbebebe,0xffb9b9b9,0xffacacac,0xff808080,0xff8f8f8f,0xff939393,0xff909090,0xf86b6b6b,0x34202020,0x0,0x0,
+ 0x0,0x1c191919,0xf8a5a5a5,0xffc2c2c2,0xffcccccc,0xffcecece,0xffc5c5c5,0xffbababa,0xff888888,0xffa5a5a5,0xffa4a4a4,0xffa5a5a5,0xffa1a1a1,0xd3515151,
+ 0x8030303,0x0,0x0,0x0,0x8f6f6f6f,0xffd3d3d3,0xffe2e2e2,0xffe3e3e3,0xffdbdbdb,0xff9b9b9b,0xff6f6f6f,0xff727272,0xff6e6e6e,0xff717171,
+ 0xff707070,0xff606060,0x62363636,0x0,0x0,0x0,0x6e5b5b5b,0xffb4b4b4,0xffd4d4d4,0xffdadada,0xffcecece,0xff737373,0xff656565,0xff676767,
+ 0xff696969,0xff676767,0xff636363,0xff5d5d5d,0xc44b4b4b,0x0,0x0,0x27343434,0xf5a5a5a5,0xffd1d1d1,0xffd2d2d2,0xffd1d1d1,0xffd1d1d1,0xffc3c3c3,
+ 0xff7b7b7b,0xff6f6f6f,0xff727272,0xff6f6f6f,0xff696969,0xff626262,0xf7606060,0x16050505,0x0,0xa07d7d7d,0xffb8b8b8,0xffc0c0c0,0xffc2c2c2,0xffc1c1c1,
+ 0xffc1c1c1,0xffbbbbbb,0xffa6a6a6,0xff868686,0xff858585,0xff838383,0xff838383,0xff878787,0xe95e5e5e,0x19050505,0xd141414,0xf0a2a2a2,0xffbdbdbd,0xffc6c6c6,
+ 0xffcbcbcb,0xffcbcbcb,0xffc8c8c8,0xffc0c0c0,0xffb8b8b8,0xef8b8b8b,0xd6707070,0xd26a6a6a,0xbb595959,0x82363636,0x24070707,0x0,0x44505050,0xffc0c0c0,
+ 0xffc7c7c7,0xffd2d2d2,0xffd9d9d9,0xffdadada,0xffd4d4d4,0xffcacaca,0xffc1c1c1,0xc8979797,0x3000000,0x4000000,0x0,0x0,0x0,0x0,
+ 0x2b393939,0xeeaaaaaa,0xffdadada,0xffe4e4e4,0xffeaeaea,0xffeaeaea,0xffe4e4e4,0xffdddddd,0xffd1d1d1,0xae797979,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x1e0f0f0f,0x76575757,0xae898989,0xc49c9c9c,0xc6a0a0a0,0xbc9a9a9a,0x98808080,0x57414141,0xb000000,0x0,0x0,
+ 0x0,0x0,0x0,0x0
+};
+
+/* Generated by qembed */
+static const QRgb group_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4223731d,0xc37fbb7c,0xea9bca98,0xce86b982,0x5a316e2c,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x56146610,0xfd8fce8e,0xffbae4bb,0xffb7e2b7,0xffbae3ba,
+ 0xff9ed89d,0x62166112,0x0,0x0,0x0,0x0,0x0,0x0,0x4003ca5,0x9003171,0x0,0xd0198b17,0xff6ac468,0xff6ec665,
+ 0xff70c865,0xff6ec665,0xff6ac468,0xdd1a8918,0x6000000,0x0,0x0,0x0,0xa001333,0x905b8cc4,0xeb9fc0e4,0xf6a8c5e4,0xc07a9dc9,0xf7108e1e,
+ 0xff2eb113,0xff42be17,0xff49c216,0xff44be17,0xff31b214,0xfb109301,0x1a000000,0x0,0x0,0x0,0xa3497ebb,0xffc6def8,0xffc6ddf6,0xffc5ddf6,
+ 0xffc9e0f8,0xff77abd2,0xff31af18,0xff50cd00,0xff5cd400,0xff52ce00,0xff3bbe00,0xe6218f03,0xd000000,0x0,0x0,0x21042043,0xfc61a0e3,0xff97c3f0,
+ 0xff9cc7f1,0xff9cc8f1,0xff98c4f0,0xff85b8ef,0xff469d88,0xff7de517,0xff87ed10,0xff7ce417,0xfe5bca14,0x811b5304,0x0,0x0,0x0,0x3e082e58,
+ 0xff60a7ed,0xff7fbaef,0xff8ac3f1,0xff8bc4f1,0xff83beef,0xff6caeec,0xff4e98b3,0xff88d54a,0xff98e343,0xff89d64a,0xf846a630,0x340c4100,0x0,0x0,
+ 0x0,0x1c021631,0xf867a7e3,0xff90c9f4,0xffa1d6f8,0xffa4d8f8,0xff96cef5,0xff82bef2,0xff65aca9,0xff8ad576,0xff86d276,0xff88d377,0xff80d072,0xd3279310,
+ 0x8000700,0x0,0x0,0x0,0x8f3f6f9f,0xffaedcf9,0xffc7effe,0xffc9f0fe,0xffbbe5fc,0xff73b7c4,0xff45ba25,0xff51c61e,0xff50c617,0xff51c61c,
+ 0xff4bc120,0xff30b50c,0x62206705,0x0,0x0,0x0,0x6e1d5899,0xff81b2e7,0xffb4d7f4,0xffbddcf7,0xffa8cef4,0xff4698a0,0xff45c407,0xff53ce00,
+ 0xff59d200,0xff54cf00,0xff46c600,0xff34bb00,0xc42d9105,0x0,0x0,0x270a305f,0xf567a5e3,0xffaed3f4,0xffafd4f5,0xffaed4f4,0xffaed3f4,0xff94c2f3,
+ 0xff4fa782,0xff6cdf00,0xff74e400,0xff6cdf00,0xff5ad300,0xff43c401,0xf742b110,0x16060b00,0x0,0xa0407dba,0xff80bcf1,0xff8ec5f2,0xff92c8f2,0xff91c8f2,
+ 0xff90c6f2,0xff86bff0,0xff67a8e6,0xff80e02c,0xff95f615,0xff8aee18,0xff7de323,0xff76db33,0xe951a31a,0x19040a00,0xd000f28,0xf066a4de,0xff88c4f2,0xff97cef5,
+ 0xffa0d4f7,0xffa0d5f7,0xff9ad0f6,0xff8dc7f3,0xff7ebcf2,0xef6ea88b,0xd679b12f,0xd271a82d,0xbb5c9221,0x8235600c,0x24060d02,0x0,0x44184c89,0xff8cc6f4,
+ 0xff99d0f6,0xffabddfa,0xffb7e6fc,0xffb8e6fc,0xffaee0fb,0xff9ed4f7,0xff90c9f3,0xc86697c9,0x3000000,0x4000000,0x0,0x0,0x0,0x0,
+ 0x2b0e3664,0xee7caed8,0xffb9e4fc,0xffcaf1fe,0xffd5f6ff,0xffd6f7ff,0xffcbf2fe,0xffbee8fc,0xffa9d6f9,0xae5378a0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x1e020c1d,0x7634547a,0xae6a88a8,0xc4849bb4,0xc689a0b8,0xbc7d9ab7,0x98627f9f,0x572c3e56,0xb000000,0x0,0x0,
+ 0x0,0x0,0x0,0x0
+};
+
+static const QRgb mask_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x11c84a00,0x1000000,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x68d14e00,0xffda6400,0x72bf4700,0x3000000,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x14d04d00,0xefda6400,0xfffec300,0xf2d86300,0x24742b00,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98d14e00,0xfff3b537,0xfffffed6,
+ 0xfff3b537,0xa5c04800,0x6000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30cf4d00,0xfbe17803,
+ 0xfff1e7ad,0xffcacaba,0xfff1e7ac,0xfce07803,0x42973800,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0xc4d35300,0xfffad45c,0xffc0c0b2,0xff979797,0xffb2b2a9,0xfffad45a,0xccca5000,0xa000000,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x58d14e00,0xffe89410,0xfffffcbd,0xffc6c6af,0xff929292,0xffbdbda8,0xfffffcb9,0xffe8930e,0x69b04100,0x2000000,0x0,0x0,0x0,
+ 0x0,0x0,0x8cb4c00,0xe3d76000,0xfffeec6c,0xffffffbe,0xffe2e2b2,0xff878787,0xffd5d5a8,0xffffffb7,0xfffeeb62,0xe8d35e00,0x17491b00,0x0,
+ 0x0,0x0,0x0,0x0,0x84d14e00,0xfff0b41a,0xfffffea3,0xffffffa8,0xfffbfba7,0xff7b7b76,0xfff6f6a0,0xffffff9c,0xfffffe8e,0xfff0b414,
+ 0x92bd4600,0x4000000,0x0,0x0,0x0,0x20d04d00,0xf7dd7400,0xfffff85e,0xffffff89,0xffffff8b,0xffffff8a,0xffc3c376,0xffffff82,0xffffff7b,
+ 0xffffff71,0xfffff746,0xf9db7300,0x32873200,0x0,0x0,0x0,0xa8d25200,0xfff6d518,0xffffff61,0xffffff65,0xffffff65,0xffecec60,0xff9f9f52,
+ 0xffe6e657,0xffffff54,0xffffff4c,0xffffff44,0xfff6d50e,0xb4c54c00,0x8000000,0x0,0x40d04e00,0xffe49001,0xfffffd2b,0xffffff3a,0xffffff3d,0xffffff3d,
+ 0xff9b9b33,0xff272727,0xff84842a,0xffffff2e,0xffffff28,0xffffff22,0xfffffd18,0xffe49000,0x52a33c00,0x2000000,0xd0d55b00,0xfffcef07,0xffffff17,0xffffff1a,
+ 0xffffff1b,0xffffff1b,0xffeaea19,0xff8c8c16,0xffdbdb13,0xffffff10,0xffffff0d,0xffffff0a,0xffffff07,0xfffcef02,0xd7ce5800,0xc000000,0xe4d55d00,0xffe49204,
+ 0xffe4940a,0xffe4950c,0xffe4960d,0xffe4950c,0xffe4950c,0xffe4940a,0xffe49308,0xffe49307,0xffe49205,0xffe39204,0xffe39102,0xffe39100,0xead05b00,0x1c000000,
+ 0x13582100,0x3c702900,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,
+ 0x29290f00,0xc000000,0x0,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,
+ 0x2000000,0x2000000,0x2000000,0x0
+};
+
+static const QRgb others_grey_data[] = {
+ 0x0,0x0,0x0,0xa4c4c4c,0x5d676767,0x777c7c7c,0x3d555555,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x17535353,0xd2afafaf,0xffebebeb,0xffe5e5e5,0xfec2c2c2,0x906d6d6d,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0xa09c9c9c,0xfff1f1f1,0xfff5f5f5,0xffe6e6e6,0xffd4d4d4,0xffbebebe,0x4c424242,0x117b7b7b,
+ 0x357d7d7d,0x177c7c7c,0x0,0x0,0x0,0x0,0x0,0x606060,0xe4b4b4b4,0xffe1e1e1,0xffe4e4e4,0xffdcdcdc,0xffcecece,0xffc0c0c0,
+ 0xd9858585,0xf3d5d5d5,0xffe6e6e6,0xf8cdcdcd,0x8c828282,0x2030303,0x0,0x0,0x0,0x0,0xdcaaaaaa,0xffd0d0d0,0xffd2d2d2,0xffcecece,
+ 0xffc5c5c5,0xffa3a3a3,0xffe8e8e8,0xfffbfbfb,0xfff4f4f4,0xffeaeaea,0xffe0e0e0,0x6f767676,0x0,0x0,0x0,0x0,0x7e848484,0xffc3c3c3,
+ 0xffc3c3c3,0xffbfbfbf,0xffaeaeae,0xffaaaaaa,0xfff1f1f1,0xfff2f2f2,0xffefefef,0xffe6e6e6,0xffe0e0e0,0xcba6a6a6,0x0,0x0,0x0,0xc3f3f3f,
+ 0xb8858585,0xff8f8f8f,0xff969696,0xff919191,0xff787878,0xffa5a5a5,0xffe7e7e7,0xffe8e8e8,0xffe5e5e5,0xffe1e1e1,0xffdcdcdc,0xd4a6a6a6,0x0,0x0,
+ 0x0,0xa1959595,0xffdbdbdb,0xffe3e3e3,0xff999999,0xff7a7a7a,0xffb9b9b9,0xffb5b5b5,0xffdedede,0xffe0e0e0,0xffdfdfdf,0xffdbdbdb,0xffd1d1d1,0x8e898989,
+ 0x0,0x0,0x28363636,0xfcb2b2b2,0xffdadada,0xffededed,0xfff5f5f5,0xffd5d5d5,0xfff5f5f5,0xffcbcbcb,0xffb7b7b7,0xffd2d2d2,0xffd3d3d3,0xffc8c8c8,
+ 0xffb2b2b2,0x78979797,0x0,0x0,0x694b4b4b,0xffafafaf,0xffc8c8c8,0xffd1d1d1,0xffd8d8d8,0xffdbdbdb,0xffb9b9b9,0xffd7d7d7,0xffe4e4e4,0xffc3c3c3,
+ 0xffa0a0a0,0xffb9b9b9,0xffd2d2d2,0xffdbdbdb,0x5e979797,0x0,0x70434343,0xff9c9c9c,0xffadadad,0xffb6b6b6,0xffbbbbbb,0xffbbbbbb,0xffb0b0b0,0xffdfdfdf,
+ 0xfff5f5f5,0xfff8f8f8,0xfff2f2f2,0xfff8f8f8,0xfff6f6f6,0xffe3e3e3,0xe6bababa,0x90b0b0b,0x30232323,0xfb767676,0xff939393,0xff9a9a9a,0xff9f9f9f,0xff969696,
+ 0xffbbbbbb,0xffdadada,0xffe3e3e3,0xffe8e8e8,0xffeaeaea,0xffe9e9e9,0xffe5e5e5,0xffdedede,0xffc8c8c8,0x41363636,0x0,0x5a2e2e2e,0xde5b5b5b,0xfe707070,
+ 0xff7a7a7a,0xff727272,0xffb3b3b3,0xffcbcbcb,0xffd1d1d1,0xffd6d6d6,0xffd8d8d8,0xffd7d7d7,0xffd3d3d3,0xffcecece,0xffbfbfbf,0x57424242,0x0,0x0,
+ 0x4000000,0x20050505,0x33070707,0x3b181818,0xf2959595,0xffbababa,0xffbfbfbf,0xffc3c3c3,0xffc5c5c5,0xffc4c4c4,0xffc1c1c1,0xffbcbcbc,0xfe9f9f9f,0x321d1d1d,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x5c5f5f5f,0xf08a8a8a,0xffa7a7a7,0xffb0b0b0,0xffb2b2b2,0xffb0b0b0,0xffa9a9a9,0xf98e8e8e,
+ 0x874c4c4c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf101010,0x4a2b2b2b,0x65424242,0x6c4a4a4a,0x67444444,
+ 0x542e2e2e,0x200f0f0f,0x0,0x0
+};
+
+static const QRgb others_data[] = {
+ 0x0,0x0,0x0,0xa804618,0x5d95643a,0x77a77c52,0x3d855126,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x17964f11,0xd2cfb190,0xfff8efdf,0xffffeccb,0xfeedce98,0x909b703f,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0xa0d29e66,0xfffff7e3,0xfffff8ec,0xffffedce,0xffffe0a9,0xfff5cd88,0x4c6f4316,0x11f72300,
+ 0x35fb2b00,0x17f82200,0x0,0x0,0x0,0x0,0x0,0xc15b00,0xe4ebbc7d,0xffffeac4,0xffffecca,0xffffe5b9,0xfffedb9e,0xfff4d38d,
+ 0xd9c76844,0xf3f6b8b4,0xfffcdad0,0xf8f5b3a6,0x8cba524a,0x2070000,0x0,0x0,0x0,0x0,0xdce9b56b,0xfffedda3,0xffffdea6,0xfffedb9e,
+ 0xfff8d592,0xffdf9f67,0xfffadad6,0xfffffaf8,0xfffef0ea,0xfffee2d6,0xfffed4c3,0x6fac4f41,0x0,0x0,0x0,0x0,0x7ecd933c,0xfff7d390,
+ 0xfff6d390,0xfff3d08b,0xffe6c377,0xffe29c73,0xfffeece4,0xfffeeee7,0xfffee9e0,0xfffddecf,0xfff9d8c8,0xcbd0927d,0x0,0x0,0x0,0xc007f00,
+ 0xb85db05a,0xffbbae64,0xffd4ab58,0xffd0a952,0xffba9636,0xffd9a571,0xfffddfd2,0xfffee0d3,0xfffdddce,0xfffbd8c8,0xfff6d2c2,0xd4d3927a,0x0,0x0,
+ 0x0,0xa171b973,0xffd4e9ce,0xffd4f2d5,0xffb2a680,0xffdb301a,0xff9cde94,0xffd3c097,0xfffbd4c2,0xfffad7c6,0xfff9d6c6,0xfff6d2c0,0xfff8c2ab,0x8ec26d51,
+ 0x0,0x0,0x28026b11,0xfc9ed391,0xffd4efc6,0xffeaf8e2,0xfff2fcee,0xffe5cdc6,0xfff4fcee,0xffb5cbe1,0xffd19da5,0xfff9c2ab,0xfff8c5ae,0xfff9b398,
+ 0xffd6918f,0x785982d5,0x0,0x0,0x691d792e,0xff9edc82,0xffbdeaa7,0xffc8edb6,0xffd0f0c0,0xffd4f2c4,0xffa8cac2,0xffbdccf2,0xffcfdefa,0xffbcb5d2,
+ 0xff9a91b0,0xffaba8ca,0xffaaccfb,0xffc4d1f2,0x5e6184ce,0x0,0x70196d2d,0xff88d663,0xff9dde7c,0xffa8e28a,0xffaee493,0xffb0e493,0xff89add8,0xffc6dbf8,
+ 0xffebf5ff,0xfff1f7ff,0xffe6f3ff,0xfff2f8ff,0xffeef6ff,0xffcfe0f8,0xe694b1e1,0x9000317,0x30004626,0xfb57b03d,0xff7ed651,0xff86d75e,0xff8cd966,0xff7cc16b,
+ 0xff84aff2,0xffb6dafe,0xffc8e4ff,0xffd2eaff,0xffd6ebff,0xffd4eaff,0xffcce6ff,0xffbee0ff,0xff96c2fb,0x410e1f5e,0x0,0x5a104c2a,0xde3b882f,0xfe51aa37,
+ 0xff5cb83c,0xff4e9c49,0xff70a8f6,0xff98cdff,0xffa4d3ff,0xffaed7ff,0xffb1d8ff,0xffb0d8ff,0xffa8d4ff,0xff9dcfff,0xff81bcfe,0x57132571,0x0,0x0,
+ 0x4000001,0x2000020a,0x3300080f,0x3b000d31,0xf24a83e0,0xff76bdff,0xff80c2ff,0xff88c5ff,0xff8cc6ff,0xff8ac6ff,0xff84c2ff,0xff7abeff,0xfe5694e9,0x32030738,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x5c1429ab,0xf03d77d8,0xff57a3f7,0xff62b0fe,0xff65b2ff,0xff63b1fe,0xff5aa6f9,0xf9427edb,
+ 0x87152a83,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000021,0x4a020554,0x650b167a,0x6c0e1d86,0x670c187d,
+ 0x5403065a,0x2000001e,0x0,0x0
+};
+
+static const QRgb user_green_data[] = {
+ 0x0,0x0,0x0,0x0,0x5029,0x6c1c6e21,0xe332aa3b,0xf83ac841,0xf838c83f,0xda369a3b,0x5a145819,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x7e1a6c1e,0xff32da39,0xff3de341,0xff3ee045,0xff3ee042,0xff3de345,0xff27d930,0x68125817,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f013105,0xf721a328,0xff22de27,0xff23dd27,0xff26dc26,0xff26dc2a,0xff22de27,
+ 0xff22de27,0xee268c2b,0x12001402,0x0,0x0,0x0,0x0,0x0,0x0,0x5c0b590f,0xff19b51d,0xff1ecc1e,0xff1dd31d,0xff22d41e,
+ 0xff1ed41e,0xff1cd21c,0xff1dcb21,0xff18b01b,0x4d093d0d,0x0,0x0,0x0,0x0,0x0,0x0,0x640f5f13,0xff18bc18,0xff1ec61a,
+ 0xff1ed119,0xff22d519,0xff22d519,0xff22ce1a,0xff1fc31b,0xff16be1a,0x5a0e4211,0x0,0x0,0x0,0x0,0x0,0x0,0x38033507,
+ 0xff1db91d,0xff21d818,0xff24e616,0xff2aec16,0xff2aec16,0xff24e416,0xff21d418,0xfd20b020,0x35031b05,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x2000000,0xbb2a702c,0xff2df018,0xff3af41c,0xff48f620,0xff46fa1c,0xff39f21a,0xff23ef13,0xb929632c,0x4000000,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x2e012703,0xfc279129,0xff3fe729,0xff5ff537,0xff5bf632,0xff2ef11f,0xf6298f2e,0x29010d02,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x6000e07,0xc41f7721,0xff1ee01e,0xff29dd2d,0xff22de27,0xff22de27,0xff2bdf34,0xff1ddf21,0xab227226,
+ 0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x6d136117,0xff1bc31b,0xff1ee01e,0xff24e020,0xff25e220,0xff25e220,0xff20e020,
+ 0xff20dc20,0xff1bbf1e,0x561b571f,0x0,0x0,0x0,0x0,0x0,0x8001205,0xe2268e29,0xff1eca1a,0xff23d41a,0xff23d81a,0xff23d81a,
+ 0xff23d81a,0xff23d81a,0xff24d11b,0xff1fc71b,0xd12a882c,0x4000000,0x0,0x0,0x0,0x0,0x4a0e5012,0xff1cc818,0xff21d119,0xff25db17,
+ 0xff25e117,0xff24e616,0xff24e616,0xff27df19,0xff21da18,0xff22cf19,0xff18c418,0x3a173d19,0x0,0x0,0x0,0x0,0x982b732c,0xff1ed915,
+ 0xff25dd17,0xff28ec14,0xff32f018,0xff34f21a,0xff32f218,0xff2af016,0xff28ea14,0xff20db17,0xff1bd317,0x85316f34,0x0,0x0,0x0,0x0,
+ 0xbf318131,0xff22e818,0xff2aea16,0xff39ef1b,0xff44fa1a,0xff4dfa1e,0xff4dfa1e,0xff3ff71b,0xff30f016,0xff2ae616,0xff20e616,0xb3337936,0x0,0x0,
+ 0x0,0x0,0x51134b16,0xed369834,0xff2ef11f,0xff54f828,0xff67fc2c,0xff6bfb33,0xff6ffc30,0xff5ffc28,0xff48f925,0xff30f41c,0xec33a135,0x561b3d1e,
+ 0x0,0x0,0x0,0x0,0x0,0x18000802,0x60113b14,0x9d315f33,0xbb417143,0xc6467848,0xc6467a48,0xbc417942,0x9e3c663e,0x64224225,
+ 0x1c020604,0x0,0x0,0x0
+};
+
+static const QRgb user_grey_data[] = {
+ 0x0,0x0,0x0,0x0,0x404040,0x6c6e6e6e,0xe3b0b0b0,0xf8cecece,0xf8cccccc,0xdaa6a6a6,0x5a575757,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x7e6b6b6b,0xffd6d6d6,0xffe6e6e6,0xffe4e4e4,0xffe4e4e4,0xffe6e6e6,0xffcccccc,0x68555555,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f282828,0xf79d9d9d,0xffcccccc,0xffcdcdcd,0xffcecece,0xffcecece,0xffcccccc,
+ 0xffcccccc,0xee8f8f8f,0x12101010,0x0,0x0,0x0,0x0,0x0,0x0,0x5c515151,0xffa5a5a5,0xffbbbbbb,0xffc0c0c0,0xffc1c1c1,
+ 0xffc1c1c1,0xffbfbfbf,0xffbababa,0xffa0a0a0,0x4d383838,0x0,0x0,0x0,0x0,0x0,0x0,0x64585858,0xffaaaaaa,0xffb4b4b4,
+ 0xffbcbcbc,0xffbfbfbf,0xffbfbfbf,0xffbababa,0xffb2b2b2,0xffa9a9a9,0x5a404040,0x0,0x0,0x0,0x0,0x0,0x0,0x382e2e2e,
+ 0xffababab,0xffc0c0c0,0xffc9c9c9,0xffcfcfcf,0xffcecece,0xffc8c8c8,0xffbdbdbd,0xfda6a6a6,0x35181818,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x2000000,0xbb7c7c7c,0xffd3d3d3,0xffd9d9d9,0xffdfdfdf,0xffdedede,0xffd7d7d7,0xffcecece,0xb9717171,0x4000000,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x2e202020,0xfc939393,0xffdadada,0xfff0f0f0,0xffededed,0xffdadada,0xf6949494,0x290c0c0c,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x60c0c0c,0xc4787878,0xffcbcbcb,0xffd2d2d2,0xffcccccc,0xffcccccc,0xffd4d4d4,0xffc9c9c9,0xab777777,
+ 0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x6d5d5d5d,0xffb2b2b2,0xffcbcbcb,0xffcccccc,0xffcecece,0xffcecece,0xffcccccc,
+ 0xffcacaca,0xffafafaf,0x565c5c5c,0x0,0x0,0x0,0x0,0x0,0x80f0f0f,0xe2909090,0xffb7b7b7,0xffbebebe,0xffc1c1c1,0xffc1c1c1,
+ 0xffc1c1c1,0xffc1c1c1,0xffbdbdbd,0xffb5b5b5,0xd18f8f8f,0x4000000,0x0,0x0,0x0,0x0,0x4a4c4c4c,0xffb3b3b3,0xffbbbbbb,0xffc2c2c2,
+ 0xffc7c7c7,0xffc9c9c9,0xffc9c9c9,0xffc6c6c6,0xffc1c1c1,0xffb9b9b9,0xffb0b0b0,0x3a434343,0x0,0x0,0x0,0x0,0x987e7e7e,0xffbfbfbf,
+ 0xffc4c4c4,0xffcdcdcd,0xffd3d3d3,0xffd6d6d6,0xffd5d5d5,0xffd1d1d1,0xffcbcbcb,0xffc2c2c2,0xffbbbbbb,0x85808080,0x0,0x0,0x0,0x0,
+ 0xbf8e8e8e,0xffcccccc,0xffcccccc,0xffd5d5d5,0xffdddddd,0xffe0e0e0,0xffe0e0e0,0xffdbdbdb,0xffd2d2d2,0xffcacaca,0xffcacaca,0xb38a8a8a,0x0,0x0,
+ 0x0,0x0,0x514b4b4b,0xeda4a4a4,0xffdadada,0xffe7e7e7,0xffededed,0xfff1f1f1,0xfff0f0f0,0xffeaeaea,0xffe4e4e4,0xffdadada,0xeca9a9a9,0x56474747,
+ 0x0,0x0,0x0,0x0,0x0,0x18070707,0x603e3e3e,0x9d747474,0xbb8e8e8e,0xc6989898,0xc69a9a9a,0xbc959595,0x9e828282,0x64505050,
+ 0x1c070707,0x0,0x0,0x0
+};
+
+static const QRgb user_data[] = {
+ 0x0,0x0,0x0,0x0,0x7f,0x6c2c68af,0xe384abdb,0xf8b2ccea,0xf8aecae9,0xda7ba3d1,0x5a20508d,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x7e2a66ac,0xffb8d4f3,0xffd2e5f9,0xffd0e3f8,0xffcfe3f8,0xffd3e5f9,0xffa7c9f0,0x681d4e8c,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f02244d,0xf75c9ade,0xffa6cbf2,0xffa7ccf2,0xffa9cef2,0xffa9cdf2,0xffa6ccf2,
+ 0xffa6ccf2,0xee4d8bd0,0x12000d1f,0x0,0x0,0x0,0x0,0x0,0x0,0x5c124c8f,0xff60a4ea,0xff88bcee,0xff8fc1f0,0xff92c4f0,
+ 0xff92c3f0,0xff8ec0f0,0xff85baee,0xff579fe9,0x4d0f3460,0x0,0x0,0x0,0x0,0x0,0x0,0x64185598,0xff67acec,0xff7ab8ee,
+ 0xff87c1f1,0xff8cc5f2,0xff8cc5f2,0xff84c0f0,0xff76b6ed,0xff63a9ee,0x5a173d69,0x0,0x0,0x0,0x0,0x0,0x0,0x38052a56,
+ 0xff6caee9,0xff8cc6f3,0xff9cd2f6,0xffa5d8f8,0xffa4d7f8,0xff99d0f6,0xff88c3f2,0xfd68a7e4,0x3505152b,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x2000000,0xbb447bb3,0xffabdbfa,0xffb6e4fc,0xffc0ecfe,0xffbeebfe,0xffb3e2fb,0xffa2d6f9,0xb9426e9f,0x4000000,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x2e011c3e,0xfc5491d2,0xffbce2f8,0xffe1f6fe,0xffdcf5fe,0xffb9e0fb,0xf65790d0,0x29010b17,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x6000017,0xc43276be,0xffa2cbf3,0xffb0d1f3,0xffa6cbf2,0xffa6cbf2,0xffb4d2f4,0xff9ec9f3,0xab3774b7,
+ 0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x6d1f599b,0xff76b3ed,0xffa3ccf3,0xffa5cff3,0xffa7d0f4,0xffa7d0f4,0xffa5cef3,
+ 0xffa2ccf2,0xff71afed,0x562c578c,0x0,0x0,0x0,0x0,0x0,0x800071e,0xe24f8fd0,0xff7ebaef,0xff8bc4f1,0xff90c7f2,0xff8fc7f2,
+ 0xff8fc6f2,0xff8fc6f2,0xff89c2f0,0xff7bb8ee,0xd1538dca,0x4000000,0x0,0x0,0x0,0x0,0x4a164781,0xff77b8ef,0xff85c2f1,0xff90caf4,
+ 0xff98cff5,0xff9cd2f6,0xff9bd1f6,0xff97cef5,0xff8ec8f3,0xff82bff0,0xff72b2ee,0x3a244062,0x0,0x0,0x0,0x0,0x98447db7,0xff8ac5f4,
+ 0xff94ccf4,0xffa1d6f8,0xffabddfa,0xffb0e0fb,0xffafe0fb,0xffa8dbfa,0xff9ed4f7,0xff90c9f4,0xff83c0f3,0x854d7cb2,0x0,0x0,0x0,0x0,
+ 0xbf5a8fc1,0xffa1d2f6,0xffa0d6f7,0xffafe0fa,0xffbceafe,0xffc2eefe,0xffc2eefe,0xffb9e8fd,0xffaaddfa,0xff9ed3f6,0xff9dd0f6,0xb35a88ba,0x0,0x0,
+ 0x0,0x0,0x511f4776,0xed77a7d1,0xffb8e0fb,0xffcff1fe,0xffdaf8ff,0xffe2f9ff,0xffe0f9ff,0xffd5f6ff,0xffcaeefe,0xffb8e1fc,0xec7ca9d6,0x562c4462,
+ 0x0,0x0,0x0,0x0,0x0,0x1800030d,0x601b3a61,0x9d4f7198,0xbb6e8cad,0xc67d96b3,0xc67d98b6,0xbc7494b5,0x9e6180a3,0x64364c69,
+ 0x1c040409,0x0,0x0,0x0
+};
+
+static const QRgb yes_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x11049c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x1005a200,0x800ba600,0xd512a700,0xe1009d00,0x34007700,0x1000000,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x8009500,0x78009b00,0xf0039f03,0xe2009800,0x46003700,0xbb009300,0xeb11a111,0x35006f00,0x1000000,0x0,0x0,
+ 0x0,0x0,0x0,0x8008d00,0x70009300,0xe819ab19,0xff3ec63e,0xd4099109,0x45002c00,0xf000000,0x6f008900,0xff33d633,0xeb0a9e0a,0x35006800,
+ 0x1000000,0x0,0x0,0x4008900,0x6c008a00,0xe8099e09,0xff2cd52c,0xff3bd93b,0xcb048404,0x3c001c00,0xc000000,0x0,0x28007a00,0xff0abc0a,
+ 0xff10f410,0xeb019701,0x35006100,0x5006d00,0x60008100,0xdc009800,0xff06d206,0xff13fd13,0xff11ce11,0xc2017801,0x32000b00,0xa000000,0x0,0x0,
+ 0x1000000,0xde009100,0xff00f700,0xff00eb00,0xeb008e00,0xde008700,0xff00c400,0xff00f500,0xff00f700,0xff00c100,0xae006700,0x30000b00,0x8000000,0x0,
+ 0x0,0x0,0x0,0x97007100,0xff00dc00,0xff00eb00,0xff00e500,0xff00e700,0xff00eb00,0xff00eb00,0xff00a800,0xa2005c00,0x29000000,0x6000000,
+ 0x0,0x0,0x0,0x0,0x0,0x4c006600,0xff00af00,0xff00de00,0xff00de00,0xff00de00,0xff00dc00,0xff009600,0x96005100,0x24000000,
+ 0x5000000,0x0,0x0,0x0,0x0,0x0,0x0,0xa004e00,0xf8008200,0xff00d200,0xff00d200,0xff00ce00,0xfc008700,0x80004100,
+ 0x21000000,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbb005f00,0xff00c300,0xff00c100,0xf6007500,
+ 0x76003800,0x1d000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6f005800,0xff009700,
+ 0xf4006d00,0x6c003200,0x19000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x28005300,0xed005900,0x5a002800,0x16000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x1000000,0x15000000,0x12000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0
+};
+
+static const QRgb yespartial_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x114e4e4e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x10515151,0x80535353,0xd5535353,0xe14e4e4e,0x343b3b3b,0x1000000,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x84a4a4a,0x784d4d4d,0x9e515151,0xe24c4c4c,0x461b1b1b,0xbb494949,0xeb595959,0x35373737,0x1000000,0x0,0x0,
+ 0x0,0x0,0x0,0x8464646,0x70494949,0xe8626262,0x93828282,0xc34d4d4d,0x45161616,0xf000000,0x6f444444,0x8c848484,0xcf545454,0x35343434,
+ 0x1000000,0x0,0x0,0x4444444,0x6c454545,0xe5535353,0x57808080,0x5e8a8a8a,0xcb444444,0x3c0e0e0e,0xc000000,0x0,0x283d3d3d,0xa7636363,
+ 0x32828282,0xeb4c4c4c,0x35303030,0x5363636,0x60404040,0xdc4c4c4c,0x756c6c6c,0x2b888888,0x7b6f6f6f,0xc23c3c3c,0x32050505,0xa000000,0x0,0x0,
+ 0x1000000,0xde484848,0x3c7b7b7b,0x1f757575,0xeb474747,0xde434343,0x80626262,0x3c7a7a7a,0x337b7b7b,0x56606060,0xae333333,0x30050505,0x8000000,0x0,
+ 0x0,0x0,0x0,0x97383838,0x4c6e6e6e,0xa757575,0x3727272,0x24737373,0x2b757575,0x27757575,0x75545454,0x952e2e2e,0x29000000,0x6000000,
+ 0x0,0x0,0x0,0x0,0x0,0x4c333333,0x8e575757,0x1c6f6f6f,0x46f6f6f,0xb6f6f6f,0x2b6e6e6e,0x994b4b4b,0x85282828,0x24000000,
+ 0x5000000,0x0,0x0,0x0,0x0,0x0,0x0,0xa272727,0xdc414141,0x3d696969,0x11696969,0x1e676767,0x91434343,0x77202020,
+ 0x21000000,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbb2f2f2f,0x5d616161,0x36606060,0x893a3a3a,
+ 0x761c1c1c,0x1d000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6f2c2c2c,0x9a4b4b4b,
+ 0x9b363636,0x6c191919,0x19000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x28292929,0xed2c2c2c,0x5a141414,0x16000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x1000000,0x15000000,0x12000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0
+};
+
+static struct EmbedImage {
+ int width, height, depth;
+ const unsigned char *data;
+ int numColors;
+ const QRgb *colorTable;
+ bool alpha;
+ const char *name;
+} embed_image_vec[] = {
+ { 16, 16, 32, (const unsigned char*)group_grey_data, 0, 0, TRUE, "group-grey" },
+ { 16, 16, 32, (const unsigned char*)group_data, 0, 0, TRUE, "group" },
+ { 16, 16, 32, (const unsigned char*)mask_data, 0, 0, TRUE, "mask" },
+ { 16, 16, 32, (const unsigned char*)others_grey_data, 0, 0, TRUE, "others-grey" },
+ { 16, 16, 32, (const unsigned char*)others_data, 0, 0, TRUE, "others" },
+ { 16, 16, 32, (const unsigned char*)user_green_data, 0, 0, TRUE, "user-green" },
+ { 16, 16, 32, (const unsigned char*)user_grey_data, 0, 0, TRUE, "user-grey" },
+ { 16, 16, 32, (const unsigned char*)user_data, 0, 0, TRUE, "user" },
+ { 16, 16, 32, (const unsigned char*)yes_data, 0, 0, TRUE, "yes" },
+ { 16, 16, 32, (const unsigned char*)yespartial_data, 0, 0, TRUE, "yespartial" },
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static const QImage& qembed_findImage( const QString& name )
+{
+ static QDict<QImage> dict;
+ QImage* img = dict.find( name );
+ if ( !img ) {
+ for ( int i = 0; embed_image_vec[i].data; i++ ) {
+ if ( strcmp(embed_image_vec[i].name, name.latin1()) == 0 ) {
+ img = new QImage((uchar*)embed_image_vec[i].data,
+ embed_image_vec[i].width,
+ embed_image_vec[i].height,
+ embed_image_vec[i].depth,
+ (QRgb*)embed_image_vec[i].colorTable,
+ embed_image_vec[i].numColors,
+ QImage::BigEndian );
+ if ( embed_image_vec[i].alpha )
+ img->setAlphaBuffer( TRUE );
+ dict.insert( name, img );
+ break;
+ }
+ }
+ if ( !img ) {
+ static QImage dummy;
+ return dummy;
+ }
+ }
+ return *img;
+}
+
+#endif
+#endif
diff --git a/kio/kfile/kacleditwidget.cpp b/kio/kfile/kacleditwidget.cpp
new file mode 100644
index 000000000..41a5af7bd
--- /dev/null
+++ b/kio/kfile/kacleditwidget.cpp
@@ -0,0 +1,1054 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> *
+ * Till Adam <adam@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+
+#include "kacleditwidget.h"
+#include "kacleditwidget_p.h"
+
+#ifdef USE_POSIX_ACL
+
+#include <qpainter.h>
+#include <qptrlist.h>
+#include <qvbox.h>
+#include <qhbox.h>
+#include <qpushbutton.h>
+#include <qvbuttongroup.h>
+#include <qradiobutton.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qwidgetstack.h>
+#include <qheader.h>
+
+#include <klocale.h>
+#include <kfileitem.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+
+#ifdef HAVE_ACL_LIBACL_H
+# include <acl/libacl.h>
+#endif
+extern "C" {
+#include <pwd.h>
+#include <grp.h>
+}
+#include <assert.h>
+
+#include "images.h"
+
+static struct {
+ const char* label;
+ const char* pixmapName;
+ QPixmap* pixmap;
+} s_itemAttributes[] = {
+ { I18N_NOOP( "Owner" ), "user-grey", 0 },
+ { I18N_NOOP( "Owning Group" ), "group-grey", 0 },
+ { I18N_NOOP( "Others" ), "others-grey", 0 },
+ { I18N_NOOP( "Mask" ), "mask", 0 },
+ { I18N_NOOP( "Named User" ), "user", 0 },
+ { I18N_NOOP( "Named Group" ), "group", 0 },
+};
+
+KACLEditWidget::KACLEditWidget( QWidget *parent, const char *name )
+ :QWidget( parent, name )
+{
+ QHBox *hbox = new QHBox( parent );
+ hbox->setSpacing( KDialog::spacingHint() );
+ m_listView = new KACLListView( hbox, "acl_listview" );
+ connect( m_listView, SIGNAL( selectionChanged() ),
+ this, SLOT( slotUpdateButtons() ) );
+ QVBox *vbox = new QVBox( hbox );
+ vbox->setSpacing( KDialog::spacingHint() );
+ m_AddBtn = new QPushButton( i18n( "Add Entry..." ), vbox, "add_entry_button" );
+ connect( m_AddBtn, SIGNAL( clicked() ), m_listView, SLOT( slotAddEntry() ) );
+ m_EditBtn = new QPushButton( i18n( "Edit Entry..." ), vbox, "edit_entry_button" );
+ connect( m_EditBtn, SIGNAL( clicked() ), m_listView, SLOT( slotEditEntry() ) );
+ m_DelBtn = new QPushButton( i18n( "Delete Entry" ), vbox, "delete_entry_button" );
+ connect( m_DelBtn, SIGNAL( clicked() ), m_listView, SLOT( slotRemoveEntry() ) );
+ QWidget *spacer = new QWidget( vbox );
+ spacer->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding );
+ slotUpdateButtons();
+}
+
+void KACLEditWidget::slotUpdateButtons()
+{
+ bool atLeastOneIsNotDeletable = false;
+ bool atLeastOneIsNotAllowedToChangeType = false;
+ int selectedCount = 0;
+ QListViewItemIterator it( m_listView, QListViewItemIterator::Selected );
+ while ( KACLListViewItem *item = dynamic_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it; ++selectedCount;
+ if ( !item->isDeletable() )
+ atLeastOneIsNotDeletable = true;
+ if ( !item->isAllowedToChangeType() )
+ atLeastOneIsNotAllowedToChangeType = true;
+ }
+ m_EditBtn->setEnabled( selectedCount && !atLeastOneIsNotAllowedToChangeType );
+ m_DelBtn->setEnabled( selectedCount && !atLeastOneIsNotDeletable );
+}
+
+KACL KACLEditWidget::getACL() const
+{
+ return m_listView->getACL();
+}
+
+KACL KACLEditWidget::getDefaultACL() const
+{
+ return m_listView->getDefaultACL();
+}
+
+void KACLEditWidget::setACL( const KACL &acl )
+{
+ return m_listView->setACL( acl );
+}
+
+void KACLEditWidget::setDefaultACL( const KACL &acl )
+{
+ return m_listView->setDefaultACL( acl );
+}
+
+void KACLEditWidget::setAllowDefaults( bool value )
+{
+ m_listView->setAllowDefaults( value );
+}
+
+void KACLEditWidget::setReadOnly( bool on )
+{
+ m_listView->setEnabled( !on );
+ m_AddBtn->setEnabled( !on );
+ if ( !on )
+ slotUpdateButtons();
+}
+
+KACLListViewItem::KACLListViewItem( QListView* parent,
+ KACLListView::EntryType _type,
+ unsigned short _value, bool defaults,
+ const QString& _qualifier )
+ : KListViewItem( parent, parent->lastItem() ), // we want to append
+ type( _type ), value( _value ), isDefault( defaults ),
+ qualifier( _qualifier ), isPartial( false )
+{
+ m_pACLListView = dynamic_cast<KACLListView*>( parent );
+ repaint();
+}
+
+
+KACLListViewItem::~ KACLListViewItem()
+{
+
+}
+
+QString KACLListViewItem::key( int, bool ) const
+{
+ QString key;
+ if ( !isDefault )
+ key = "A";
+ else
+ key = "B";
+ switch ( type )
+ {
+ case KACLListView::User:
+ key += "A";
+ break;
+ case KACLListView::Group:
+ key += "B";
+ break;
+ case KACLListView::Others:
+ key += "C";
+ break;
+ case KACLListView::Mask:
+ key += "D";
+ break;
+ case KACLListView::NamedUser:
+ key += "E" + text( 1 );
+ break;
+ case KACLListView::NamedGroup:
+ key += "F" + text( 1 );
+ break;
+ default:
+ key += text( 0 );
+ break;
+ }
+ return key;
+}
+
+void KACLListViewItem::paintCell( QPainter* p, const QColorGroup &cg,
+ int column, int width, int alignment )
+{
+ QColorGroup mycg = cg;
+ if ( isDefault ) {
+ mycg.setColor( QColorGroup::Text, QColor( 0, 0, 255 ) );
+ }
+ if ( isPartial ) {
+ QFont font = p->font();
+ font.setItalic( true );
+ mycg.setColor( QColorGroup::Text, QColor( 100, 100, 100 ) );
+ p->setFont( font );
+ }
+ KListViewItem::paintCell( p, mycg, column, width, alignment );
+
+ KACLListViewItem *below =0;
+ if ( itemBelow() )
+ below = static_cast<KACLListViewItem*>( itemBelow() );
+ const bool lastUser = type == KACLListView::NamedUser && below && below->type == KACLListView::NamedGroup;
+ const bool lastNonDefault = !isDefault && below && below->isDefault;
+ if ( type == KACLListView::Mask || lastUser || lastNonDefault )
+ {
+ p->setPen( QPen( Qt::gray, 0, QPen::DotLine ) );
+ if ( type == KACLListView::Mask )
+ p->drawLine( 0, 0, width - 1, 0 );
+ p->drawLine( 0, height() - 1, width - 1, height() - 1 );
+ }
+}
+
+
+void KACLListViewItem::updatePermPixmaps()
+{
+ unsigned int partialPerms = value;
+
+ if ( value & ACL_READ )
+ setPixmap( 2, m_pACLListView->getYesPixmap() );
+ else if ( partialPerms & ACL_READ )
+ setPixmap( 2, m_pACLListView->getYesPartialPixmap() );
+ else
+ setPixmap( 2, QPixmap() );
+
+ if ( value & ACL_WRITE )
+ setPixmap( 3, m_pACLListView->getYesPixmap() );
+ else if ( partialPerms & ACL_WRITE )
+ setPixmap( 3, m_pACLListView->getYesPartialPixmap() );
+ else
+ setPixmap( 3, QPixmap() );
+
+ if ( value & ACL_EXECUTE )
+ setPixmap( 4, m_pACLListView->getYesPixmap() );
+ else if ( partialPerms & ACL_EXECUTE )
+ setPixmap( 4, m_pACLListView->getYesPartialPixmap() );
+ else
+ setPixmap( 4, QPixmap() );
+}
+
+void KACLListViewItem::repaint()
+{
+ int idx = 0;
+ switch ( type )
+ {
+ case KACLListView::User:
+ idx = KACLListView::OWNER_IDX;
+ break;
+ case KACLListView::Group:
+ idx = KACLListView::GROUP_IDX;
+ break;
+ case KACLListView::Others:
+ idx = KACLListView::OTHERS_IDX;
+ break;
+ case KACLListView::Mask:
+ idx = KACLListView::MASK_IDX;
+ break;
+ case KACLListView::NamedUser:
+ idx = KACLListView::NAMED_USER_IDX;
+ break;
+ case KACLListView::NamedGroup:
+ idx = KACLListView::NAMED_GROUP_IDX;
+ break;
+ default:
+ idx = KACLListView::OWNER_IDX;
+ break;
+ }
+ setText( 0, i18n(s_itemAttributes[idx].label) );
+ setPixmap( 0, *s_itemAttributes[idx].pixmap );
+ if ( isDefault )
+ setText( 0, text( 0 ) + i18n( " (Default)" ) );
+ setText( 1, qualifier );
+ // Set the pixmaps for which of the perms are set
+ updatePermPixmaps();
+}
+
+void KACLListViewItem::calcEffectiveRights()
+{
+ QString strEffective = QString( "---" );
+
+ // Do we need to worry about the mask entry? It applies to named users,
+ // owning group, and named groups
+ if ( m_pACLListView->hasMaskEntry()
+ && ( type == KACLListView::NamedUser
+ || type == KACLListView::Group
+ || type == KACLListView::NamedGroup )
+ && !isDefault )
+ {
+
+ strEffective[0] = ( m_pACLListView->maskPermissions() & value & ACL_READ ) ? 'r' : '-';
+ strEffective[1] = ( m_pACLListView->maskPermissions() & value & ACL_WRITE ) ? 'w' : '-';
+ strEffective[2] = ( m_pACLListView->maskPermissions() & value & ACL_EXECUTE ) ? 'x' : '-';
+/*
+ // What about any partial perms?
+ if ( maskPerms & partialPerms & ACL_READ || // Partial perms on entry
+ maskPartialPerms & perms & ACL_READ || // Partial perms on mask
+ maskPartialPerms & partialPerms & ACL_READ ) // Partial perms on mask and entry
+ strEffective[0] = 'R';
+ if ( maskPerms & partialPerms & ACL_WRITE || // Partial perms on entry
+ maskPartialPerms & perms & ACL_WRITE || // Partial perms on mask
+ maskPartialPerms & partialPerms & ACL_WRITE ) // Partial perms on mask and entry
+ strEffective[1] = 'W';
+ if ( maskPerms & partialPerms & ACL_EXECUTE || // Partial perms on entry
+ maskPartialPerms & perms & ACL_EXECUTE || // Partial perms on mask
+ maskPartialPerms & partialPerms & ACL_EXECUTE ) // Partial perms on mask and entry
+ strEffective[2] = 'X';
+*/
+ }
+ else
+ {
+ // No, the effective value are just the value in this entry
+ strEffective[0] = ( value & ACL_READ ) ? 'r' : '-';
+ strEffective[1] = ( value & ACL_WRITE ) ? 'w' : '-';
+ strEffective[2] = ( value & ACL_EXECUTE ) ? 'x' : '-';
+
+ /*
+ // What about any partial perms?
+ if ( partialPerms & ACL_READ )
+ strEffective[0] = 'R';
+ if ( partialPerms & ACL_WRITE )
+ strEffective[1] = 'W';
+ if ( partialPerms & ACL_EXECUTE )
+ strEffective[2] = 'X';
+ */
+ }
+ setText( 5, strEffective );
+}
+
+bool KACLListViewItem::isDeletable() const
+{
+ bool isMaskAndDeletable = false;
+ if (type == KACLListView::Mask ) {
+ if ( !isDefault && m_pACLListView->maskCanBeDeleted() )
+ isMaskAndDeletable = true;
+ else if ( isDefault && m_pACLListView->defaultMaskCanBeDeleted() )
+ isMaskAndDeletable = true;
+ }
+ return type != KACLListView::User &&
+ type != KACLListView::Group &&
+ type != KACLListView::Others &&
+ ( type != KACLListView::Mask || isMaskAndDeletable );
+}
+
+bool KACLListViewItem::isAllowedToChangeType() const
+{
+ return type != KACLListView::User &&
+ type != KACLListView::Group &&
+ type != KACLListView::Others &&
+ type != KACLListView::Mask;
+}
+
+void KACLListViewItem::togglePerm( acl_perm_t perm )
+{
+ value ^= perm; // Toggle the perm
+ if ( type == KACLListView::Mask && !isDefault ) {
+ m_pACLListView->setMaskPermissions( value );
+ }
+ calcEffectiveRights();
+ updatePermPixmaps();
+/*
+ // If the perm is in the partial perms then remove it. i.e. Once
+ // a user changes a partial perm it then applies to all selected files.
+ if ( m_pEntry->m_partialPerms & perm )
+ m_pEntry->m_partialPerms ^= perm;
+
+ m_pEntry->setPartialEntry( false );
+ // Make sure that all entries have their effective rights calculated if
+ // we are changing the ACL_MASK entry.
+ if ( type == Mask )
+ {
+ m_pACLListView->setMaskPartialPermissions( m_pEntry->m_partialPerms );
+ m_pACLListView->setMaskPermissions( value );
+ m_pACLListView->calculateEffectiveRights();
+ }
+*/
+}
+
+
+
+EditACLEntryDialog::EditACLEntryDialog( KACLListView *listView, KACLListViewItem *item,
+ const QStringList &users,
+ const QStringList &groups,
+ const QStringList &defaultUsers,
+ const QStringList &defaultGroups,
+ int allowedTypes, int allowedDefaultTypes,
+ bool allowDefaults )
+ : KDialogBase( listView, "edit_entry_dialog", true,
+ i18n( "Edit ACL Entry" ), KDialogBase::Ok|KDialogBase::Cancel,
+ KDialogBase::Ok, false ),
+ m_listView( listView ), m_item( item ), m_users( users ), m_groups( groups ),
+ m_defaultUsers( defaultUsers ), m_defaultGroups( defaultGroups ),
+ m_allowedTypes( allowedTypes ), m_allowedDefaultTypes( allowedDefaultTypes ),
+ m_defaultCB( 0 )
+{
+ QWidget *page = new QWidget( this );
+ setMainWidget( page );
+ QVBoxLayout *mainLayout = new QVBoxLayout( page, 0, spacingHint(), "mainLayout" );
+ m_buttonGroup = new QVButtonGroup( i18n("Entry Type"), page, "bg" );
+
+ if ( allowDefaults ) {
+ m_defaultCB = new QCheckBox( i18n("Default for new files in this folder"), page, "defaultCB" );
+ mainLayout->addWidget( m_defaultCB );
+ connect( m_defaultCB, SIGNAL( toggled( bool ) ),
+ this, SLOT( slotUpdateAllowedUsersAndGroups() ) );
+ connect( m_defaultCB, SIGNAL( toggled( bool ) ),
+ this, SLOT( slotUpdateAllowedTypes() ) );
+
+ }
+
+ mainLayout->addWidget( m_buttonGroup );
+
+ QRadioButton *ownerType = new QRadioButton( i18n("Owner"), m_buttonGroup, "ownerType" );
+ m_buttonGroup->insert( ownerType, KACLListView::User );
+ QRadioButton *owningGroupType = new QRadioButton( i18n("Owning Group"), m_buttonGroup, "owningGroupType" );
+ m_buttonGroup->insert( owningGroupType, KACLListView::Group );
+ QRadioButton *othersType = new QRadioButton( i18n("Others"), m_buttonGroup, "othersType" );
+ m_buttonGroup->insert( othersType, KACLListView::Others );
+ QRadioButton *maskType = new QRadioButton( i18n("Mask"), m_buttonGroup, "maskType" );
+ m_buttonGroup->insert( maskType, KACLListView::Mask );
+ QRadioButton *namedUserType = new QRadioButton( i18n("Named User"), m_buttonGroup, "namesUserType" );
+ m_buttonGroup->insert( namedUserType, KACLListView::NamedUser );
+ QRadioButton *namedGroupType = new QRadioButton( i18n("Named Group"), m_buttonGroup, "namedGroupType" );
+ m_buttonGroup->insert( namedGroupType, KACLListView::NamedGroup );
+
+ connect( m_buttonGroup, SIGNAL( clicked( int ) ),
+ this, SLOT( slotSelectionChanged( int ) ) );
+
+ m_widgetStack = new QWidgetStack( page );
+ mainLayout->addWidget( m_widgetStack );
+
+ QHBox *usersBox = new QHBox( m_widgetStack );
+ m_widgetStack->addWidget( usersBox, KACLListView::NamedUser );
+
+ QHBox *groupsBox = new QHBox( m_widgetStack );
+ m_widgetStack->addWidget( groupsBox, KACLListView::NamedGroup );
+
+ QLabel *usersLabel = new QLabel( i18n( "User: " ), usersBox );
+ m_usersCombo = new QComboBox( false, usersBox, "users" );
+ usersLabel->setBuddy( m_usersCombo );
+
+ QLabel *groupsLabel = new QLabel( i18n( "Group: " ), groupsBox );
+ m_groupsCombo = new QComboBox( false, groupsBox, "groups" );
+ groupsLabel->setBuddy( m_groupsCombo );
+
+ if ( m_item ) {
+ m_buttonGroup->setButton( m_item->type );
+ if ( m_defaultCB )
+ m_defaultCB->setChecked( m_item->isDefault );
+ slotUpdateAllowedTypes();
+ slotSelectionChanged( m_item->type );
+ slotUpdateAllowedUsersAndGroups();
+ if ( m_item->type == KACLListView::NamedUser ) {
+ m_usersCombo->setCurrentText( m_item->qualifier );
+ } else if ( m_item->type == KACLListView::NamedGroup ) {
+ m_groupsCombo->setCurrentText( m_item->qualifier );
+ }
+ } else {
+ // new entry, preselect "named user", arguably the most common one
+ m_buttonGroup->setButton( KACLListView::NamedUser );
+ slotUpdateAllowedTypes();
+ slotSelectionChanged( KACLListView::NamedUser );
+ slotUpdateAllowedUsersAndGroups();
+ }
+ incInitialSize( QSize( 100, 0 ) );
+}
+
+void EditACLEntryDialog::slotUpdateAllowedTypes()
+{
+ int allowedTypes = m_allowedTypes;
+ if ( m_defaultCB && m_defaultCB->isChecked() ) {
+ allowedTypes = m_allowedDefaultTypes;
+ }
+ for ( int i=1; i < KACLListView::AllTypes; i=i*2 ) {
+ if ( allowedTypes & i )
+ m_buttonGroup->find( i )->show();
+ else
+ m_buttonGroup->find( i )->hide();
+ }
+}
+
+void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups()
+{
+ const QString oldUser = m_usersCombo->currentText();
+ const QString oldGroup = m_groupsCombo->currentText();
+ m_usersCombo->clear();
+ m_groupsCombo->clear();
+ if ( m_defaultCB && m_defaultCB->isChecked() ) {
+ m_usersCombo->insertStringList( m_defaultUsers );
+ if ( m_defaultUsers.find( oldUser ) != m_defaultUsers.end() )
+ m_usersCombo->setCurrentText( oldUser );
+ m_groupsCombo->insertStringList( m_defaultGroups );
+ if ( m_defaultGroups.find( oldGroup ) != m_defaultGroups.end() )
+ m_groupsCombo->setCurrentText( oldGroup );
+ } else {
+ m_usersCombo->insertStringList( m_users );
+ if ( m_users.find( oldUser ) != m_users.end() )
+ m_usersCombo->setCurrentText( oldUser );
+ m_groupsCombo->insertStringList( m_groups );
+ if ( m_groups.find( oldGroup ) != m_groups.end() )
+ m_groupsCombo->setCurrentText( oldGroup );
+ }
+}
+void EditACLEntryDialog::slotOk()
+{
+ KACLListView::EntryType type = static_cast<KACLListView::EntryType>( m_buttonGroup->selectedId() );
+
+ QString qualifier;
+ if ( type == KACLListView::NamedUser )
+ qualifier = m_usersCombo->currentText();
+ if ( type == KACLListView::NamedGroup )
+ qualifier = m_groupsCombo->currentText();
+
+ if ( !m_item ) {
+ m_item = new KACLListViewItem( m_listView, type, ACL_READ | ACL_WRITE | ACL_EXECUTE, false, qualifier );
+ } else {
+ m_item->type = type;
+ m_item->qualifier = qualifier;
+ }
+ if ( m_defaultCB )
+ m_item->isDefault = m_defaultCB->isChecked();
+ m_item->repaint();
+
+ KDialogBase::slotOk();
+}
+
+void EditACLEntryDialog::slotSelectionChanged( int id )
+{
+ switch ( id ) {
+ case KACLListView::User:
+ case KACLListView::Group:
+ case KACLListView::Others:
+ case KACLListView::Mask:
+ m_widgetStack->setEnabled( false );
+ break;
+ case KACLListView::NamedUser:
+ m_widgetStack->setEnabled( true );
+ m_widgetStack->raiseWidget( KACLListView::NamedUser );
+ break;
+ case KACLListView::NamedGroup:
+ m_widgetStack->setEnabled( true );
+ m_widgetStack->raiseWidget( KACLListView::NamedGroup );
+ break;
+ default:
+ break;
+ }
+}
+
+
+KACLListView::KACLListView( QWidget* parent, const char* name )
+ : KListView( parent, name ),
+ m_hasMask( false ), m_allowDefaults( false )
+{
+ // Add the columns
+ addColumn( i18n( "Type" ) );
+ addColumn( i18n( "Name" ) );
+ addColumn( i18n( "read permission", "r" ) );
+ addColumn( i18n( "write permission", "w" ) );
+ addColumn( i18n( "execute permission", "x" ) );
+ addColumn( i18n( "Effective" ) );
+
+ header()->setClickEnabled( false );
+
+ // Load the avatars
+ for ( int i=0; i < LAST_IDX; ++i ) {
+ s_itemAttributes[i].pixmap = new QPixmap( qembed_findImage( s_itemAttributes[i].pixmapName ) );
+ }
+ m_yesPixmap = new QPixmap( qembed_findImage( "yes" ) );
+ m_yesPartialPixmap = new QPixmap( qembed_findImage( "yespartial" ) );
+
+ setSelectionMode( QListView::Extended );
+
+ // fill the lists of all legal users and groups
+ struct passwd *user = 0;
+ setpwent();
+ while ( ( user = getpwent() ) != 0 ) {
+ m_allUsers << QString::fromLatin1( user->pw_name );
+ }
+ endpwent();
+
+ struct group *gr = 0;
+ setgrent();
+ while ( ( gr = getgrent() ) != 0 ) {
+ m_allGroups << QString::fromLatin1( gr->gr_name );
+ }
+ endgrent();
+ m_allUsers.sort();
+ m_allGroups.sort();
+}
+
+
+KACLListView::~KACLListView()
+{
+ for ( int i=0; i < LAST_IDX; ++i ) {
+ delete s_itemAttributes[i].pixmap;
+ }
+ delete m_yesPixmap;
+ delete m_yesPartialPixmap;
+}
+
+QStringList KACLListView::allowedUsers( bool defaults, KACLListViewItem *allowedItem )
+{
+ QStringList allowedUsers = m_allUsers;
+ QListViewItemIterator it( this );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
+ ++it;
+ if ( !item->type == NamedUser || item->isDefault != defaults ) continue;
+ if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue;
+ allowedUsers.remove( item->qualifier );
+ }
+ return allowedUsers;
+}
+
+QStringList KACLListView::allowedGroups( bool defaults, KACLListViewItem *allowedItem )
+{
+ QStringList allowedGroups = m_allGroups;
+ QListViewItemIterator it( this );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
+ ++it;
+ if ( !item->type == NamedGroup || item->isDefault != defaults ) continue;
+ if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue;
+ allowedGroups.remove( item->qualifier );
+ }
+ return allowedGroups;
+}
+
+void KACLListView::fillItemsFromACL( const KACL &pACL, bool defaults )
+{
+ // clear out old entries of that ilk
+ QListViewItemIterator it( this );
+ while ( KACLListViewItem *item = static_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it;
+ if ( item->isDefault == defaults )
+ delete item;
+ }
+ KACLListViewItem *item =
+ new KACLListViewItem( this, User, pACL.ownerPermissions(), defaults );
+
+ item = new KACLListViewItem( this, Group, pACL.owningGroupPermissions(), defaults );
+
+ item = new KACLListViewItem( this, Others, pACL.othersPermissions(), defaults );
+
+ bool hasMask = false;
+ unsigned short mask = pACL.maskPermissions( hasMask );
+ if ( hasMask ) {
+ item = new KACLListViewItem( this, Mask, mask, defaults );
+ }
+
+ // read all named user entries
+ const ACLUserPermissionsList &userList = pACL.allUserPermissions();
+ ACLUserPermissionsConstIterator itu = userList.begin();
+ while ( itu != userList.end() ) {
+ new KACLListViewItem( this, NamedUser, (*itu).second, defaults, (*itu).first );
+ ++itu;
+ }
+
+ // and now all named groups
+ const ACLUserPermissionsList &groupList = pACL.allGroupPermissions();
+ ACLUserPermissionsConstIterator itg = groupList.begin();
+ while ( itg != groupList.end() ) {
+ new KACLListViewItem( this, NamedGroup, (*itg).second, defaults, (*itg).first );
+ ++itg;
+ }
+}
+
+void KACLListView::setACL( const KACL &acl )
+{
+ if ( !acl.isValid() ) return;
+ // Remove any entries left over from displaying a previous ACL
+ m_ACL = acl;
+ fillItemsFromACL( m_ACL );
+
+ m_mask = acl.maskPermissions( m_hasMask );
+ calculateEffectiveRights();
+}
+
+void KACLListView::setDefaultACL( const KACL &acl )
+{
+ if ( !acl.isValid() ) return;
+ m_defaultACL = acl;
+ fillItemsFromACL( m_defaultACL, true );
+ calculateEffectiveRights();
+}
+
+KACL KACLListView::itemsToACL( bool defaults ) const
+{
+ KACL newACL( 0 );
+ bool atLeastOneEntry = false;
+ ACLUserPermissionsList users;
+ ACLGroupPermissionsList groups;
+ QListViewItemIterator it( const_cast<KACLListView*>( this ) );
+ while ( QListViewItem* qlvi = it.current() ) {
+ ++it;
+ const KACLListViewItem* item = static_cast<KACLListViewItem*>( qlvi );
+ if ( item->isDefault != defaults ) continue;
+ atLeastOneEntry = true;
+ switch ( item->type ) {
+ case User:
+ newACL.setOwnerPermissions( item->value );
+ break;
+ case Group:
+ newACL.setOwningGroupPermissions( item->value );
+ break;
+ case Others:
+ newACL.setOthersPermissions( item->value );
+ break;
+ case Mask:
+ newACL.setMaskPermissions( item->value );
+ break;
+ case NamedUser:
+ users.append( qMakePair( item->text( 1 ), item->value ) );
+ break;
+ case NamedGroup:
+ groups.append( qMakePair( item->text( 1 ), item->value ) );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( atLeastOneEntry ) {
+ newACL.setAllUserPermissions( users );
+ newACL.setAllGroupPermissions( groups );
+ if ( newACL.isValid() )
+ return newACL;
+ }
+ return KACL();
+}
+
+KACL KACLListView::getACL()
+{
+ return itemsToACL( false );
+}
+
+
+KACL KACLListView::getDefaultACL()
+{
+ return itemsToACL( true );
+}
+
+void KACLListView::contentsMousePressEvent( QMouseEvent * e )
+{
+ QListViewItem *clickedItem = itemAt( contentsToViewport( e->pos() ) );
+ if ( !clickedItem ) return;
+ // if the click is on an as yet unselected item, select it first
+ if ( !clickedItem->isSelected() )
+ KListView::contentsMousePressEvent( e );
+
+ if ( !currentItem() ) return;
+ int column = header()->sectionAt( e->x() );
+ acl_perm_t perm;
+ switch ( column )
+ {
+ case 2:
+ perm = ACL_READ;
+ break;
+ case 3:
+ perm = ACL_WRITE;
+ break;
+ case 4:
+ perm = ACL_EXECUTE;
+ break;
+ default:
+ return KListView::contentsMousePressEvent( e );
+ }
+ KACLListViewItem* referenceItem = static_cast<KACLListViewItem*>( clickedItem );
+ unsigned short referenceHadItSet = referenceItem->value & perm;
+ QListViewItemIterator it( this );
+ while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it;
+ if ( !item->isSelected() ) continue;
+ // toggle those with the same value as the clicked item, leave the others
+ if ( referenceHadItSet == ( item->value & perm ) )
+ item->togglePerm( perm );
+ }
+}
+
+void KACLListView::entryClicked( QListViewItem* pItem, const QPoint& /*pt*/, int col )
+{
+ if ( !pItem ) return;
+
+ QListViewItemIterator it( this );
+ while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it;
+ if ( !item->isSelected() ) continue;
+ switch ( col )
+ {
+ case 2:
+ item->togglePerm( ACL_READ );
+ break;
+ case 3:
+ item->togglePerm( ACL_WRITE );
+ break;
+ case 4:
+ item->togglePerm( ACL_EXECUTE );
+ break;
+
+ default:
+ ; // Do nothing
+ }
+ }
+ /*
+ // Has the user changed one of the required entries in a default ACL?
+ if ( m_pACL->aclType() == ACL_TYPE_DEFAULT &&
+ ( col == 2 || col == 3 || col == 4 ) &&
+ ( pACLItem->entryType() == ACL_USER_OBJ ||
+ pACLItem->entryType() == ACL_GROUP_OBJ ||
+ pACLItem->entryType() == ACL_OTHER ) )
+ {
+ // Mark the required entries as no longer being partial entries.
+ // That is, they will get applied to all selected directories.
+ KACLListViewItem* pUserObj = findACLEntryByType( this, ACL_USER_OBJ );
+ pUserObj->entry()->setPartialEntry( false );
+
+ KACLListViewItem* pGroupObj = findACLEntryByType( this, ACL_GROUP_OBJ );
+ pGroupObj->entry()->setPartialEntry( false );
+
+ KACLListViewItem* pOther = findACLEntryByType( this, ACL_OTHER );
+ pOther->entry()->setPartialEntry( false );
+
+ update();
+ }
+ */
+}
+
+
+void KACLListView::calculateEffectiveRights()
+{
+ QListViewItemIterator it( this );
+ KACLListViewItem* pItem;
+ while ( ( pItem = dynamic_cast<KACLListViewItem*>( it.current() ) ) != 0 )
+ {
+ ++it;
+ pItem->calcEffectiveRights();
+ }
+}
+
+
+unsigned short KACLListView::maskPermissions() const
+{
+ return m_mask;
+}
+
+
+void KACLListView::setMaskPermissions( unsigned short maskPerms )
+{
+ m_mask = maskPerms;
+ calculateEffectiveRights();
+}
+
+
+acl_perm_t KACLListView::maskPartialPermissions() const
+{
+ // return m_pMaskEntry->m_partialPerms;
+ return 0;
+}
+
+
+void KACLListView::setMaskPartialPermissions( acl_perm_t /*maskPartialPerms*/ )
+{
+ //m_pMaskEntry->m_partialPerms = maskPartialPerms;
+ calculateEffectiveRights();
+}
+
+bool KACLListView::hasDefaultEntries() const
+{
+ QListViewItemIterator it( const_cast<KACLListView*>( this ) );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( it.current() );
+ ++it;
+ if ( item->isDefault ) return true;
+ }
+ return false;
+}
+
+const KACLListViewItem* KACLListView::findDefaultItemByType( EntryType type ) const
+{
+ return findItemByType( type, true );
+}
+
+const KACLListViewItem* KACLListView::findItemByType( EntryType type, bool defaults ) const
+{
+ QListViewItemIterator it( const_cast<KACLListView*>( this ) );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( it.current() );
+ ++it;
+ if ( item->isDefault == defaults && item->type == type ) {
+ return item;
+ }
+ }
+ return 0;
+}
+
+
+unsigned short KACLListView::calculateMaskValue( bool defaults ) const
+{
+ // KACL auto-adds the relevant maks entries, so we can simply query
+ bool dummy;
+ return itemsToACL( defaults ).maskPermissions( dummy );
+}
+
+void KACLListView::slotAddEntry()
+{
+ int allowedTypes = NamedUser | NamedGroup;
+ if ( !m_hasMask )
+ allowedTypes |= Mask;
+ int allowedDefaultTypes = NamedUser | NamedGroup;
+ if ( !findDefaultItemByType( Mask ) )
+ allowedDefaultTypes |= Mask;
+ if ( !hasDefaultEntries() )
+ allowedDefaultTypes |= User | Group;
+ EditACLEntryDialog dlg( this, 0,
+ allowedUsers( false ), allowedGroups( false ),
+ allowedUsers( true ), allowedGroups( true ),
+ allowedTypes, allowedDefaultTypes, m_allowDefaults );
+ dlg.exec();
+ KACLListViewItem *item = dlg.item();
+ if ( !item ) return; // canceled
+ if ( item->type == Mask && !item->isDefault ) {
+ m_hasMask = true;
+ m_mask = item->value;
+ }
+ if ( item->isDefault && !hasDefaultEntries() ) {
+ // first default entry, fill in what is needed
+ if ( item->type != User ) {
+ unsigned short v = findDefaultItemByType( User )->value;
+ new KACLListViewItem( this, User, v, true );
+ }
+ if ( item->type != Group ) {
+ unsigned short v = findDefaultItemByType( Group )->value;
+ new KACLListViewItem( this, Group, v, true );
+ }
+ if ( item->type != Others ) {
+ unsigned short v = findDefaultItemByType( Others )->value;
+ new KACLListViewItem( this, Others, v, true );
+ }
+ }
+ const KACLListViewItem *defaultMaskItem = findDefaultItemByType( Mask );
+ if ( item->isDefault && !defaultMaskItem ) {
+ unsigned short v = calculateMaskValue( true );
+ new KACLListViewItem( this, Mask, v, true );
+ }
+ if ( !item->isDefault && !m_hasMask &&
+ ( item->type == Group
+ || item->type == NamedUser
+ || item->type == NamedGroup ) ) {
+ // auto-add a mask entry
+ unsigned short v = calculateMaskValue( false );
+ new KACLListViewItem( this, Mask, v, false );
+ m_hasMask = true;
+ m_mask = v;
+ }
+ calculateEffectiveRights();
+ sort();
+ setCurrentItem( item );
+ // QListView doesn't seem to emit, in this case, and we need to update
+ // the buttons...
+ if ( childCount() == 1 )
+ emit currentChanged( item );
+}
+
+void KACLListView::slotEditEntry()
+{
+ QListViewItem * current = currentItem();
+ if ( !current ) return;
+ KACLListViewItem *item = static_cast<KACLListViewItem*>( current );
+ int allowedTypes = item->type | NamedUser | NamedGroup;
+ bool itemWasMask = item->type == Mask;
+ if ( !m_hasMask || itemWasMask )
+ allowedTypes |= Mask;
+ int allowedDefaultTypes = item->type | NamedUser | NamedGroup;
+ if ( !findDefaultItemByType( Mask ) )
+ allowedDefaultTypes |= Mask;
+ if ( !hasDefaultEntries() )
+ allowedDefaultTypes |= User | Group;
+
+ EditACLEntryDialog dlg( this, item,
+ allowedUsers( false, item ), allowedGroups( false, item ),
+ allowedUsers( true, item ), allowedGroups( true, item ),
+ allowedTypes, allowedDefaultTypes, m_allowDefaults );
+ dlg.exec();
+ if ( itemWasMask && item->type != Mask ) {
+ m_hasMask = false;
+ m_mask = 0;
+ }
+ if ( !itemWasMask && item->type == Mask ) {
+ m_mask = item->value;
+ m_hasMask = true;
+ }
+ calculateEffectiveRights();
+ sort();
+}
+
+void KACLListView::slotRemoveEntry()
+{
+ QListViewItemIterator it( this, QListViewItemIterator::Selected );
+ while ( it.current() ) {
+ KACLListViewItem *item = static_cast<KACLListViewItem*>( it.current() );
+ ++it;
+ /* First check if it's a mask entry and if so, make sure that there is
+ * either no name user or group entry, which means the mask can be
+ * removed, or don't remove it, but reset it. That is allowed. */
+ if ( item->type == Mask ) {
+ bool itemWasDefault = item->isDefault;
+ if ( !itemWasDefault && maskCanBeDeleted() ) {
+ m_hasMask= false;
+ m_mask = 0;
+ delete item;
+ } else if ( itemWasDefault && defaultMaskCanBeDeleted() ) {
+ delete item;
+ } else {
+ item->value = 0;
+ item->repaint();
+ }
+ if ( !itemWasDefault )
+ calculateEffectiveRights();
+ } else {
+ // for the base permissions, disable them, which is what libacl does
+ if ( !item->isDefault &&
+ ( item->type == User
+ || item->type == Group
+ || item->type == Others ) ) {
+ item->value = 0;
+ item->repaint();
+ } else {
+ delete item;
+ }
+ }
+ }
+}
+
+bool KACLListView::maskCanBeDeleted() const
+{
+ return !findItemByType( NamedUser ) && !findItemByType( NamedGroup );
+}
+
+bool KACLListView::defaultMaskCanBeDeleted() const
+{
+ return !findDefaultItemByType( NamedUser ) && !findDefaultItemByType( NamedGroup );
+}
+
+#include "kacleditwidget.moc"
+#include "kacleditwidget_p.moc"
+#endif
+// vim:set ts=8 sw=4:
diff --git a/kio/kfile/kacleditwidget.h b/kio/kfile/kacleditwidget.h
new file mode 100644
index 000000000..4fec2d7c3
--- /dev/null
+++ b/kio/kfile/kacleditwidget.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> *
+ * Till Adam <adam@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef KACLEDITWIDGET_H
+#define KACLEDITWIDGET_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef USE_POSIX_ACL
+
+#include <klistview.h>
+#include <kacl.h>
+#include <kfileitem.h>
+
+class KACLListViewItem;
+class KACLListView;
+class QPushButton;
+
+class KACLEditWidget : QWidget
+{
+ Q_OBJECT
+public:
+ KACLEditWidget( QWidget *parent = 0, const char *name = 0 );
+ KACL getACL() const;
+ KACL getDefaultACL() const;
+ void setACL( const KACL & );
+ void setDefaultACL( const KACL & );
+ void setAllowDefaults( bool value );
+ void setReadOnly( bool value );
+private slots:
+ void slotUpdateButtons();
+
+private:
+ KACLListView* m_listView;
+ QPushButton *m_AddBtn;
+ QPushButton *m_EditBtn;
+ QPushButton *m_DelBtn;
+};
+
+
+#endif
+#endif
diff --git a/kio/kfile/kacleditwidget_p.h b/kio/kfile/kacleditwidget_p.h
new file mode 100644
index 000000000..6a5a7d074
--- /dev/null
+++ b/kio/kfile/kacleditwidget_p.h
@@ -0,0 +1,200 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> *
+ * Till Adam <adam@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef KACLEDITWIDGET_P_H
+#define KACLEDITWIDGET_P_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef USE_POSIX_ACL
+#include <klistview.h>
+#include <sys/acl.h>
+#include <kacl.h>
+#include <kfileitem.h>
+#include <kdialogbase.h>
+#include <qpixmap.h>
+#include <qcombobox.h>
+
+class KACLListViewItem;
+class QPushButton;
+class QVButtonGroup;
+class KACLListView;
+class QWidgetStack;
+class QCheckBox;
+
+/**
+@author Sean Harmer
+*/
+class KACLListView : public KListView
+{
+Q_OBJECT
+ friend class KACLListViewItem;
+public:
+ enum Types
+ {
+ OWNER_IDX = 0,
+ GROUP_IDX,
+ OTHERS_IDX,
+ MASK_IDX,
+ NAMED_USER_IDX,
+ NAMED_GROUP_IDX,
+ LAST_IDX
+ };
+ enum EntryType { User = 1,
+ Group = 2,
+ Others = 4,
+ Mask = 8,
+ NamedUser = 16,
+ NamedGroup = 32,
+ AllTypes = 63 };
+
+ KACLListView( QWidget* parent = 0, const char* name = 0 );
+ ~KACLListView();
+
+ bool hasMaskEntry() const { return m_hasMask; }
+ bool hasDefaultEntries() const;
+ bool allowDefaults() const { return m_allowDefaults; }
+ void setAllowDefaults( bool v ) { m_allowDefaults = v; }
+ unsigned short maskPermissions() const;
+ void setMaskPermissions( unsigned short maskPerms );
+ acl_perm_t maskPartialPermissions() const;
+ void setMaskPartialPermissions( acl_perm_t maskPerms );
+
+ bool maskCanBeDeleted() const;
+ bool defaultMaskCanBeDeleted() const;
+
+ const KACLListViewItem* findDefaultItemByType( EntryType type ) const;
+ const KACLListViewItem* findItemByType( EntryType type,
+ bool defaults = false ) const;
+ unsigned short calculateMaskValue( bool defaults ) const;
+ void calculateEffectiveRights();
+
+ QStringList allowedUsers( bool defaults, KACLListViewItem *allowedItem = 0 );
+ QStringList allowedGroups( bool defaults, KACLListViewItem *allowedItem = 0 );
+
+ const KACL getACL() const { return getACL(); }
+ KACL getACL();
+
+ const KACL getDefaultACL() const { return getDefaultACL(); }
+ KACL getDefaultACL();
+
+ QPixmap getYesPixmap() const { return *m_yesPixmap; }
+ QPixmap getYesPartialPixmap() const { return *m_yesPartialPixmap; }
+
+public slots:
+ void slotAddEntry();
+ void slotEditEntry();
+ void slotRemoveEntry();
+ void setACL( const KACL &anACL );
+ void setDefaultACL( const KACL &anACL );
+
+protected slots:
+ void entryClicked( QListViewItem* pItem, const QPoint& pt, int col );
+protected:
+ void contentsMousePressEvent( QMouseEvent * e );
+
+private:
+ void fillItemsFromACL( const KACL &pACL, bool defaults = false );
+ KACL itemsToACL( bool defaults ) const;
+
+ KACL m_ACL;
+ KACL m_defaultACL;
+ unsigned short m_mask;
+ bool m_hasMask;
+ bool m_allowDefaults;
+ QStringList m_allUsers;
+ QStringList m_allGroups;
+ QPixmap* m_yesPixmap;
+ QPixmap* m_yesPartialPixmap;
+};
+
+class EditACLEntryDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ EditACLEntryDialog( KACLListView *listView, KACLListViewItem *item,
+ const QStringList &users,
+ const QStringList &groups,
+ const QStringList &defaultUsers,
+ const QStringList &defaultGroups,
+ int allowedTypes = KACLListView::AllTypes,
+ int allowedDefaultTypes = KACLListView::AllTypes,
+ bool allowDefault = false );
+ KACLListViewItem* item() const { return m_item; }
+public slots:
+ void slotOk();
+ void slotSelectionChanged( int id );
+private slots:
+ void slotUpdateAllowedUsersAndGroups();
+ void slotUpdateAllowedTypes();
+private:
+ KACLListView *m_listView;
+ KACLListViewItem *m_item;
+ QStringList m_users;
+ QStringList m_groups;
+ QStringList m_defaultUsers;
+ QStringList m_defaultGroups;
+ int m_allowedTypes;
+ int m_allowedDefaultTypes;
+ QVButtonGroup *m_buttonGroup;
+ QComboBox *m_usersCombo;
+ QComboBox *m_groupsCombo;
+ QWidgetStack *m_widgetStack;
+ QCheckBox *m_defaultCB;
+};
+
+
+class KACLListViewItem : public KListViewItem
+{
+public:
+ KACLListViewItem( QListView* parent, KACLListView::EntryType type,
+ unsigned short value,
+ bool defaultEntry,
+ const QString& qualifier = QString::null );
+ virtual ~KACLListViewItem();
+ virtual QString key( int column, bool ascending ) const;
+
+ void calcEffectiveRights();
+
+ bool isDeletable() const;
+ bool isAllowedToChangeType() const;
+
+ void togglePerm( acl_perm_t perm );
+
+ virtual void paintCell( QPainter *p, const QColorGroup &cg,
+ int column, int width, int alignment );
+
+ void updatePermPixmaps();
+ void repaint();
+
+ KACLListView::EntryType type;
+ unsigned short value;
+ bool isDefault;
+ QString qualifier;
+ bool isPartial;
+
+private:
+ KACLListView* m_pACLListView;
+};
+
+
+#endif
+#endif
diff --git a/kio/kfile/kcombiview.cpp b/kio/kfile/kcombiview.cpp
new file mode 100644
index 000000000..fc16054f1
--- /dev/null
+++ b/kio/kfile/kcombiview.cpp
@@ -0,0 +1,371 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// $Id$
+
+#include <assert.h>
+
+#include "kfileitem.h"
+#include "kcombiview.h"
+#include "kfileiconview.h"
+#include "kfiledetailview.h"
+#include "config-kfile.h"
+
+#include <qevent.h>
+
+#include <qdir.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include <qvaluelist.h>
+
+KCombiView::KCombiView( QWidget *parent, const char *name)
+ : QSplitter( parent, name),
+ KFileView(),
+ right(0),
+ m_lastViewForNextItem(0),
+ m_lastViewForPrevItem(0)
+{
+ left = new KFileIconView( this, "left" );
+ left->setAcceptDrops(false);
+ left->viewport()->setAcceptDrops(false);
+ left->setGridX( 160 );
+ left->KFileView::setViewMode( Directories );
+ left->setArrangement( QIconView::LeftToRight );
+ left->setParentView( this );
+ left->setAcceptDrops(false);
+ left->installEventFilter( this );
+
+ connect( sig, SIGNAL( sortingChanged( QDir::SortSpec ) ),
+ SLOT( slotSortingChanged( QDir::SortSpec ) ));
+}
+
+KCombiView::~KCombiView()
+{
+ delete right;
+}
+
+void KCombiView::setRight(KFileView *view)
+{
+ delete right;
+ right = view;
+ right->KFileView::setViewMode( Files );
+ setViewName( right->viewName() );
+
+ QValueList<int> lst;
+ lst << left->gridX() + 2 * left->spacing();
+ setSizes( lst );
+ setResizeMode( left, QSplitter::KeepSize );
+
+ right->setParentView( this );
+ right->widget()->setAcceptDrops(acceptDrops());
+ right->setDropOptions(dropOptions());
+ right->widget()->installEventFilter( this );
+}
+
+
+void KCombiView::insertItem( KFileItem *item )
+{
+ KFileView::insertItem( item );
+
+ if ( item->isDir() ) {
+ left->updateNumbers( item );
+ left->insertItem( item );
+ }
+ else {
+ right->updateNumbers( item );
+ right->insertItem( item );
+ }
+}
+
+void KCombiView::setSorting( QDir::SortSpec sort )
+{
+ if ( !right )
+ kdFatal() << "You need to call setRight( someview ) before!" << endl;
+ right->setSorting( sort );
+ left->setSorting( sort );
+
+ KFileView::setSorting( right->sorting() );
+}
+
+void KCombiView::clearView()
+{
+ left->clearView();
+ if ( right )
+ right->clearView();
+}
+
+void KCombiView::updateView( bool b )
+{
+ left->updateView( b );
+ if ( right )
+ right->updateView( b );
+}
+
+void KCombiView::updateView( const KFileItem *i )
+{
+ left->updateView( i );
+ if ( right )
+ right->updateView( i );
+}
+
+void KCombiView::removeItem( const KFileItem *i )
+{
+ left->removeItem( i );
+ if ( right )
+ right->removeItem( i );
+ KFileView::removeItem( i );
+}
+
+void KCombiView::listingCompleted()
+{
+ left->listingCompleted();
+ if ( right )
+ right->listingCompleted();
+}
+
+void KCombiView::clear()
+{
+ KFileView::clear();
+ left->KFileView::clear();
+ if ( right )
+ right->clear();
+}
+
+void KCombiView::clearSelection()
+{
+ left->clearSelection();
+ if ( right )
+ right->clearSelection();
+}
+
+void KCombiView::selectAll()
+{
+ left->selectAll();
+ if ( right )
+ right->selectAll();
+}
+
+void KCombiView::invertSelection()
+{
+ left->invertSelection();
+ if ( right )
+ right->invertSelection();
+}
+
+bool KCombiView::isSelected( const KFileItem *item ) const
+{
+ assert( right ); // for performance reasons no if ( right ) check.
+ return (right->isSelected( item ) || left->isSelected( item ));
+}
+
+void KCombiView::setSelectionMode( KFile::SelectionMode sm )
+{
+ // I think the left view (directories should always be in
+ // Single-Mode, right?
+ // left->setSelectionMode( sm );
+ if ( !right )
+ kdFatal() << "You need to call setRight( someview ) before!" << endl;
+ right->setSelectionMode( sm );
+}
+
+void KCombiView::setSelected( const KFileItem *item, bool enable )
+{
+ left->setSelected( item, enable );
+ if ( right )
+ right->setSelected( item, enable );
+}
+
+void KCombiView::setCurrentItem( const KFileItem *item )
+{
+ left->setCurrentItem( item );
+ if ( right )
+ right->setCurrentItem( item );
+}
+
+KFileItem * KCombiView::currentFileItem() const
+{
+ // we can actually have two current items, one in each view. So we simply
+ // prefer the fileview's item over the directory's.
+ // Smarter: if the right view has focus, prefer that over the left.
+ if ( !right )
+ return left->currentFileItem();
+
+ KFileView *preferredView = focusView( right );
+ KFileItem *item = preferredView->currentFileItem();
+ if ( !item && preferredView != left )
+ item = left->currentFileItem();
+
+ return item;
+}
+
+void KCombiView::ensureItemVisible(const KFileItem *item)
+{
+ left->ensureItemVisible( item );
+ if ( right )
+ right->ensureItemVisible( item );
+}
+
+KFileItem * KCombiView::firstFileItem() const
+{
+ if ( !right )
+ return left->firstFileItem();
+
+ KFileView *preferredView = focusView( left );
+ KFileView *otherView = (preferredView == left) ? right : left;
+ KFileItem *item = preferredView->firstFileItem();
+ if ( !item )
+ item = otherView->firstFileItem();
+
+ return item;
+}
+
+KFileItem * KCombiView::nextItem( const KFileItem *fileItem ) const
+{
+ if ( !right )
+ return left->nextItem( fileItem );
+
+ KFileView *preferredView = focusView( left );
+ KFileView *otherView = (preferredView == left) ? right : left;
+ KFileItem *item = preferredView->nextItem( fileItem );
+
+ if ( item )
+ m_lastViewForNextItem = preferredView;
+ else { // no item, check other view
+ // when changing from one to another view, we need to continue
+ // with the next view's first item!
+ if ( m_lastViewForNextItem != otherView ) {
+ m_lastViewForNextItem = otherView;
+ return otherView->firstFileItem();
+ }
+
+ item = otherView->nextItem( fileItem );
+ m_lastViewForNextItem = otherView;
+ }
+
+ return item;
+}
+
+KFileItem * KCombiView::prevItem( const KFileItem *fileItem ) const
+{
+ if ( !right )
+ return left->nextItem( fileItem );
+
+ KFileView *preferredView = focusView( left );
+ KFileView *otherView = (preferredView == left) ? right : left;
+ KFileItem *item = preferredView->prevItem( fileItem );
+ if ( item )
+ m_lastViewForPrevItem = preferredView;
+
+ else { // no item, check other view
+ // when changing from one to another view, we need to continue
+ // with the next view's last item!
+ if ( m_lastViewForPrevItem != otherView ) {
+ fileItem = otherView->firstFileItem();
+ while ( otherView->nextItem( fileItem ) ) // find the last item
+ fileItem = otherView->nextItem( fileItem );
+ }
+
+ item = otherView->prevItem( fileItem );
+ m_lastViewForPrevItem = otherView;
+ }
+
+ return item;
+}
+
+void KCombiView::slotSortingChanged( QDir::SortSpec sorting )
+{
+ KFileView::setSorting( sorting );
+}
+
+KFileView *KCombiView::focusView( KFileView *preferred ) const
+{
+ QWidget *w = focusWidget();
+ KFileView *other = (right == preferred) ? left : right;
+ return (preferred && w == preferred->widget()) ? preferred : other;
+}
+
+void KCombiView::readConfig( KConfig *config, const QString& group )
+{
+ left->readConfig( config, group );
+ if ( right )
+ right->readConfig( config, group );
+}
+
+void KCombiView::writeConfig( KConfig *config, const QString& group )
+{
+ left->writeConfig( config, group );
+ if ( right )
+ right->writeConfig( config, group );
+}
+
+KActionCollection * KCombiView::actionCollection() const
+{
+ return focusView( right )->actionCollection();
+}
+
+void KCombiView::setAcceptDrops(bool b)
+{
+ left->setAcceptDrops(b);
+ if (right)
+ right->widget()->setAcceptDrops(b);
+ QSplitter::setAcceptDrops(b);
+}
+
+void KCombiView::setDropOptions_impl(int options)
+{
+ KFileView::setDropOptions_impl(options);
+ left->setDropOptions(options);
+ if (right)
+ right->setDropOptions(options);
+}
+
+void KCombiView::virtual_hook( int id, void* data )
+{
+ switch(id) {
+ case VIRTUAL_SET_DROP_OPTIONS:
+ setDropOptions_impl(*(int *)data);
+ break;
+ default:
+ KFileView::virtual_hook( id, data );
+ }
+}
+
+bool KCombiView::eventFilter( QObject *o, QEvent *e )
+{
+ int type = e->type();
+
+ // only the focused view may have a selection
+ if ( type == QEvent::FocusIn )
+ {
+ if ( o == left )
+ right->clearSelection();
+ else if ( o == right->widget() )
+ left->clearSelection();
+ }
+
+ return QSplitter::eventFilter( o, e );
+}
+
+#include "kcombiview.moc"
+
diff --git a/kio/kfile/kcombiview.h b/kio/kfile/kcombiview.h
new file mode 100644
index 000000000..b38876d71
--- /dev/null
+++ b/kio/kfile/kcombiview.h
@@ -0,0 +1,133 @@
+/* -*- c++ -*-
+ This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KCOMBIVIEW_H
+#define _KCOMBIVIEW_H
+
+#include <qsplitter.h>
+#include <klocale.h>
+
+#include <kfile.h>
+#include <kfileview.h>
+
+class KFileIconView;
+class QEvent;
+class QIconViewItem;
+
+/**
+ * This view is designed to combine two KFileViews into one widget, to show
+ * directories on the left side and files on the right side.
+ *
+ * Methods like selectedItems() to query status _only_ work on the right side,
+ * i.e. on the files.
+ *
+ * After creating the KCombiView, you need to supply the view shown in the
+ * right, (see setRight()). Available KFileView implementations are
+ * KFileIconView and KFileDetailView.
+ *
+ * Most of the below methods are just implementations of the baseclass
+ * KFileView, so look there for documentation.
+ *
+ * @see KFileView
+ * @see KFileIconView
+ * @see KFileDetailView
+ * @see KDirOperator
+ */
+class KIO_EXPORT KCombiView : public QSplitter,
+ public KFileView
+{
+ Q_OBJECT
+
+public:
+ KCombiView( QWidget *parent, const char *name);
+ virtual ~KCombiView();
+
+ virtual QWidget *widget() { return this; }
+ virtual void clearView();
+
+ virtual void updateView( bool );
+ virtual void updateView(const KFileItem*);
+ virtual void removeItem( const KFileItem * );
+ virtual void listingCompleted();
+
+ /**
+ * Sets the view to be shown in the right. You need to call this before
+ * doing anything else with this widget.
+ */
+ void setRight(KFileView *view);
+
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+
+ virtual void setSelected(const KFileItem *, bool);
+ virtual bool isSelected( const KFileItem * ) const;
+ virtual void clearSelection();
+ virtual void selectAll();
+ virtual void invertSelection();
+
+ virtual void setCurrentItem( const KFileItem * );
+ virtual KFileItem * currentFileItem() const;
+ virtual KFileItem * firstFileItem() const;
+ virtual KFileItem * nextItem( const KFileItem * ) const;
+ virtual KFileItem * prevItem( const KFileItem * ) const;
+
+ virtual void insertItem( KFileItem *i );
+ virtual void clear();
+
+ virtual void setSorting( QDir::SortSpec sort );
+
+ virtual void readConfig( KConfig *, const QString& group = QString::null );
+ virtual void writeConfig( KConfig *, const QString& group = QString::null);
+
+ void ensureItemVisible( const KFileItem * );
+
+ virtual KActionCollection * actionCollection() const;
+
+ virtual void setAcceptDrops(bool b);
+
+protected:
+ KFileIconView *left;
+ KFileView *right;
+
+protected slots:
+ void slotSortingChanged( QDir::SortSpec );
+
+private:
+ KFileView *focusView( KFileView *preferred ) const;
+
+ // in nextItem() and prevItem(), we have to switch views, when the first
+ // view returns 0L. So we need to remember which view was used in the
+ // previous call to next/prevItem(). Yes, it's a hack, but it works for
+ // some cases at least.
+ mutable KFileView *m_lastViewForNextItem;
+ mutable KFileView *m_lastViewForPrevItem;
+
+protected:
+ virtual bool eventFilter( QObject *o, QEvent *e );
+ void setDropOptions_impl(int options);
+
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KCombiViewPrivate;
+ KCombiViewPrivate *d;
+
+};
+
+#endif
diff --git a/kio/kfile/kcustommenueditor.cpp b/kio/kfile/kcustommenueditor.cpp
new file mode 100644
index 000000000..edbca55e3
--- /dev/null
+++ b/kio/kfile/kcustommenueditor.cpp
@@ -0,0 +1,242 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qhbox.h>
+#include <qregexp.h>
+#include <qimage.h>
+#include <qpushbutton.h>
+#include <qdir.h>
+
+#include <kbuttonbox.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klistview.h>
+#include <kservice.h>
+#include <kstandarddirs.h>
+#include <kconfigbase.h>
+#include <kopenwith.h>
+
+#include "kcustommenueditor.h"
+
+class KCustomMenuEditor::Item : public QListViewItem
+{
+public:
+ Item(QListView *parent, KService::Ptr service)
+ : QListViewItem(parent),
+ s(service)
+ {
+ init();
+ }
+
+ Item(QListViewItem *parent, KService::Ptr service)
+ : QListViewItem(parent),
+ s(service)
+ {
+ init();
+ }
+
+ void init()
+ {
+ QString serviceName = s->name();
+
+ // item names may contain ampersands. To avoid them being converted
+ // to accelators, replace them with two ampersands.
+ serviceName.replace("&", "&&");
+
+ QPixmap normal = KGlobal::instance()->iconLoader()->loadIcon(s->icon(), KIcon::Small,
+ 0, KIcon::DefaultState, 0L, true);
+
+ // make sure they are not larger than 16x16
+ if (normal.width() > 16 || normal.height() > 16) {
+ QImage tmp = normal.convertToImage();
+ tmp = tmp.smoothScale(16, 16);
+ normal.convertFromImage(tmp);
+ }
+ setText(0, serviceName);
+ setPixmap(0, normal);
+ }
+
+ KService::Ptr s;
+};
+
+class KCustomMenuEditor::KCustomMenuEditorPrivate
+{
+public:
+ QPushButton * pbRemove;
+ QPushButton * pbMoveUp;
+ QPushButton * pbMoveDown;
+};
+
+KCustomMenuEditor::KCustomMenuEditor(QWidget *parent)
+ : KDialogBase(parent, "custommenueditor", true, i18n("Menu Editor"), Ok|Cancel, Ok, true),
+ m_listView(0)
+{
+ d = new KCustomMenuEditorPrivate;
+ QHBox *page = makeHBoxMainWidget();
+ m_listView = new KListView(page);
+ m_listView->addColumn(i18n("Menu"));
+ m_listView->setFullWidth(true);
+ m_listView->setSorting(-1);
+ KButtonBox *buttonBox = new KButtonBox(page, Vertical);
+ buttonBox->addButton(i18n("New..."), this, SLOT(slotNewItem()));
+ d->pbRemove=buttonBox->addButton(i18n("Remove"), this, SLOT(slotRemoveItem()));
+ d->pbMoveUp=buttonBox->addButton(i18n("Move Up"), this, SLOT(slotMoveUp()));
+ d->pbMoveDown=buttonBox->addButton(i18n("Move Down"), this, SLOT(slotMoveDown()));
+ buttonBox->layout();
+ connect( m_listView, SIGNAL( selectionChanged () ), this, SLOT( refreshButton() ) );
+ refreshButton();
+}
+
+KCustomMenuEditor::~KCustomMenuEditor()
+{
+ delete d;
+ d=0;
+}
+
+void KCustomMenuEditor::refreshButton()
+{
+ QListViewItem *item = m_listView->currentItem();
+ d->pbRemove->setEnabled( item );
+ d->pbMoveUp->setEnabled( item && item->itemAbove() );
+ d->pbMoveDown->setEnabled( item && item->itemBelow() );
+}
+
+void
+KCustomMenuEditor::load(KConfigBase *cfg)
+{
+ cfg->setGroup(QString::null);
+ int count = cfg->readNumEntry("NrOfItems");
+ QListViewItem *last = 0;
+ for(int i = 0; i < count; i++)
+ {
+ QString entry = cfg->readPathEntry(QString("Item%1").arg(i+1));
+ if (entry.isEmpty())
+ continue;
+
+ // Try KSycoca first.
+ KService::Ptr menuItem = KService::serviceByDesktopPath( entry );
+ if (!menuItem)
+ menuItem = KService::serviceByDesktopName( entry );
+ if (!menuItem)
+ menuItem = new KService( entry );
+
+ if (!menuItem->isValid())
+ continue;
+
+ QListViewItem *item = new Item(m_listView, menuItem);
+ item->moveItem(last);
+ last = item;
+ }
+}
+
+void
+KCustomMenuEditor::save(KConfigBase *cfg)
+{
+ // First clear the whole config file.
+ QStringList groups = cfg->groupList();
+ for(QStringList::ConstIterator it = groups.begin();
+ it != groups.end(); ++it)
+ {
+ cfg->deleteGroup(*it);
+ }
+
+ cfg->setGroup(QString::null);
+ Item * item = (Item *) m_listView->firstChild();
+ int i = 0;
+ while(item)
+ {
+ i++;
+ QString path = item->s->desktopEntryPath();
+ if (QDir::isRelativePath(path) || QDir::isRelativePath(KGlobal::dirs()->relativeLocation("xdgdata-apps", path)))
+ path = item->s->desktopEntryName();
+ cfg->writePathEntry(QString("Item%1").arg(i), path);
+ item = (Item *) item->nextSibling();
+ }
+ cfg->writeEntry("NrOfItems", i);
+}
+
+void
+KCustomMenuEditor::slotNewItem()
+{
+ QListViewItem *item = m_listView->currentItem();
+
+ KOpenWithDlg dlg(this);
+ dlg.setSaveNewApplications(true);
+
+ if (dlg.exec())
+ {
+ KService::Ptr s = dlg.service();
+ if (s && s->isValid())
+ {
+ Item *newItem = new Item(m_listView, s);
+ newItem->moveItem(item);
+ }
+ refreshButton();
+ }
+}
+
+void
+KCustomMenuEditor::slotRemoveItem()
+{
+ QListViewItem *item = m_listView->currentItem();
+ if (!item)
+ return;
+
+ delete item;
+ refreshButton();
+}
+
+void
+KCustomMenuEditor::slotMoveUp()
+{
+ QListViewItem *item = m_listView->currentItem();
+ if (!item)
+ return;
+
+ QListViewItem *searchItem = m_listView->firstChild();
+ while(searchItem)
+ {
+ QListViewItem *next = searchItem->nextSibling();
+ if (next == item)
+ {
+ searchItem->moveItem(item);
+ break;
+ }
+ searchItem = next;
+ }
+ refreshButton();
+}
+
+void
+KCustomMenuEditor::slotMoveDown()
+{
+ QListViewItem *item = m_listView->currentItem();
+ if (!item)
+ return;
+
+ QListViewItem *after = item->nextSibling();
+ if (!after)
+ return;
+
+ item->moveItem( after );
+ refreshButton();
+}
+
+#include "kcustommenueditor.moc"
diff --git a/kio/kfile/kcustommenueditor.h b/kio/kfile/kcustommenueditor.h
new file mode 100644
index 000000000..88151f5d4
--- /dev/null
+++ b/kio/kfile/kcustommenueditor.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef _KCUSTOMMENUEDITOR_H_
+#define _KCUSTOMMENUEDITOR_H_
+
+#include <kdialogbase.h>
+
+class KListView;
+class KConfigBase;
+
+ /*
+ * Dialog for editing custom menus.
+ *
+ * @author Waldo Bastian (bastian@kde.org)
+ * @since 3.1
+ */
+class KIO_EXPORT KCustomMenuEditor : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Create a dialog for editing a custom menu
+ */
+ KCustomMenuEditor(QWidget *parent);
+ ~KCustomMenuEditor();
+ /**
+ * load the custom menu
+ */
+ void load(KConfigBase *);
+
+ /**
+ * save the custom menu
+ */
+ void save(KConfigBase *);
+
+public slots:
+ void slotNewItem();
+ void slotRemoveItem();
+ void slotMoveUp();
+ void slotMoveDown();
+ void refreshButton();
+
+protected:
+ class Item;
+ KListView *m_listView;
+
+ class KCustomMenuEditorPrivate;
+ KCustomMenuEditorPrivate *d;
+};
+
+#endif
diff --git a/kio/kfile/kdiroperator.cpp b/kio/kfile/kdiroperator.cpp
new file mode 100644
index 000000000..b12e45153
--- /dev/null
+++ b/kio/kfile/kdiroperator.cpp
@@ -0,0 +1,1740 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999,2000 Stephan Kulow <coolo@kde.org>
+ 1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <unistd.h>
+
+#include <qdir.h>
+#include <qapplication.h>
+#include <qdialog.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qpopupmenu.h>
+#include <qregexp.h>
+#include <qtimer.h>
+#include <qvbox.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+#include <kdirlister.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpopupmenu.h>
+#include <kprogress.h>
+#include <kstdaction.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kio/netaccess.h>
+#include <kio/previewjob.h>
+#include <kio/renamedlg.h>
+#include <kpropertiesdialog.h>
+#include <kservicetypefactory.h>
+#include <kstdaccel.h>
+#include <kde_file.h>
+
+#include "config-kfile.h"
+#include "kcombiview.h"
+#include "kdiroperator.h"
+#include "kfiledetailview.h"
+#include "kfileiconview.h"
+#include "kfilepreview.h"
+#include "kfileview.h"
+#include "kfileitem.h"
+#include "kfilemetapreview.h"
+
+
+template class QPtrStack<KURL>;
+template class QDict<KFileItem>;
+
+
+class KDirOperator::KDirOperatorPrivate
+{
+public:
+ KDirOperatorPrivate() {
+ onlyDoubleClickSelectsFiles = false;
+ progressDelayTimer = 0L;
+ dirHighlighting = false;
+ config = 0L;
+ dropOptions = 0;
+ }
+
+ ~KDirOperatorPrivate() {
+ delete progressDelayTimer;
+ }
+
+ bool dirHighlighting;
+ QString lastURL; // used for highlighting a directory on cdUp
+ bool onlyDoubleClickSelectsFiles;
+ QTimer *progressDelayTimer;
+ KActionSeparator *viewActionSeparator;
+ int dropOptions;
+
+ KConfig *config;
+ QString configGroup;
+};
+
+KDirOperator::KDirOperator(const KURL& _url,
+ QWidget *parent, const char* _name)
+ : QWidget(parent, _name),
+ dir(0),
+ m_fileView(0),
+ progress(0)
+{
+ myPreview = 0L;
+ myMode = KFile::File;
+ m_viewKind = KFile::Simple;
+ mySorting = static_cast<QDir::SortSpec>(QDir::Name | QDir::DirsFirst);
+ d = new KDirOperatorPrivate;
+
+ if (_url.isEmpty()) { // no dir specified -> current dir
+ QString strPath = QDir::currentDirPath();
+ strPath.append('/');
+ currUrl = KURL();
+ currUrl.setProtocol(QString::fromLatin1("file"));
+ currUrl.setPath(strPath);
+ }
+ else {
+ currUrl = _url;
+ if ( currUrl.protocol().isEmpty() )
+ currUrl.setProtocol(QString::fromLatin1("file"));
+
+ currUrl.addPath("/"); // make sure we have a trailing slash!
+ }
+
+ setDirLister( new KDirLister( true ) );
+
+ connect(&myCompletion, SIGNAL(match(const QString&)),
+ SLOT(slotCompletionMatch(const QString&)));
+
+ progress = new KProgress(this, "progress");
+ progress->adjustSize();
+ progress->move(2, height() - progress->height() -2);
+
+ d->progressDelayTimer = new QTimer( this, "progress delay timer" );
+ connect( d->progressDelayTimer, SIGNAL( timeout() ),
+ SLOT( slotShowProgress() ));
+
+ myCompleteListDirty = false;
+
+ backStack.setAutoDelete( true );
+ forwardStack.setAutoDelete( true );
+
+ // action stuff
+ setupActions();
+ setupMenu();
+
+ setFocusPolicy(QWidget::WheelFocus);
+}
+
+KDirOperator::~KDirOperator()
+{
+ resetCursor();
+ if ( m_fileView )
+ {
+ if ( d->config )
+ m_fileView->writeConfig( d->config, d->configGroup );
+
+ delete m_fileView;
+ m_fileView = 0L;
+ }
+
+ delete myPreview;
+ delete dir;
+ delete d;
+}
+
+
+void KDirOperator::setSorting( QDir::SortSpec spec )
+{
+ if ( m_fileView )
+ m_fileView->setSorting( spec );
+ mySorting = spec;
+ updateSortActions();
+}
+
+void KDirOperator::resetCursor()
+{
+ QApplication::restoreOverrideCursor();
+ progress->hide();
+}
+
+void KDirOperator::insertViewDependentActions()
+{
+ // If we have a new view actionCollection(), insert its actions
+ // into viewActionMenu.
+
+ if( !m_fileView )
+ return;
+
+ if ( (viewActionMenu->popupMenu()->count() == 0) || // Not yet initialized or...
+ (viewActionCollection != m_fileView->actionCollection()) ) // ...changed since.
+ {
+ if (viewActionCollection)
+ {
+ disconnect( viewActionCollection, SIGNAL( inserted( KAction * )),
+ this, SLOT( slotViewActionAdded( KAction * )));
+ disconnect( viewActionCollection, SIGNAL( removed( KAction * )),
+ this, SLOT( slotViewActionRemoved( KAction * )));
+ }
+
+ viewActionMenu->popupMenu()->clear();
+// viewActionMenu->insert( shortAction );
+// viewActionMenu->insert( detailedAction );
+// viewActionMenu->insert( actionSeparator );
+ viewActionMenu->insert( myActionCollection->action( "short view" ) );
+ viewActionMenu->insert( myActionCollection->action( "detailed view" ) );
+ viewActionMenu->insert( actionSeparator );
+ viewActionMenu->insert( showHiddenAction );
+// viewActionMenu->insert( myActionCollection->action( "single" ));
+ viewActionMenu->insert( separateDirsAction );
+ // Warning: adjust slotViewActionAdded() and slotViewActionRemoved()
+ // when you add/remove actions here!
+
+ viewActionCollection = m_fileView->actionCollection();
+ if (!viewActionCollection)
+ return;
+
+ if ( !viewActionCollection->isEmpty() )
+ {
+ viewActionMenu->insert( d->viewActionSeparator );
+
+ // first insert the normal actions, then the grouped ones
+ QStringList groups = viewActionCollection->groups();
+ groups.prepend( QString::null ); // actions without group
+ QStringList::ConstIterator git = groups.begin();
+ KActionPtrList list;
+ KAction *sep = actionCollection()->action("separator");
+ for ( ; git != groups.end(); ++git )
+ {
+ if ( git != groups.begin() )
+ viewActionMenu->insert( sep );
+
+ list = viewActionCollection->actions( *git );
+ KActionPtrList::ConstIterator it = list.begin();
+ for ( ; it != list.end(); ++it )
+ viewActionMenu->insert( *it );
+ }
+ }
+
+ connect( viewActionCollection, SIGNAL( inserted( KAction * )),
+ SLOT( slotViewActionAdded( KAction * )));
+ connect( viewActionCollection, SIGNAL( removed( KAction * )),
+ SLOT( slotViewActionRemoved( KAction * )));
+ }
+}
+
+void KDirOperator::activatedMenu( const KFileItem *, const QPoint& pos )
+{
+ setupMenu();
+ updateSelectionDependentActions();
+
+ actionMenu->popup( pos );
+}
+
+void KDirOperator::updateSelectionDependentActions()
+{
+ bool hasSelection = m_fileView && m_fileView->selectedItems() &&
+ !m_fileView->selectedItems()->isEmpty();
+ myActionCollection->action( "trash" )->setEnabled( hasSelection );
+ myActionCollection->action( "delete" )->setEnabled( hasSelection );
+ myActionCollection->action( "properties" )->setEnabled( hasSelection );
+}
+
+void KDirOperator::setPreviewWidget(const QWidget *w)
+{
+ if(w != 0L)
+ m_viewKind = (m_viewKind | KFile::PreviewContents);
+ else
+ m_viewKind = (m_viewKind & ~KFile::PreviewContents);
+
+ delete myPreview;
+ myPreview = w;
+
+ KToggleAction *preview = static_cast<KToggleAction*>(myActionCollection->action("preview"));
+ preview->setEnabled( w != 0L );
+ preview->setChecked( w != 0L );
+ setView( static_cast<KFile::FileView>(m_viewKind) );
+}
+
+int KDirOperator::numDirs() const
+{
+ return m_fileView ? m_fileView->numDirs() : 0;
+}
+
+int KDirOperator::numFiles() const
+{
+ return m_fileView ? m_fileView->numFiles() : 0;
+}
+
+void KDirOperator::slotDetailedView()
+{
+ KFile::FileView view = static_cast<KFile::FileView>( (m_viewKind & ~KFile::Simple) | KFile::Detail );
+ setView( view );
+}
+
+void KDirOperator::slotSimpleView()
+{
+ KFile::FileView view = static_cast<KFile::FileView>( (m_viewKind & ~KFile::Detail) | KFile::Simple );
+ setView( view );
+}
+
+void KDirOperator::slotToggleHidden( bool show )
+{
+ dir->setShowingDotFiles( show );
+ updateDir();
+ if ( m_fileView )
+ m_fileView->listingCompleted();
+}
+
+void KDirOperator::slotSeparateDirs()
+{
+ if (separateDirsAction->isChecked())
+ {
+ KFile::FileView view = static_cast<KFile::FileView>( m_viewKind | KFile::SeparateDirs );
+ setView( view );
+ }
+ else
+ {
+ KFile::FileView view = static_cast<KFile::FileView>( m_viewKind & ~KFile::SeparateDirs );
+ setView( view );
+ }
+}
+
+void KDirOperator::slotDefaultPreview()
+{
+ m_viewKind = m_viewKind | KFile::PreviewContents;
+ if ( !myPreview ) {
+ myPreview = new KFileMetaPreview( this );
+ (static_cast<KToggleAction*>( myActionCollection->action("preview") ))->setChecked(true);
+ }
+
+ setView( static_cast<KFile::FileView>(m_viewKind) );
+}
+
+void KDirOperator::slotSortByName()
+{
+ int sorting = (m_fileView->sorting()) & ~QDir::SortByMask;
+ m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::Name ));
+ mySorting = m_fileView->sorting();
+ caseInsensitiveAction->setEnabled( true );
+}
+
+void KDirOperator::slotSortBySize()
+{
+ int sorting = (m_fileView->sorting()) & ~QDir::SortByMask;
+ m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::Size ));
+ mySorting = m_fileView->sorting();
+ caseInsensitiveAction->setEnabled( false );
+}
+
+void KDirOperator::slotSortByDate()
+{
+ int sorting = (m_fileView->sorting()) & ~QDir::SortByMask;
+ m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::Time ));
+ mySorting = m_fileView->sorting();
+ caseInsensitiveAction->setEnabled( false );
+}
+
+void KDirOperator::slotSortReversed()
+{
+ if ( m_fileView )
+ m_fileView->sortReversed();
+}
+
+void KDirOperator::slotToggleDirsFirst()
+{
+ QDir::SortSpec sorting = m_fileView->sorting();
+ if ( !KFile::isSortDirsFirst( sorting ) )
+ m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::DirsFirst ));
+ else
+ m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting & ~QDir::DirsFirst));
+ mySorting = m_fileView->sorting();
+}
+
+void KDirOperator::slotToggleIgnoreCase()
+{
+ QDir::SortSpec sorting = m_fileView->sorting();
+ if ( !KFile::isSortCaseInsensitive( sorting ) )
+ m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::IgnoreCase ));
+ else
+ m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting & ~QDir::IgnoreCase));
+ mySorting = m_fileView->sorting();
+}
+
+void KDirOperator::mkdir()
+{
+ bool ok;
+ QString where = url().pathOrURL();
+ QString name = i18n( "New Folder" );
+ if ( url().isLocalFile() && QFileInfo( url().path(+1) + name ).exists() )
+ name = KIO::RenameDlg::suggestName( url(), name );
+
+ QString dir = KInputDialog::getText( i18n( "New Folder" ),
+ i18n( "Create new folder in:\n%1" ).arg( where ),
+ name, &ok, this);
+ if (ok)
+ mkdir( KIO::encodeFileName( dir ), true );
+}
+
+bool KDirOperator::mkdir( const QString& directory, bool enterDirectory )
+{
+ // Creates "directory", relative to the current directory (currUrl).
+ // The given path may contain any number directories, existant or not.
+ // They will all be created, if possible.
+
+ bool writeOk = false;
+ bool exists = false;
+ KURL url( currUrl );
+
+ QStringList dirs = QStringList::split( QDir::separator(), directory );
+ QStringList::ConstIterator it = dirs.begin();
+
+ for ( ; it != dirs.end(); ++it )
+ {
+ url.addPath( *it );
+ exists = KIO::NetAccess::exists( url, false, 0 );
+ writeOk = !exists && KIO::NetAccess::mkdir( url, topLevelWidget() );
+ }
+
+ if ( exists ) // url was already existant
+ {
+ KMessageBox::sorry(viewWidget(), i18n("A file or folder named %1 already exists.").arg(url.pathOrURL()));
+ enterDirectory = false;
+ }
+ else if ( !writeOk ) {
+ KMessageBox::sorry(viewWidget(), i18n("You do not have permission to "
+ "create that folder." ));
+ }
+ else if ( enterDirectory ) {
+ setURL( url, true );
+ }
+
+ return writeOk;
+}
+
+KIO::DeleteJob * KDirOperator::del( const KFileItemList& items,
+ bool ask, bool showProgress )
+{
+ return del( items, this, ask, showProgress );
+}
+
+KIO::DeleteJob * KDirOperator::del( const KFileItemList& items,
+ QWidget *parent,
+ bool ask, bool showProgress )
+{
+ if ( items.isEmpty() ) {
+ KMessageBox::information( parent,
+ i18n("You did not select a file to delete."),
+ i18n("Nothing to Delete") );
+ return 0L;
+ }
+
+ KURL::List urls;
+ QStringList files;
+ KFileItemListIterator it( items );
+
+ for ( ; it.current(); ++it ) {
+ KURL url = (*it)->url();
+ urls.append( url );
+ if ( url.isLocalFile() )
+ files.append( url.path() );
+ else
+ files.append( url.prettyURL() );
+ }
+
+ bool doIt = !ask;
+ if ( ask ) {
+ int ret;
+ if ( items.count() == 1 ) {
+ ret = KMessageBox::warningContinueCancel( parent,
+ i18n( "<qt>Do you really want to delete\n <b>'%1'</b>?</qt>" )
+ .arg( files.first() ),
+ i18n("Delete File"),
+ KStdGuiItem::del(), "AskForDelete" );
+ }
+ else
+ ret = KMessageBox::warningContinueCancelList( parent,
+ i18n("Do you really want to delete this item?", "Do you really want to delete these %n items?", items.count() ),
+ files,
+ i18n("Delete Files"),
+ KStdGuiItem::del(), "AskForDelete" );
+ doIt = (ret == KMessageBox::Continue);
+ }
+
+ if ( doIt ) {
+ KIO::DeleteJob *job = KIO::del( urls, false, showProgress );
+ job->setWindow (topLevelWidget());
+ job->setAutoErrorHandlingEnabled( true, parent );
+ return job;
+ }
+
+ return 0L;
+}
+
+void KDirOperator::deleteSelected()
+{
+ if ( !m_fileView )
+ return;
+
+ const KFileItemList *list = m_fileView->selectedItems();
+ if ( list )
+ del( *list );
+}
+
+KIO::CopyJob * KDirOperator::trash( const KFileItemList& items,
+ QWidget *parent,
+ bool ask, bool showProgress )
+{
+ if ( items.isEmpty() ) {
+ KMessageBox::information( parent,
+ i18n("You did not select a file to trash."),
+ i18n("Nothing to Trash") );
+ return 0L;
+ }
+
+ KURL::List urls;
+ QStringList files;
+ KFileItemListIterator it( items );
+
+ for ( ; it.current(); ++it ) {
+ KURL url = (*it)->url();
+ urls.append( url );
+ if ( url.isLocalFile() )
+ files.append( url.path() );
+ else
+ files.append( url.prettyURL() );
+ }
+
+ bool doIt = !ask;
+ if ( ask ) {
+ int ret;
+ if ( items.count() == 1 ) {
+ ret = KMessageBox::warningContinueCancel( parent,
+ i18n( "<qt>Do you really want to trash\n <b>'%1'</b>?</qt>" )
+ .arg( files.first() ),
+ i18n("Trash File"),
+ KGuiItem(i18n("to trash", "&Trash"),"edittrash"), "AskForTrash" );
+ }
+ else
+ ret = KMessageBox::warningContinueCancelList( parent,
+ i18n("translators: not called for n == 1", "Do you really want to trash these %n items?", items.count() ),
+ files,
+ i18n("Trash Files"),
+ KGuiItem(i18n("to trash", "&Trash"),"edittrash"), "AskForTrash" );
+ doIt = (ret == KMessageBox::Continue);
+ }
+
+ if ( doIt ) {
+ KIO::CopyJob *job = KIO::trash( urls, showProgress );
+ job->setWindow (topLevelWidget());
+ job->setAutoErrorHandlingEnabled( true, parent );
+ return job;
+ }
+
+ return 0L;
+}
+
+void KDirOperator::trashSelected(KAction::ActivationReason reason, Qt::ButtonState state)
+{
+ if ( !m_fileView )
+ return;
+
+ if ( reason == KAction::PopupMenuActivation && ( state & Qt::ShiftButton ) ) {
+ deleteSelected();
+ return;
+ }
+
+ const KFileItemList *list = m_fileView->selectedItems();
+ if ( list )
+ trash( *list, this );
+}
+
+void KDirOperator::close()
+{
+ resetCursor();
+ pendingMimeTypes.clear();
+ myCompletion.clear();
+ myDirCompletion.clear();
+ myCompleteListDirty = true;
+ dir->stop();
+}
+
+void KDirOperator::checkPath(const QString &, bool /*takeFiles*/) // SLOT
+{
+#if 0
+ // copy the argument in a temporary string
+ QString text = _txt;
+ // it's unlikely to happen, that at the beginning are spaces, but
+ // for the end, it happens quite often, I guess.
+ text = text.stripWhiteSpace();
+ // if the argument is no URL (the check is quite fragil) and it's
+ // no absolute path, we add the current directory to get a correct url
+ if (text.find(':') < 0 && text[0] != '/')
+ text.insert(0, currUrl);
+
+ // in case we have a selection defined and someone patched the file-
+ // name, we check, if the end of the new name is changed.
+ if (!selection.isNull()) {
+ int position = text.findRev('/');
+ ASSERT(position >= 0); // we already inserted the current dir in case
+ QString filename = text.mid(position + 1, text.length());
+ if (filename != selection)
+ selection = QString::null;
+ }
+
+ KURL u(text); // I have to take care of entered URLs
+ bool filenameEntered = false;
+
+ if (u.isLocalFile()) {
+ // the empty path is kind of a hack
+ KFileItem i("", u.path());
+ if (i.isDir())
+ setURL(text, true);
+ else {
+ if (takeFiles)
+ if (acceptOnlyExisting && !i.isFile())
+ warning("you entered an invalid URL");
+ else
+ filenameEntered = true;
+ }
+ } else
+ setURL(text, true);
+
+ if (filenameEntered) {
+ filename_ = u.url();
+ emit fileSelected(filename_);
+
+ QApplication::restoreOverrideCursor();
+
+ accept();
+ }
+#endif
+ kdDebug(kfile_area) << "TODO KDirOperator::checkPath()" << endl;
+}
+
+void KDirOperator::setURL(const KURL& _newurl, bool clearforward)
+{
+ KURL newurl;
+
+ if ( !_newurl.isValid() )
+ newurl.setPath( QDir::homeDirPath() );
+ else
+ newurl = _newurl;
+
+ QString pathstr = newurl.path(+1);
+ newurl.setPath(pathstr);
+
+ // already set
+ if ( newurl.equals( currUrl, true ) )
+ return;
+
+ if ( !isReadable( newurl ) ) {
+ // maybe newurl is a file? check its parent directory
+ newurl.cd(QString::fromLatin1(".."));
+ if ( !isReadable( newurl ) ) {
+ resetCursor();
+ KMessageBox::error(viewWidget(),
+ i18n("The specified folder does not exist "
+ "or was not readable."));
+ return;
+ }
+ }
+
+ if (clearforward) {
+ // autodelete should remove this one
+ backStack.push(new KURL(currUrl));
+ forwardStack.clear();
+ }
+
+ d->lastURL = currUrl.url(-1);
+ currUrl = newurl;
+
+ pathChanged();
+ emit urlEntered(newurl);
+
+ // enable/disable actions
+ forwardAction->setEnabled( !forwardStack.isEmpty() );
+ backAction->setEnabled( !backStack.isEmpty() );
+ upAction->setEnabled( !isRoot() );
+
+ openURL( newurl );
+}
+
+void KDirOperator::updateDir()
+{
+ dir->emitChanges();
+ if ( m_fileView )
+ m_fileView->listingCompleted();
+}
+
+void KDirOperator::rereadDir()
+{
+ pathChanged();
+ openURL( currUrl, false, true );
+}
+
+
+bool KDirOperator::openURL( const KURL& url, bool keep, bool reload )
+{
+ bool result = dir->openURL( url, keep, reload );
+ if ( !result ) // in that case, neither completed() nor canceled() will be emitted by KDL
+ slotCanceled();
+
+ return result;
+}
+
+// Protected
+void KDirOperator::pathChanged()
+{
+ if (!m_fileView)
+ return;
+
+ pendingMimeTypes.clear();
+ m_fileView->clear();
+ myCompletion.clear();
+ myDirCompletion.clear();
+
+ // it may be, that we weren't ready at this time
+ QApplication::restoreOverrideCursor();
+
+ // when KIO::Job emits finished, the slot will restore the cursor
+ QApplication::setOverrideCursor( waitCursor );
+
+ if ( !isReadable( currUrl )) {
+ KMessageBox::error(viewWidget(),
+ i18n("The specified folder does not exist "
+ "or was not readable."));
+ if (backStack.isEmpty())
+ home();
+ else
+ back();
+ }
+}
+
+void KDirOperator::slotRedirected( const KURL& newURL )
+{
+ currUrl = newURL;
+ pendingMimeTypes.clear();
+ myCompletion.clear();
+ myDirCompletion.clear();
+ myCompleteListDirty = true;
+ emit urlEntered( newURL );
+}
+
+// Code pinched from kfm then hacked
+void KDirOperator::back()
+{
+ if ( backStack.isEmpty() )
+ return;
+
+ forwardStack.push( new KURL(currUrl) );
+
+ KURL *s = backStack.pop();
+
+ setURL(*s, false);
+ delete s;
+}
+
+// Code pinched from kfm then hacked
+void KDirOperator::forward()
+{
+ if ( forwardStack.isEmpty() )
+ return;
+
+ backStack.push(new KURL(currUrl));
+
+ KURL *s = forwardStack.pop();
+ setURL(*s, false);
+ delete s;
+}
+
+KURL KDirOperator::url() const
+{
+ return currUrl;
+}
+
+void KDirOperator::cdUp()
+{
+ KURL tmp(currUrl);
+ tmp.cd(QString::fromLatin1(".."));
+ setURL(tmp, true);
+}
+
+void KDirOperator::home()
+{
+ KURL u;
+ u.setPath( QDir::homeDirPath() );
+ setURL(u, true);
+}
+
+void KDirOperator::clearFilter()
+{
+ dir->setNameFilter( QString::null );
+ dir->clearMimeFilter();
+ checkPreviewSupport();
+}
+
+void KDirOperator::setNameFilter(const QString& filter)
+{
+ dir->setNameFilter(filter);
+ checkPreviewSupport();
+}
+
+void KDirOperator::setMimeFilter( const QStringList& mimetypes )
+{
+ dir->setMimeFilter( mimetypes );
+ checkPreviewSupport();
+}
+
+bool KDirOperator::checkPreviewSupport()
+{
+ KToggleAction *previewAction = static_cast<KToggleAction*>( myActionCollection->action( "preview" ));
+
+ bool hasPreviewSupport = false;
+ KConfig *kc = KGlobal::config();
+ KConfigGroupSaver cs( kc, ConfigGroup );
+ if ( kc->readBoolEntry( "Show Default Preview", true ) )
+ hasPreviewSupport = checkPreviewInternal();
+
+ previewAction->setEnabled( hasPreviewSupport );
+ return hasPreviewSupport;
+}
+
+bool KDirOperator::checkPreviewInternal() const
+{
+ QStringList supported = KIO::PreviewJob::supportedMimeTypes();
+ // no preview support for directories?
+ if ( dirOnlyMode() && supported.findIndex( "inode/directory" ) == -1 )
+ return false;
+
+ QStringList mimeTypes = dir->mimeFilters();
+ QStringList nameFilter = QStringList::split( " ", dir->nameFilter() );
+
+ if ( mimeTypes.isEmpty() && nameFilter.isEmpty() && !supported.isEmpty() )
+ return true;
+ else {
+ QRegExp r;
+ r.setWildcard( true ); // the "mimetype" can be "image/*"
+
+ if ( !mimeTypes.isEmpty() ) {
+ QStringList::Iterator it = supported.begin();
+
+ for ( ; it != supported.end(); ++it ) {
+ r.setPattern( *it );
+
+ QStringList result = mimeTypes.grep( r );
+ if ( !result.isEmpty() ) { // matches! -> we want previews
+ return true;
+ }
+ }
+ }
+
+ if ( !nameFilter.isEmpty() ) {
+ // find the mimetypes of all the filter-patterns and
+ KServiceTypeFactory *fac = KServiceTypeFactory::self();
+ QStringList::Iterator it1 = nameFilter.begin();
+ for ( ; it1 != nameFilter.end(); ++it1 ) {
+ if ( (*it1) == "*" ) {
+ return true;
+ }
+
+ KMimeType *mt = fac->findFromPattern( *it1 );
+ if ( !mt )
+ continue;
+ QString mime = mt->name();
+ delete mt;
+
+ // the "mimetypes" we get from the PreviewJob can be "image/*"
+ // so we need to check in wildcard mode
+ QStringList::Iterator it2 = supported.begin();
+ for ( ; it2 != supported.end(); ++it2 ) {
+ r.setPattern( *it2 );
+ if ( r.search( mime ) != -1 ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+KFileView* KDirOperator::createView( QWidget* parent, KFile::FileView view )
+{
+ KFileView* new_view = 0L;
+ bool separateDirs = KFile::isSeparateDirs( view );
+ bool preview = ( KFile::isPreviewInfo(view) || KFile::isPreviewContents( view ) );
+
+ if ( separateDirs || preview ) {
+ KCombiView *combi = 0L;
+ if (separateDirs)
+ {
+ combi = new KCombiView( parent, "combi view" );
+ combi->setOnlyDoubleClickSelectsFiles(d->onlyDoubleClickSelectsFiles);
+ }
+
+ KFileView* v = 0L;
+ if ( KFile::isSimpleView( view ) )
+ v = createView( combi, KFile::Simple );
+ else
+ v = createView( combi, KFile::Detail );
+
+ v->setOnlyDoubleClickSelectsFiles(d->onlyDoubleClickSelectsFiles);
+
+ if (combi)
+ combi->setRight( v );
+
+ if (preview)
+ {
+ KFilePreview* pView = new KFilePreview( combi ? combi : v, parent, "preview" );
+ pView->setOnlyDoubleClickSelectsFiles(d->onlyDoubleClickSelectsFiles);
+ new_view = pView;
+ }
+ else
+ new_view = combi;
+ }
+ else if ( KFile::isDetailView( view ) && !preview ) {
+ new_view = new KFileDetailView( parent, "detail view");
+ new_view->setViewName( i18n("Detailed View") );
+ }
+ else /* if ( KFile::isSimpleView( view ) && !preview ) */ {
+ KFileIconView *iconView = new KFileIconView( parent, "simple view");
+ new_view = iconView;
+ new_view->setViewName( i18n("Short View") );
+ }
+
+ new_view->widget()->setAcceptDrops(acceptDrops());
+ return new_view;
+}
+
+void KDirOperator::setAcceptDrops(bool b)
+{
+ if (m_fileView)
+ m_fileView->widget()->setAcceptDrops(b);
+ QWidget::setAcceptDrops(b);
+}
+
+void KDirOperator::setDropOptions(int options)
+{
+ d->dropOptions = options;
+ if (m_fileView)
+ m_fileView->setDropOptions(options);
+}
+
+void KDirOperator::setView( KFile::FileView view )
+{
+ bool separateDirs = KFile::isSeparateDirs( view );
+ bool preview=( KFile::isPreviewInfo(view) || KFile::isPreviewContents( view ) );
+
+ if (view == KFile::Default) {
+ if ( KFile::isDetailView( (KFile::FileView) defaultView ) )
+ view = KFile::Detail;
+ else
+ view = KFile::Simple;
+
+ separateDirs = KFile::isSeparateDirs( static_cast<KFile::FileView>(defaultView) );
+ preview = ( KFile::isPreviewInfo( static_cast<KFile::FileView>(defaultView) ) ||
+ KFile::isPreviewContents( static_cast<KFile::FileView>(defaultView) ) )
+ && myActionCollection->action("preview")->isEnabled();
+
+ if ( preview ) { // instantiates KFileMetaPreview and calls setView()
+ m_viewKind = defaultView;
+ slotDefaultPreview();
+ return;
+ }
+ else if ( !separateDirs )
+ separateDirsAction->setChecked(true);
+ }
+
+ // if we don't have any files, we can't separate dirs from files :)
+ if ( (mode() & KFile::File) == 0 &&
+ (mode() & KFile::Files) == 0 ) {
+ separateDirs = false;
+ separateDirsAction->setEnabled( false );
+ }
+
+ m_viewKind = static_cast<int>(view) | (separateDirs ? KFile::SeparateDirs : 0);
+ view = static_cast<KFile::FileView>(m_viewKind);
+
+ KFileView *new_view = createView( this, view );
+ if ( preview ) {
+ // we keep the preview-_widget_ around, but not the KFilePreview.
+ // KFilePreview::setPreviewWidget handles the reparenting for us
+ static_cast<KFilePreview*>(new_view)->setPreviewWidget(myPreview, url());
+ }
+
+ setView( new_view );
+}
+
+
+void KDirOperator::connectView(KFileView *view)
+{
+ // TODO: do a real timer and restart it after that
+ pendingMimeTypes.clear();
+ bool listDir = true;
+
+ if ( dirOnlyMode() )
+ view->setViewMode(KFileView::Directories);
+ else
+ view->setViewMode(KFileView::All);
+
+ if ( myMode & KFile::Files )
+ view->setSelectionMode( KFile::Extended );
+ else
+ view->setSelectionMode( KFile::Single );
+
+ if (m_fileView)
+ {
+ if ( d->config ) // save and restore the views' configuration
+ {
+ m_fileView->writeConfig( d->config, d->configGroup );
+ view->readConfig( d->config, d->configGroup );
+ }
+
+ // transfer the state from old view to new view
+ view->clear();
+ view->addItemList( *m_fileView->items() );
+ listDir = false;
+
+ if ( m_fileView->widget()->hasFocus() )
+ view->widget()->setFocus();
+
+ KFileItem *oldCurrentItem = m_fileView->currentFileItem();
+ if ( oldCurrentItem ) {
+ view->setCurrentItem( oldCurrentItem );
+ view->setSelected( oldCurrentItem, false );
+ view->ensureItemVisible( oldCurrentItem );
+ }
+
+ const KFileItemList *oldSelected = m_fileView->selectedItems();
+ if ( !oldSelected->isEmpty() ) {
+ KFileItemListIterator it( *oldSelected );
+ for ( ; it.current(); ++it )
+ view->setSelected( it.current(), true );
+ }
+
+ m_fileView->widget()->hide();
+ delete m_fileView;
+ }
+
+ else
+ {
+ if ( d->config )
+ view->readConfig( d->config, d->configGroup );
+ }
+
+ m_fileView = view;
+ m_fileView->setDropOptions(d->dropOptions);
+ viewActionCollection = 0L;
+ KFileViewSignaler *sig = view->signaler();
+
+ connect(sig, SIGNAL( activatedMenu(const KFileItem *, const QPoint& ) ),
+ this, SLOT( activatedMenu(const KFileItem *, const QPoint& )));
+ connect(sig, SIGNAL( dirActivated(const KFileItem *) ),
+ this, SLOT( selectDir(const KFileItem*) ) );
+ connect(sig, SIGNAL( fileSelected(const KFileItem *) ),
+ this, SLOT( selectFile(const KFileItem*) ) );
+ connect(sig, SIGNAL( fileHighlighted(const KFileItem *) ),
+ this, SLOT( highlightFile(const KFileItem*) ));
+ connect(sig, SIGNAL( sortingChanged( QDir::SortSpec ) ),
+ this, SLOT( slotViewSortingChanged( QDir::SortSpec )));
+ connect(sig, SIGNAL( dropped(const KFileItem *, QDropEvent*, const KURL::List&) ),
+ this, SIGNAL( dropped(const KFileItem *, QDropEvent*, const KURL::List&)) );
+
+ if ( reverseAction->isChecked() != m_fileView->isReversed() )
+ slotSortReversed();
+
+ updateViewActions();
+ m_fileView->widget()->resize(size());
+ m_fileView->widget()->show();
+
+ if ( listDir ) {
+ QApplication::setOverrideCursor( waitCursor );
+ openURL( currUrl );
+ }
+ else
+ view->listingCompleted();
+}
+
+KFile::Mode KDirOperator::mode() const
+{
+ return myMode;
+}
+
+void KDirOperator::setMode(KFile::Mode m)
+{
+ if (myMode == m)
+ return;
+
+ myMode = m;
+
+ dir->setDirOnlyMode( dirOnlyMode() );
+
+ // reset the view with the different mode
+ setView( static_cast<KFile::FileView>(m_viewKind) );
+}
+
+void KDirOperator::setView(KFileView *view)
+{
+ if ( view == m_fileView ) {
+ return;
+ }
+
+ setFocusProxy(view->widget());
+ view->setSorting( mySorting );
+ view->setOnlyDoubleClickSelectsFiles( d->onlyDoubleClickSelectsFiles );
+ connectView(view); // also deletes the old view
+
+ emit viewChanged( view );
+}
+
+void KDirOperator::setDirLister( KDirLister *lister )
+{
+ if ( lister == dir ) // sanity check
+ return;
+
+ delete dir;
+ dir = lister;
+
+ dir->setAutoUpdate( true );
+
+ QWidget* mainWidget = topLevelWidget();
+ dir->setMainWindow (mainWidget);
+ kdDebug (kfile_area) << "mainWidget=" << mainWidget << endl;
+
+ connect( dir, SIGNAL( percent( int )),
+ SLOT( slotProgress( int ) ));
+ connect( dir, SIGNAL(started( const KURL& )), SLOT(slotStarted()));
+ connect( dir, SIGNAL(newItems(const KFileItemList &)),
+ SLOT(insertNewFiles(const KFileItemList &)));
+ connect( dir, SIGNAL(completed()), SLOT(slotIOFinished()));
+ connect( dir, SIGNAL(canceled()), SLOT(slotCanceled()));
+ connect( dir, SIGNAL(deleteItem(KFileItem *)),
+ SLOT(itemDeleted(KFileItem *)));
+ connect( dir, SIGNAL(redirection( const KURL& )),
+ SLOT( slotRedirected( const KURL& )));
+ connect( dir, SIGNAL( clear() ), SLOT( slotClearView() ));
+ connect( dir, SIGNAL( refreshItems( const KFileItemList& ) ),
+ SLOT( slotRefreshItems( const KFileItemList& ) ) );
+}
+
+void KDirOperator::insertNewFiles(const KFileItemList &newone)
+{
+ if ( newone.isEmpty() || !m_fileView )
+ return;
+
+ myCompleteListDirty = true;
+ m_fileView->addItemList( newone );
+ emit updateInformation(m_fileView->numDirs(), m_fileView->numFiles());
+
+ KFileItem *item;
+ KFileItemListIterator it( newone );
+
+ while ( (item = it.current()) ) {
+ // highlight the dir we come from, if possible
+ if ( d->dirHighlighting && item->isDir() &&
+ item->url().url(-1) == d->lastURL ) {
+ m_fileView->setCurrentItem( item );
+ m_fileView->ensureItemVisible( item );
+ }
+
+ ++it;
+ }
+
+ QTimer::singleShot(200, this, SLOT(resetCursor()));
+}
+
+void KDirOperator::selectDir(const KFileItem *item)
+{
+ setURL(item->url(), true);
+}
+
+void KDirOperator::itemDeleted(KFileItem *item)
+{
+ pendingMimeTypes.removeRef( item );
+ if ( m_fileView )
+ {
+ m_fileView->removeItem( static_cast<KFileItem *>( item ));
+ emit updateInformation(m_fileView->numDirs(), m_fileView->numFiles());
+ }
+}
+
+void KDirOperator::selectFile(const KFileItem *item)
+{
+ QApplication::restoreOverrideCursor();
+
+ emit fileSelected( item );
+}
+
+void KDirOperator::setCurrentItem( const QString& filename )
+{
+ if ( m_fileView ) {
+ const KFileItem *item = 0L;
+
+ if ( !filename.isNull() )
+ item = static_cast<KFileItem *>(dir->findByName( filename ));
+
+ m_fileView->clearSelection();
+ if ( item ) {
+ m_fileView->setCurrentItem( item );
+ m_fileView->setSelected( item, true );
+ m_fileView->ensureItemVisible( item );
+ }
+ }
+}
+
+QString KDirOperator::makeCompletion(const QString& string)
+{
+ if ( string.isEmpty() ) {
+ m_fileView->clearSelection();
+ return QString::null;
+ }
+
+ prepareCompletionObjects();
+ return myCompletion.makeCompletion( string );
+}
+
+QString KDirOperator::makeDirCompletion(const QString& string)
+{
+ if ( string.isEmpty() ) {
+ m_fileView->clearSelection();
+ return QString::null;
+ }
+
+ prepareCompletionObjects();
+ return myDirCompletion.makeCompletion( string );
+}
+
+void KDirOperator::prepareCompletionObjects()
+{
+ if ( !m_fileView )
+ return;
+
+ if ( myCompleteListDirty ) { // create the list of all possible completions
+ KFileItemListIterator it( *(m_fileView->items()) );
+ for( ; it.current(); ++it ) {
+ KFileItem *item = it.current();
+
+ myCompletion.addItem( item->name() );
+ if ( item->isDir() )
+ myDirCompletion.addItem( item->name() );
+ }
+ myCompleteListDirty = false;
+ }
+}
+
+void KDirOperator::slotCompletionMatch(const QString& match)
+{
+ setCurrentItem( match );
+ emit completion( match );
+}
+
+void KDirOperator::setupActions()
+{
+ myActionCollection = new KActionCollection( topLevelWidget(), this, "KDirOperator::myActionCollection" );
+
+ actionMenu = new KActionMenu( i18n("Menu"), myActionCollection, "popupMenu" );
+ upAction = KStdAction::up( this, SLOT( cdUp() ), myActionCollection, "up" );
+ upAction->setText( i18n("Parent Folder") );
+ backAction = KStdAction::back( this, SLOT( back() ), myActionCollection, "back" );
+ forwardAction = KStdAction::forward( this, SLOT(forward()), myActionCollection, "forward" );
+ homeAction = KStdAction::home( this, SLOT( home() ), myActionCollection, "home" );
+ homeAction->setText(i18n("Home Folder"));
+ reloadAction = KStdAction::redisplay( this, SLOT(rereadDir()), myActionCollection, "reload" );
+ actionSeparator = new KActionSeparator( myActionCollection, "separator" );
+ d->viewActionSeparator = new KActionSeparator( myActionCollection,
+ "viewActionSeparator" );
+ mkdirAction = new KAction( i18n("New Folder..."), 0,
+ this, SLOT( mkdir() ), myActionCollection, "mkdir" );
+ KAction* trash = new KAction( i18n( "Move to Trash" ), "edittrash", Key_Delete, myActionCollection, "trash" );
+ connect( trash, SIGNAL( activated( KAction::ActivationReason, Qt::ButtonState ) ),
+ this, SLOT( trashSelected( KAction::ActivationReason, Qt::ButtonState ) ) );
+ new KAction( i18n( "Delete" ), "editdelete", SHIFT+Key_Delete, this,
+ SLOT( deleteSelected() ), myActionCollection, "delete" );
+ mkdirAction->setIcon( QString::fromLatin1("folder_new") );
+ reloadAction->setText( i18n("Reload") );
+ reloadAction->setShortcut( KStdAccel::shortcut( KStdAccel::Reload ));
+
+
+ // the sort menu actions
+ sortActionMenu = new KActionMenu( i18n("Sorting"), myActionCollection, "sorting menu");
+ byNameAction = new KRadioAction( i18n("By Name"), 0,
+ this, SLOT( slotSortByName() ),
+ myActionCollection, "by name" );
+ byDateAction = new KRadioAction( i18n("By Date"), 0,
+ this, SLOT( slotSortByDate() ),
+ myActionCollection, "by date" );
+ bySizeAction = new KRadioAction( i18n("By Size"), 0,
+ this, SLOT( slotSortBySize() ),
+ myActionCollection, "by size" );
+ reverseAction = new KToggleAction( i18n("Reverse"), 0,
+ this, SLOT( slotSortReversed() ),
+ myActionCollection, "reversed" );
+
+ QString sortGroup = QString::fromLatin1("sort");
+ byNameAction->setExclusiveGroup( sortGroup );
+ byDateAction->setExclusiveGroup( sortGroup );
+ bySizeAction->setExclusiveGroup( sortGroup );
+
+
+ dirsFirstAction = new KToggleAction( i18n("Folders First"), 0,
+ myActionCollection, "dirs first");
+ caseInsensitiveAction = new KToggleAction(i18n("Case Insensitive"), 0,
+ myActionCollection, "case insensitive" );
+
+ connect( dirsFirstAction, SIGNAL( toggled( bool ) ),
+ SLOT( slotToggleDirsFirst() ));
+ connect( caseInsensitiveAction, SIGNAL( toggled( bool ) ),
+ SLOT( slotToggleIgnoreCase() ));
+
+
+
+ // the view menu actions
+ viewActionMenu = new KActionMenu( i18n("&View"), myActionCollection, "view menu" );
+ connect( viewActionMenu->popupMenu(), SIGNAL( aboutToShow() ),
+ SLOT( insertViewDependentActions() ));
+
+ shortAction = new KRadioAction( i18n("Short View"), "view_multicolumn",
+ KShortcut(), myActionCollection, "short view" );
+ detailedAction = new KRadioAction( i18n("Detailed View"), "view_detailed",
+ KShortcut(), myActionCollection, "detailed view" );
+
+ showHiddenAction = new KToggleAction( i18n("Show Hidden Files"), KShortcut(),
+ myActionCollection, "show hidden" );
+// showHiddenAction->setCheckedState( i18n("Hide Hidden Files") );
+ separateDirsAction = new KToggleAction( i18n("Separate Folders"), KShortcut(),
+ this,
+ SLOT(slotSeparateDirs()),
+ myActionCollection, "separate dirs" );
+ KToggleAction *previewAction = new KToggleAction(i18n("Show Preview"),
+ "thumbnail", KShortcut(),
+ myActionCollection,
+ "preview" );
+ previewAction->setCheckedState(i18n("Hide Preview"));
+ connect( previewAction, SIGNAL( toggled( bool )),
+ SLOT( togglePreview( bool )));
+
+
+ QString viewGroup = QString::fromLatin1("view");
+ shortAction->setExclusiveGroup( viewGroup );
+ detailedAction->setExclusiveGroup( viewGroup );
+
+ connect( shortAction, SIGNAL( activated() ),
+ SLOT( slotSimpleView() ));
+ connect( detailedAction, SIGNAL( activated() ),
+ SLOT( slotDetailedView() ));
+ connect( showHiddenAction, SIGNAL( toggled( bool ) ),
+ SLOT( slotToggleHidden( bool ) ));
+
+ new KAction( i18n("Properties"), KShortcut(ALT+Key_Return), this,
+ SLOT(slotProperties()), myActionCollection, "properties" );
+}
+
+void KDirOperator::setupMenu()
+{
+ setupMenu(AllActions);
+}
+
+void KDirOperator::setupMenu(int whichActions)
+{
+ // first fill the submenus (sort and view)
+ sortActionMenu->popupMenu()->clear();
+ sortActionMenu->insert( byNameAction );
+ sortActionMenu->insert( byDateAction );
+ sortActionMenu->insert( bySizeAction );
+ sortActionMenu->insert( actionSeparator );
+ sortActionMenu->insert( reverseAction );
+ sortActionMenu->insert( dirsFirstAction );
+ sortActionMenu->insert( caseInsensitiveAction );
+
+ // now plug everything into the popupmenu
+ actionMenu->popupMenu()->clear();
+ if (whichActions & NavActions)
+ {
+ actionMenu->insert( upAction );
+ actionMenu->insert( backAction );
+ actionMenu->insert( forwardAction );
+ actionMenu->insert( homeAction );
+ actionMenu->insert( actionSeparator );
+ }
+
+ if (whichActions & FileActions)
+ {
+ actionMenu->insert( mkdirAction );
+ if (currUrl.isLocalFile() && !(KApplication::keyboardMouseState() & Qt::ShiftButton))
+ actionMenu->insert( myActionCollection->action( "trash" ) );
+ KConfig *globalconfig = KGlobal::config();
+ KConfigGroupSaver cs( globalconfig, QString::fromLatin1("KDE") );
+ if (!currUrl.isLocalFile() || (KApplication::keyboardMouseState() & Qt::ShiftButton) ||
+ globalconfig->readBoolEntry("ShowDeleteCommand", false))
+ actionMenu->insert( myActionCollection->action( "delete" ) );
+ actionMenu->insert( actionSeparator );
+ }
+
+ if (whichActions & SortActions)
+ {
+ actionMenu->insert( sortActionMenu );
+ actionMenu->insert( actionSeparator );
+ }
+
+ if (whichActions & ViewActions)
+ {
+ actionMenu->insert( viewActionMenu );
+ actionMenu->insert( actionSeparator );
+ }
+
+ if (whichActions & FileActions)
+ {
+ actionMenu->insert( myActionCollection->action( "properties" ) );
+ }
+}
+
+void KDirOperator::updateSortActions()
+{
+ if ( KFile::isSortByName( mySorting ) )
+ byNameAction->setChecked( true );
+ else if ( KFile::isSortByDate( mySorting ) )
+ byDateAction->setChecked( true );
+ else if ( KFile::isSortBySize( mySorting ) )
+ bySizeAction->setChecked( true );
+
+ dirsFirstAction->setChecked( KFile::isSortDirsFirst( mySorting ) );
+ caseInsensitiveAction->setChecked( KFile::isSortCaseInsensitive(mySorting) );
+ caseInsensitiveAction->setEnabled( KFile::isSortByName( mySorting ) );
+
+ if ( m_fileView )
+ reverseAction->setChecked( m_fileView->isReversed() );
+}
+
+void KDirOperator::updateViewActions()
+{
+ KFile::FileView fv = static_cast<KFile::FileView>( m_viewKind );
+
+ separateDirsAction->setChecked( KFile::isSeparateDirs( fv ) &&
+ separateDirsAction->isEnabled() );
+
+ shortAction->setChecked( KFile::isSimpleView( fv ));
+ detailedAction->setChecked( KFile::isDetailView( fv ));
+}
+
+void KDirOperator::readConfig( KConfig *kc, const QString& group )
+{
+ if ( !kc )
+ return;
+ QString oldGroup = kc->group();
+ if ( !group.isEmpty() )
+ kc->setGroup( group );
+
+ defaultView = 0;
+ int sorting = 0;
+
+ QString viewStyle = kc->readEntry( QString::fromLatin1("View Style"),
+ QString::fromLatin1("Simple") );
+ if ( viewStyle == QString::fromLatin1("Detail") )
+ defaultView |= KFile::Detail;
+ else
+ defaultView |= KFile::Simple;
+ if ( kc->readBoolEntry( QString::fromLatin1("Separate Directories"),
+ DefaultMixDirsAndFiles ) )
+ defaultView |= KFile::SeparateDirs;
+ if ( kc->readBoolEntry(QString::fromLatin1("Show Preview"), false))
+ defaultView |= KFile::PreviewContents;
+
+ if ( kc->readBoolEntry( QString::fromLatin1("Sort case insensitively"),
+ DefaultCaseInsensitive ) )
+ sorting |= QDir::IgnoreCase;
+ if ( kc->readBoolEntry( QString::fromLatin1("Sort directories first"),
+ DefaultDirsFirst ) )
+ sorting |= QDir::DirsFirst;
+
+
+ QString name = QString::fromLatin1("Name");
+ QString sortBy = kc->readEntry( QString::fromLatin1("Sort by"), name );
+ if ( sortBy == name )
+ sorting |= QDir::Name;
+ else if ( sortBy == QString::fromLatin1("Size") )
+ sorting |= QDir::Size;
+ else if ( sortBy == QString::fromLatin1("Date") )
+ sorting |= QDir::Time;
+
+ mySorting = static_cast<QDir::SortSpec>( sorting );
+ setSorting( mySorting );
+
+
+ if ( kc->readBoolEntry( QString::fromLatin1("Show hidden files"),
+ DefaultShowHidden ) ) {
+ showHiddenAction->setChecked( true );
+ dir->setShowingDotFiles( true );
+ }
+ if ( kc->readBoolEntry( QString::fromLatin1("Sort reversed"),
+ DefaultSortReversed ) )
+ reverseAction->setChecked( true );
+
+ kc->setGroup( oldGroup );
+}
+
+void KDirOperator::writeConfig( KConfig *kc, const QString& group )
+{
+ if ( !kc )
+ return;
+
+ const QString oldGroup = kc->group();
+
+ if ( !group.isEmpty() )
+ kc->setGroup( group );
+
+ QString sortBy = QString::fromLatin1("Name");
+ if ( KFile::isSortBySize( mySorting ) )
+ sortBy = QString::fromLatin1("Size");
+ else if ( KFile::isSortByDate( mySorting ) )
+ sortBy = QString::fromLatin1("Date");
+ kc->writeEntry( QString::fromLatin1("Sort by"), sortBy );
+
+ kc->writeEntry( QString::fromLatin1("Sort reversed"),
+ reverseAction->isChecked() );
+ kc->writeEntry( QString::fromLatin1("Sort case insensitively"),
+ caseInsensitiveAction->isChecked() );
+ kc->writeEntry( QString::fromLatin1("Sort directories first"),
+ dirsFirstAction->isChecked() );
+
+ // don't save the separate dirs or preview when an application specific
+ // preview is in use.
+ bool appSpecificPreview = false;
+ if ( myPreview ) {
+ QWidget *preview = const_cast<QWidget*>( myPreview ); // grmbl
+ KFileMetaPreview *tmp = dynamic_cast<KFileMetaPreview*>( preview );
+ appSpecificPreview = (tmp == 0L);
+ }
+
+ if ( !appSpecificPreview ) {
+ if ( separateDirsAction->isEnabled() )
+ kc->writeEntry( QString::fromLatin1("Separate Directories"),
+ separateDirsAction->isChecked() );
+
+ KToggleAction *previewAction = static_cast<KToggleAction*>(myActionCollection->action("preview"));
+ if ( previewAction->isEnabled() ) {
+ bool hasPreview = previewAction->isChecked();
+ kc->writeEntry( QString::fromLatin1("Show Preview"), hasPreview );
+ }
+ }
+
+ kc->writeEntry( QString::fromLatin1("Show hidden files"),
+ showHiddenAction->isChecked() );
+
+ KFile::FileView fv = static_cast<KFile::FileView>( m_viewKind );
+ QString style;
+ if ( KFile::isDetailView( fv ) )
+ style = QString::fromLatin1("Detail");
+ else if ( KFile::isSimpleView( fv ) )
+ style = QString::fromLatin1("Simple");
+ kc->writeEntry( QString::fromLatin1("View Style"), style );
+
+ kc->setGroup( oldGroup );
+}
+
+
+void KDirOperator::resizeEvent( QResizeEvent * )
+{
+ if (m_fileView)
+ m_fileView->widget()->resize( size() );
+
+ if ( progress->parent() == this ) // might be reparented into a statusbar
+ progress->move(2, height() - progress->height() -2);
+}
+
+void KDirOperator::setOnlyDoubleClickSelectsFiles( bool enable )
+{
+ d->onlyDoubleClickSelectsFiles = enable;
+ if ( m_fileView )
+ m_fileView->setOnlyDoubleClickSelectsFiles( enable );
+}
+
+bool KDirOperator::onlyDoubleClickSelectsFiles() const
+{
+ return d->onlyDoubleClickSelectsFiles;
+}
+
+void KDirOperator::slotStarted()
+{
+ progress->setProgress( 0 );
+ // delay showing the progressbar for one second
+ d->progressDelayTimer->start( 1000, true );
+}
+
+void KDirOperator::slotShowProgress()
+{
+ progress->raise();
+ progress->show();
+ QApplication::flushX();
+}
+
+void KDirOperator::slotProgress( int percent )
+{
+ progress->setProgress( percent );
+ // we have to redraw this as fast as possible
+ if ( progress->isVisible() )
+ QApplication::flushX();
+}
+
+
+void KDirOperator::slotIOFinished()
+{
+ d->progressDelayTimer->stop();
+ slotProgress( 100 );
+ progress->hide();
+ emit finishedLoading();
+ resetCursor();
+
+ if ( m_fileView )
+ m_fileView->listingCompleted();
+}
+
+void KDirOperator::slotCanceled()
+{
+ emit finishedLoading();
+ resetCursor();
+
+ if ( m_fileView )
+ m_fileView->listingCompleted();
+}
+
+KProgress * KDirOperator::progressBar() const
+{
+ return progress;
+}
+
+void KDirOperator::clearHistory()
+{
+ backStack.clear();
+ backAction->setEnabled( false );
+ forwardStack.clear();
+ forwardAction->setEnabled( false );
+}
+
+void KDirOperator::slotViewActionAdded( KAction *action )
+{
+ if ( viewActionMenu->popupMenu()->count() == 5 ) // need to add a separator
+ viewActionMenu->insert( d->viewActionSeparator );
+
+ viewActionMenu->insert( action );
+}
+
+void KDirOperator::slotViewActionRemoved( KAction *action )
+{
+ viewActionMenu->remove( action );
+
+ if ( viewActionMenu->popupMenu()->count() == 6 ) // remove the separator
+ viewActionMenu->remove( d->viewActionSeparator );
+}
+
+void KDirOperator::slotViewSortingChanged( QDir::SortSpec sort )
+{
+ mySorting = sort;
+ updateSortActions();
+}
+
+void KDirOperator::setEnableDirHighlighting( bool enable )
+{
+ d->dirHighlighting = enable;
+}
+
+bool KDirOperator::dirHighlighting() const
+{
+ return d->dirHighlighting;
+}
+
+void KDirOperator::slotProperties()
+{
+ if ( m_fileView ) {
+ const KFileItemList *list = m_fileView->selectedItems();
+ if ( !list->isEmpty() )
+ (void) new KPropertiesDialog( *list, this, "props dlg", true);
+ }
+}
+
+void KDirOperator::slotClearView()
+{
+ if ( m_fileView )
+ m_fileView->clearView();
+}
+
+// ### temporary code
+#include <dirent.h>
+bool KDirOperator::isReadable( const KURL& url )
+{
+ if ( !url.isLocalFile() )
+ return true; // what else can we say?
+
+ KDE_struct_stat buf;
+ QString ts = url.path(+1);
+ bool readable = ( KDE_stat( QFile::encodeName( ts ), &buf) == 0 );
+ if (readable) { // further checks
+ DIR *test;
+ test = opendir( QFile::encodeName( ts )); // we do it just to test here
+ readable = (test != 0);
+ if (test)
+ closedir(test);
+ }
+ return readable;
+}
+
+void KDirOperator::togglePreview( bool on )
+{
+ if ( on )
+ slotDefaultPreview();
+ else
+ setView( (KFile::FileView) (m_viewKind & ~(KFile::PreviewContents|KFile::PreviewInfo)) );
+}
+
+void KDirOperator::slotRefreshItems( const KFileItemList& items )
+{
+ if ( !m_fileView )
+ return;
+
+ KFileItemListIterator it( items );
+ for ( ; it.current(); ++it )
+ m_fileView->updateView( it.current() );
+}
+
+void KDirOperator::setViewConfig( KConfig *config, const QString& group )
+{
+ d->config = config;
+ d->configGroup = group;
+}
+
+KConfig * KDirOperator::viewConfig()
+{
+ return d->config;
+}
+
+QString KDirOperator::viewConfigGroup() const
+{
+ return d->configGroup;
+}
+
+void KDirOperator::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kdiroperator.moc"
diff --git a/kio/kfile/kdiroperator.h b/kio/kfile/kdiroperator.h
new file mode 100644
index 000000000..a91c7ff1a
--- /dev/null
+++ b/kio/kfile/kdiroperator.h
@@ -0,0 +1,950 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Stephan Kulow <coolo@kde.org>
+ 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KDIROPERATOR_H_
+#define KDIROPERATOR_H_
+
+#include <qwidget.h>
+#include <qptrstack.h>
+
+#include <kaction.h>
+#include <kcompletion.h>
+#include <kdirlister.h>
+#include <kfileview.h>
+#include <kfileitem.h>
+#include <kfile.h>
+
+class QPopupMenu;
+class QTimer;
+
+class KAction;
+class KDirLister;
+class KToggleAction;
+class KActionSeparator;
+class KActionMenu;
+class QWidgetStack;
+class KProgress;
+namespace KIO {
+ class CopyJob;
+ class DeleteJob;
+}
+
+/**
+ * This widget works as a network transparent filebrowser. You specify a URL
+ * to display and this url will be loaded via KDirLister. The user can
+ * browse through directories, highlight and select files, delete or rename
+ * files.
+ *
+ * It supports different views, e.g. a detailed view (see KFileDetailView),
+ * a simple icon view (see KFileIconView), a combination of two views,
+ * separating directories and files ( KCombiView).
+ *
+ * Additionally, a preview view is available (see KFilePreview), which can
+ * show either a simple or detailed view and additionally a preview widget
+ * (see setPreviewWidget()). KImageFilePreview is one implementation
+ * of a preview widget, that displays previews for all supported filetypes
+ * utilizing KIO::PreviewJob.
+ *
+ * Currently, those classes don't support Drag&Drop out of the box -- there
+ * you have to use your own view-classes. You can use some DnD-aware views
+ * from Bj�n Sahlstr� <bjorn@kbear.org> until they will be integrated
+ * into this library. See http://devel-home.kde.org/~pfeiffer/DnD-classes.tar.gz
+ *
+ * This widget is the one used in the KFileDialog.
+ *
+ * Basic usage is like this:
+ * \code
+ * KDirOperator *op = new KDirOperator( KURL( "file:/home/gis" ), this );
+ * // some signals you might be interested in
+ * connect(op, SIGNAL(urlEntered(const KURL&)),
+ * SLOT(urlEntered(const KURL&)));
+ * connect(op, SIGNAL(fileHighlighted(const KFileItem *)),
+ * SLOT(fileHighlighted(const KFileItem *)));
+ * connect(op, SIGNAL(fileSelected(const KFileItem *)),
+ * SLOT(fileSelected(const KFileItem *)));
+ * connect(op, SIGNAL(finishedLoading()),
+ * SLOT(slotLoadingFinished()));
+ *
+ * op->readConfig( KGlobal::config(), "Your KDiroperator ConfigGroup" );
+ * op->setView(KFile::Default);
+ * \endcode
+ *
+ * This will create a childwidget of 'this' showing the directory contents
+ * of /home/gis in the default-view. The view is determined by the readConfig()
+ * call, which will read the KDirOperator settings, the user left your program
+ * with (and which you saved with op->writeConfig()).
+ *
+ * @short A widget for displaying files and browsing directories.
+ * @author Stephan Kulow <coolo@kde.org>, Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class KIO_EXPORT KDirOperator : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * The various action types. These values can be or'd together
+ * @since 3.1
+ */
+ enum ActionTypes { SortActions = 1,
+ ViewActions = 2,
+ NavActions = 4,
+ FileActions = 8,
+ AllActions = 15 };
+ /**
+ * Constructs the KDirOperator with no initial view. As the views are
+ * configurable, call readConfig() to load the user's configuration
+ * and then setView to explicitly set a view.
+ *
+ * This constructor doesn't start loading the url, setView will do it.
+ */
+ KDirOperator(const KURL& urlName = KURL(),
+ QWidget *parent = 0, const char* name = 0);
+ /**
+ * Destroys the KDirOperator.
+ */
+ virtual ~KDirOperator();
+
+ /**
+ * Enables/disables showing hidden files.
+ */
+ // ### KDE4: make virtual
+ void setShowHiddenFiles ( bool s ) { showHiddenAction->setChecked( s ); }
+
+ /**
+ * @returns true when hidden files are shown or false otherwise.
+ */
+ bool showHiddenFiles () const { return showHiddenAction->isChecked(); }
+
+ /**
+ * Stops loading immediately. You don't need to call this, usually.
+ */
+ void close();
+ /// Reimplemented to avoid "hidden virtual" warnings
+ virtual bool close( bool alsoDelete ) { return QWidget::close( alsoDelete ); }
+
+ /**
+ * Sets a filter like "*.cpp *.h *.o". Only files matching that filter
+ * will be shown. Call updateDir() to apply it.
+ *
+ * @see KDirLister::setNameFilter
+ * @see nameFilter
+ */
+ void setNameFilter(const QString& filter);
+
+ /**
+ * @returns the current namefilter.
+ * @see setNameFilter
+ */
+ const QString& nameFilter() const { return dir->nameFilter(); }
+
+ /**
+ * Sets a list of mimetypes as filter. Only files of those mimetypes
+ * will be shown.
+ *
+ * Example:
+ * \code
+ * QStringList filter;
+ * filter << "text/html" << "image/png" << "inode/directory";
+ * dirOperator->setMimefilter( filter );
+ * \endcode
+ *
+ * Node: Without the mimetype inode/directory, only files would be shown.
+ * Call updateDir() to apply it.
+ *
+ * @see KDirLister::setMimeFilter
+ * @see mimeFilter
+ */
+ void setMimeFilter( const QStringList& mimetypes );
+
+ /**
+ * @returns the current mime filter.
+ */
+ QStringList mimeFilter() const { return dir->mimeFilters(); }
+
+ /**
+ * Clears both the namefilter and mimetype filter, so that all files and
+ * directories will be shown. Call updateDir() to apply it.
+ *
+ * @see setMimeFilter
+ * @see setNameFilter
+ */
+ void clearFilter();
+
+ /**
+ * @returns the current url
+ */
+ KURL url() const;
+
+ /**
+ * Sets a new url to list.
+ * @param clearforward specifies whether the "forward" history should be cleared.
+ * @param url the URL to set
+ */
+ // ### KDE4: make virtual
+ void setURL(const KURL& url, bool clearforward);
+
+ /**
+ * Clears the current selection and attempts to set @p filename
+ * the current file. filename is just the name, no path or url.
+ */
+ void setCurrentItem( const QString& filename );
+
+ /**
+ * Sets a new KFileView to be used for showing and browsing files.
+ * Note: this will read the current url() to fill the view.
+ *
+ * @see KFileView
+ * @see KFileIconView
+ * @see KFileDetailView
+ * @see KCombiView
+ * @see view
+ */
+ // ### KDE4: make virtual
+ void setView(KFileView *view);
+
+ /**
+ * @returns the currently used view.
+ * @see setView
+ */
+ KFileView * view() const { return m_fileView; }
+
+ /**
+ * Returns the widget of the current view. 0L if there is no view/widget.
+ * (KFileView itself is not a widget.)
+ */
+ QWidget * viewWidget() const { return m_fileView ? m_fileView->widget() : 0L; }
+
+ /**
+ * Sets one of the predefined fileviews
+ * @see KFile::FileView
+ */
+ // ### KDE4: make virtual
+ void setView(KFile::FileView view);
+
+ /**
+ * Sets the way to sort files and directories.
+ */
+ void setSorting( QDir::SortSpec );
+
+ /**
+ * @returns the current way of sorting files and directories
+ */
+ QDir::SortSpec sorting() const { return mySorting; }
+
+ /**
+ * @returns true if we are displaying the root directory of the current url
+ */
+ bool isRoot() const { return url().path() == QChar('/'); }
+
+ /**
+ * @returns the object listing the directory
+ */
+ KDirLister *dirLister() const { return dir; }
+
+ /**
+ * @returns the progress widget, that is shown during directory listing.
+ * You can for example reparent() it to put it into a statusbar.
+ */
+ KProgress * progressBar() const;
+
+ /**
+ * Sets the listing/selection mode for the views, an OR'ed combination of
+ * @li File
+ * @li Directory
+ * @li Files
+ * @li ExistingOnly
+ * @li LocalOnly
+ *
+ * You cannot mix File and Files of course, as the former means
+ * single-selection mode, the latter multi-selection.
+ */
+ // ### KDE4: make virtual
+ void setMode( KFile::Mode m );
+ /**
+ * @returns the listing/selection mode.
+ */
+ KFile::Mode mode() const;
+
+ /**
+ * Sets a preview-widget to be shown next to the file-view.
+ * The ownership of @p w is transferred to KDirOperator, so don't
+ * delete it yourself!
+ */
+ // ### KDE4: make virtual
+ void setPreviewWidget(const QWidget *w);
+
+ /**
+ * @returns a list of all currently selected items. If there is no view,
+ * then 0L is returned.
+ */
+ const KFileItemList * selectedItems() const {
+ return ( m_fileView ? m_fileView->selectedItems() : 0L );
+ }
+
+ /**
+ * @returns true if @p item is currently selected, or false otherwise.
+ */
+ inline bool isSelected( const KFileItem *item ) const {
+ return ( m_fileView ? m_fileView->isSelected( item ) : false );
+ }
+
+ /**
+ * @returns the number of directories in the currently listed url.
+ * Returns 0 if there is no view.
+ */
+ int numDirs() const;
+
+ /**
+ * @returns the number of files in the currently listed url.
+ * Returns 0 if there is no view.
+ */
+ int numFiles() const;
+
+ /**
+ * @returns a KCompletion object, containing all filenames and
+ * directories of the current directory/URL.
+ * You can use it to insert it into a KLineEdit or KComboBox
+ * Note: it will only contain files, after prepareCompletionObjects()
+ * has been called. It will be implicitly called from makeCompletion()
+ * or makeDirCompletion()
+ */
+ KCompletion * completionObject() const {
+ return const_cast<KCompletion *>( &myCompletion );
+ }
+
+ /**
+ * @returns a KCompletion object, containing only all directories of the
+ * current directory/URL.
+ * You can use it to insert it into a KLineEdit or KComboBox
+ * Note: it will only contain directories, after
+ * prepareCompletionObjects() has been called. It will be implicitly
+ * called from makeCompletion() or makeDirCompletion()
+ */
+ KCompletion *dirCompletionObject() const {
+ return const_cast<KCompletion *>( &myDirCompletion );
+ }
+
+ /**
+ * an accessor to a collection of all available Actions. The actions
+ * are static, they will be there all the time (no need to connect to
+ * the signals KActionCollection::inserted() or removed().
+ *
+ * There are the following actions:
+ *
+ * @li popupMenu : an ActionMenu presenting a popupmenu with all actions
+ * @li up : changes to the parent directory
+ * @li back : goes back to the previous directory
+ * @li forward : goes forward in the history
+ * @li home : changes to the user's home directory
+ * @li reload : reloads the current directory
+ * @li separator : a separator
+ * @li mkdir : opens a dialog box to create a directory
+ * @li delete : deletes the selected files/directories
+ * @li sorting menu : an ActionMenu containing all sort-options
+ * @li by name : sorts by name
+ * @li by date : sorts by date
+ * @li by size : sorts by size
+ * @li reversed : reverses the sort order
+ * @li dirs first : sorts directories before files
+ * @li case insensitive : sorts case insensitively
+ * @li view menu : an ActionMenu containing all actions concerning the view
+ * @li short view : shows a simple fileview
+ * @li detailed view : shows a detailed fileview (dates, permissions ,...)
+ * @li show hidden : shows hidden files
+ * @li separate dirs : shows directories in a separate pane
+ * @li preview : shows a preview next to the fileview
+ * @li single : hides the separate view for directories or the preview
+ * @li properties : shows a KPropertiesDialog for the selected files
+ *
+ * The short and detailed view are in an exclusive group. The sort-by
+ * actions are in an exclusive group as well. Also the "separate dirs",
+ * "preview" and "single" actions are in an exclusive group.
+ *
+ * You can e.g. use
+ * \code
+ * actionCollection()->action( "up" )->plug( someToolBar );
+ * \endcode
+ * to add a button into a toolbar, which makes the dirOperator change to
+ * its parent directory.
+ *
+ * @returns all available Actions
+ */
+ KActionCollection * actionCollection() const { return myActionCollection; }
+
+ /**
+ * Sets the config object and the to be used group in KDirOperator. This
+ * will be used to store the view's configuration via
+ * KFileView::writeConfig() (and for KFileView::readConfig()).
+ * If you don't set this, the views cannot save and restore their
+ * configuration.
+ *
+ * Usually you call this right after KDirOperator creation so that the view
+ * instantiation can make use of it already.
+ *
+ * Note that KDirOperator does NOT take ownership of that object (typically
+ * it's KGlobal::config() anyway.
+ *
+ * @see viewConfig
+ * @see viewConfigGroup
+ * @since 3.1
+ */
+ // ### KDE4: make virtual
+ void setViewConfig( KConfig *config, const QString& group );
+
+ /**
+ * Returns the KConfig object used for saving and restoring view's
+ * configuration.
+ * @returns the KConfig object used for saving and restoring view's
+ * configuration.
+ * @since 3.1
+ */
+ KConfig *viewConfig();
+
+ /**
+ * Returns the group name used for saving and restoring view's
+ * configuration.
+ * @returns the group name used for saving and restoring view's
+ * configuration.
+ * @since 3.1
+ */
+ QString viewConfigGroup() const;
+
+ /**
+ * Reads the default settings for a view, i.e. the default KFile::FileView.
+ * Also reads the sorting and whether hidden files should be shown.
+ * Note: the default view will not be set - you have to call
+ * \code
+ * setView( KFile::Default )
+ * \endcode
+ * to apply it.
+ *
+ * @see setView
+ * @see setViewConfig
+ * @see writeConfig
+ */
+ virtual void readConfig( KConfig *, const QString& group = QString::null );
+
+ /**
+ * Saves the current settings like sorting, simple or detailed view.
+ *
+ * @see readConfig
+ * @see setViewConfig
+ */
+ virtual void writeConfig( KConfig *, const QString& group = QString::null );
+
+
+ /**
+ * This is a KFileDialog specific hack: we want to select directories with
+ * single click, but not files. But as a generic class, we have to be able
+ * to select files on single click as well.
+ *
+ * This gives us the opportunity to do both.
+ *
+ * The default is false, set it to true if you don't want files selected
+ * with single click.
+ */
+ void setOnlyDoubleClickSelectsFiles( bool enable );
+
+ /**
+ * @returns whether files (not directories) should only be select()ed by
+ * double-clicks.
+ * @see setOnlyDoubleClickSelectsFiles
+ */
+ bool onlyDoubleClickSelectsFiles() const;
+
+ /**
+ * Creates the given directory/url. If it is a relative path,
+ * it will be completed with the current directory.
+ * If enterDirectory is true, the directory will be entered after a
+ * successful operation. If unsuccessful, a messagebox will be presented
+ * to the user.
+ * @returns true if the directory could be created.
+ */
+ // ### KDE4: make virtual and turn QString into KURL
+ bool mkdir( const QString& directory, bool enterDirectory = true );
+
+ /**
+ * Starts and returns a KIO::DeleteJob to delete the given @p items.
+ *
+ * @param items the list of items to be deleted
+ * @param ask specifies whether a confirmation dialog should be shown
+ * @param showProgress passed to the DeleteJob to show a progress dialog
+ */
+ // ### KDE4: make virtual
+ KIO::DeleteJob * del( const KFileItemList& items,
+ bool ask = true, bool showProgress = true );
+
+ /**
+ * Starts and returns a KIO::DeleteJob to delete the given @p items.
+ *
+ * @param items the list of items to be deleted
+ * @param parent the parent widget used for the confirmation dialog
+ * @param ask specifies whether a confirmation dialog should be shown
+ * @param showProgress passed to the DeleteJob to show a progress dialog
+ * @since 3.1
+ */
+ // ### KDE4: make virtual
+ KIO::DeleteJob * del( const KFileItemList& items, QWidget *parent,
+ bool ask = true, bool showProgress = true );
+
+ /**
+ * Clears the forward and backward history.
+ */
+ void clearHistory();
+
+ /**
+ * When going up in the directory hierarchy, KDirOperator can highlight
+ * the directory that was just left.
+ *
+ * I.e. when you go from /home/gis/src to /home/gis, the item "src" will
+ * be made the current item.
+ *
+ * Default is off, because this behavior introduces bug #136630.
+ * Don't enable until this bug is fixed.
+ */
+ // ### KDE4: make virtual
+ void setEnableDirHighlighting( bool enable );
+
+ /**
+ * @returns whether the last directory will be made the current item
+ * when going up in the directory hierarchy.
+ *
+ * Default is false.
+ */
+ bool dirHighlighting() const;
+
+ /**
+ * @returns true if we are in directory-only mode, that is, no files are
+ * shown.
+ */
+ bool dirOnlyMode() const { return dirOnlyMode( myMode ); }
+
+ static bool dirOnlyMode( uint mode ) {
+ return ( (mode & KFile::Directory) &&
+ (mode & (KFile::File | KFile::Files)) == 0 );
+ }
+
+ /**
+ * Sets up the action menu.
+ * @param whichActions is an value of OR'd ActionTypes that controls which actions to show in the action menu
+ */
+ void setupMenu(int whichActions);
+
+ /**
+ * Reimplemented - allow dropping of files if @p b is true
+ * @param b true if the widget should allow dropping of files
+ */
+ virtual void setAcceptDrops(bool b);
+
+ /**
+ * Sets the options for dropping files.
+ * @see KFileView::DropOptions
+ * @since 3.2
+ */
+ // ### KDE4: make virtual
+ void setDropOptions(int options);
+
+ /**
+ * Starts and returns a KIO::CopyJob to trash the given @p items.
+ *
+ * @param items the list of items to be trashed
+ * @param parent the parent widget used for the confirmation dialog
+ * @param ask specifies whether a confirmation dialog should be shown
+ * @param showProgress passed to the CopyJob to show a progress dialog
+ * @since 3.4
+ */
+ // ### KDE4: make virtual
+ KIO::CopyJob * trash( const KFileItemList& items, QWidget *parent,
+ bool ask = true, bool showProgress = true );
+
+protected:
+ /**
+ * A view factory for creating predefined fileviews. Called internally by setView
+ * , but you can also call it directly. Reimplement this if you depend on self defined fileviews.
+ * @param parent is the QWidget to be set as parent
+ * @param view is the predefined view to be set, note: this can be several ones OR:ed together.
+ * @returns the created KFileView
+ * @see KFileView
+ * @see KCombiView
+ * @see KFileDetailView
+ * @see KFileIconView
+ * @see KFilePreview
+ * @see KFile::FileView
+ * @see setView
+ */
+ virtual KFileView* createView( QWidget* parent, KFile::FileView view );
+ /**
+ * Sets a custom KDirLister to list directories.
+ */
+ // ### KDE4: make virtual
+ void setDirLister( KDirLister *lister );
+
+ virtual void resizeEvent( QResizeEvent * );
+
+ /**
+ * Sets up all the actions. Called from the constructor, you usually
+ * better not call this.
+ */
+ void setupActions();
+
+ /**
+ * Updates the sorting-related actions to comply with the current sorting
+ * @see sorting
+ */
+ void updateSortActions();
+
+ /**
+ * Updates the view-related actions to comply with the current
+ * KFile::FileView
+ */
+ void updateViewActions();
+
+ /**
+ * Sets up the context-menu with all the necessary actions. Called from the
+ * constructor, you usually don't need to call this.
+ * @since 3.1
+ */
+ void setupMenu();
+
+ /**
+ * Synchronizes the completion objects with the entries of the
+ * currently listed url.
+ *
+ * Automatically called from makeCompletion() and
+ * makeDirCompletion()
+ */
+ void prepareCompletionObjects();
+
+ /**
+ * Checks if there support from KIO::PreviewJob for the currently
+ * shown files, taking mimeFilter() and nameFilter() into account
+ * Enables/disables the preview-action accordingly.
+ */
+ bool checkPreviewSupport();
+
+public slots:
+ /**
+ * Goes one step back in the history and opens that url.
+ */
+ // ### KDE4: make virtual
+ void back();
+
+ /**
+ * Goes one step forward in the history and opens that url.
+ */
+ // ### KDE4: make virtual
+ void forward();
+
+ /**
+ * Enters the home directory.
+ */
+ // ### KDE4: make virtual
+ void home();
+
+ /**
+ * Goes one directory up from the current url.
+ */
+ // ### KDE4: make virtual
+ void cdUp();
+
+ /**
+ * to update the view after changing the settings
+ */
+ void updateDir();
+
+ /**
+ * Re-reads the current url.
+ */
+ // ### KDE4: make virtual
+ void rereadDir();
+
+ /**
+ * Opens a dialog to create a new directory.
+ */
+ // ### KDE4: make virtual
+ void mkdir();
+
+ /**
+ * Deletes the currently selected files/directories.
+ */
+ // ### KDE4: make virtual
+ void deleteSelected();
+
+ /**
+ * Enables/disables actions that are selection dependent. Call this e.g.
+ * when you are about to show a popup menu using some of KDirOperators
+ * actions.
+ */
+ void updateSelectionDependentActions();
+
+ /**
+ * Tries to complete the given string (only completes files).
+ */
+ QString makeCompletion(const QString&);
+
+ /**
+ * Tries to complete the given string (only completes directores).
+ */
+ QString makeDirCompletion(const QString&);
+
+ /**
+ * Trashes the currently selected files/directories.
+ * @since 3.4
+ */
+ // ### KDE4: make virtual
+ void trashSelected(KAction::ActivationReason, Qt::ButtonState);
+
+protected slots:
+ /**
+ * Restores the normal cursor after showing the busy-cursor. Also hides
+ * the progressbar.
+ */
+ void resetCursor();
+
+ /**
+ * Called after setURL() to load the directory, update the history,
+ * etc.
+ */
+ void pathChanged();
+
+ /**
+ * Adds a new list of KFileItems to the view
+ * (coming from KDirLister)
+ */
+ void insertNewFiles(const KFileItemList &newone);
+
+ /**
+ * Removes the given KFileItem item from the view (usually called from
+ * KDirLister).
+ */
+ void itemDeleted(KFileItem *);
+
+ /**
+ * Enters the directory specified by the given @p item.
+ */
+ // ### KDE4: make virtual
+ void selectDir(const KFileItem *item );
+
+ /**
+ * Emits fileSelected( item )
+ */
+ void selectFile(const KFileItem *item);
+
+ /**
+ * Emits fileHighlighted( i )
+ */
+ void highlightFile(const KFileItem* i) { emit fileHighlighted( i ); }
+
+ /**
+ * Called upon right-click to activate the popupmenu.
+ */
+ virtual void activatedMenu( const KFileItem *, const QPoint& pos );
+
+ /**
+ * Changes sorting to sort by name
+ */
+ void sortByName() { byNameAction->setChecked( true ); }
+
+ /**
+ * Changes sorting to sort by size
+ */
+ void sortBySize() { bySizeAction->setChecked( true ); }
+
+ /**
+ * Changes sorting to sort by date
+ */
+ void sortByDate() { byDateAction->setChecked( true ); }
+
+ /**
+ * Changes sorting to reverse sorting
+ */
+ void sortReversed() { reverseAction->setChecked( !reverseAction->isChecked() ); }
+
+ /**
+ * Toggles showing directories first / having them sorted like files.
+ */
+ void toggleDirsFirst() { dirsFirstAction->setChecked( !dirsFirstAction->isChecked() ); }
+
+ /**
+ * Toggles case sensitive / case insensitive sorting
+ */
+ void toggleIgnoreCase() { caseInsensitiveAction->setChecked( !caseInsensitiveAction->isChecked() ); }
+
+ /**
+ * Tries to make the given @p match as current item in the view and emits
+ * completion( match )
+ */
+ void slotCompletionMatch(const QString& match);
+
+signals:
+ void urlEntered(const KURL& );
+ void updateInformation(int files, int dirs);
+ void completion(const QString&);
+ void finishedLoading();
+
+ /**
+ * Emitted whenever the current fileview is changed, either by an explicit
+ * call to setView() or by the user selecting a different view thru
+ * the GUI.
+ */
+ void viewChanged( KFileView * newView );
+
+ /**
+ * Emitted when a file is highlighted or generally the selection changes in
+ * multiselection mode. In the latter case, @p item is 0L. You can access
+ * the selected items with selectedItems().
+ */
+ void fileHighlighted( const KFileItem *item );
+ void dirActivated( const KFileItem *item );
+ void fileSelected( const KFileItem *item );
+ /**
+ * Emitted when files are dropped. Dropping files is disabled by
+ * default. You need to enable it with setAcceptDrops()
+ * @param item the item on which the drop occurred or 0.
+ * @param event the drop event itself.
+ * @param urls the urls that where dropped.
+ * @since 3.2
+ */
+ void dropped(const KFileItem *item, QDropEvent*event, const KURL::List&urls);
+private:
+ /**
+ * Contains all URLs you can reach with the back button.
+ */
+ QPtrStack<KURL> backStack;
+
+ /**
+ * Contains all URLs you can reach with the forward button.
+ */
+ QPtrStack<KURL> forwardStack;
+
+ KDirLister *dir;
+ KURL currUrl;
+
+ KCompletion myCompletion;
+ KCompletion myDirCompletion;
+ bool myCompleteListDirty;
+ QDir::SortSpec mySorting;
+
+ /**
+ * Checks whether we preview support is available for the current
+ * mimetype/namefilter
+ */
+ bool checkPreviewInternal() const;
+
+ /**
+ * takes action on the new location. If it's a directory, change
+ * into it, if it's a file, correct the name, etc.
+ */
+ void checkPath(const QString& txt, bool takeFiles = false);
+
+ void connectView(KFileView *);
+
+ bool openURL( const KURL& url, bool keep = false, bool reload = false );
+
+ KFileView *m_fileView;
+ KFileItemList pendingMimeTypes;
+
+ // the enum KFile::FileView as an int
+ int m_viewKind;
+ int defaultView;
+
+ KFile::Mode myMode;
+ KProgress *progress;
+
+ const QWidget *myPreview; // temporary pointer for the preview widget
+
+ // actions for the popupmenus
+ // ### clean up all those -- we have them all in the actionMenu!
+ KActionMenu *actionMenu;
+
+ KAction *backAction;
+ KAction *forwardAction;
+ KAction *homeAction;
+ KAction *upAction;
+ KAction *reloadAction;
+ KActionSeparator *actionSeparator;
+ KAction *mkdirAction;
+
+ KActionMenu *sortActionMenu;
+ KRadioAction *byNameAction;
+ KRadioAction *byDateAction;
+ KRadioAction *bySizeAction;
+ KToggleAction *reverseAction;
+ KToggleAction *dirsFirstAction;
+ KToggleAction *caseInsensitiveAction;
+
+ KActionMenu *viewActionMenu;
+ KRadioAction *shortAction;
+ KRadioAction *detailedAction;
+ KToggleAction *showHiddenAction;
+ KToggleAction *separateDirsAction;
+
+ KActionCollection *myActionCollection;
+ KActionCollection *viewActionCollection;
+
+private slots:
+ /**
+ * @internal
+ */
+ void slotDetailedView();
+ void slotSimpleView();
+ void slotToggleHidden( bool );
+
+ void slotSeparateDirs();
+ void slotDefaultPreview();
+ void togglePreview( bool );
+
+ void slotSortByName();
+ void slotSortBySize();
+ void slotSortByDate();
+ void slotSortReversed();
+ void slotToggleDirsFirst();
+ void slotToggleIgnoreCase();
+
+ void slotStarted();
+ void slotProgress( int );
+ void slotShowProgress();
+ void slotIOFinished();
+ void slotCanceled();
+ void slotRedirected( const KURL& );
+
+ void slotViewActionAdded( KAction * );
+ void slotViewActionRemoved( KAction * );
+ void slotViewSortingChanged( QDir::SortSpec );
+
+ void slotClearView();
+ void slotRefreshItems( const KFileItemList& items );
+
+ void slotProperties();
+
+ void insertViewDependentActions();
+
+private:
+ static bool isReadable( const KURL& url );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KDirOperatorPrivate;
+ KDirOperatorPrivate *d;
+};
+
+#endif
diff --git a/kio/kfile/kdirselectdialog.cpp b/kio/kfile/kdirselectdialog.cpp
new file mode 100644
index 000000000..b8ea409e9
--- /dev/null
+++ b/kio/kfile/kdirselectdialog.cpp
@@ -0,0 +1,481 @@
+/*
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ Copyright (C) 2001 Michael Jarrett <michaelj@corel.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdir.h>
+#include <qlayout.h>
+#include <qpopupmenu.h>
+#include <qstringlist.h>
+#include <qvaluestack.h>
+
+#include <kactionclasses.h>
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kfiledialog.h>
+#include <kfilespeedbar.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+#include <krecentdirs.h>
+#include <kshell.h>
+#include <kurl.h>
+#include <kurlcompletion.h>
+#include <kurlpixmapprovider.h>
+#include <kinputdialog.h>
+#include <kio/netaccess.h>
+#include <kio/renamedlg.h>
+#include <kmessagebox.h>
+
+#include "kfiletreeview.h"
+#include "kdirselectdialog.h"
+
+// ### add mutator for treeview!
+
+class KDirSelectDialog::KDirSelectDialogPrivate
+{
+public:
+ KDirSelectDialogPrivate()
+ {
+ urlCombo = 0L;
+ branch = 0L;
+ comboLocked = false;
+ }
+
+ KFileSpeedBar *speedBar;
+ KHistoryCombo *urlCombo;
+ KFileTreeBranch *branch;
+ QString recentDirClass;
+ KURL startURL;
+ QValueStack<KURL> dirsToList;
+
+ bool comboLocked : 1;
+};
+
+static KURL rootUrl(const KURL &url)
+{
+ KURL root = url;
+ root.setPath( "/" );
+
+ if (!kapp->authorizeURLAction("list", KURL(), root))
+ {
+ root = KURL::fromPathOrURL( QDir::homeDirPath() );
+ if (!kapp->authorizeURLAction("list", KURL(), root))
+ {
+ root = url;
+ }
+ }
+ return root;
+}
+
+KDirSelectDialog::KDirSelectDialog(const QString &startDir, bool localOnly,
+ QWidget *parent, const char *name,
+ bool modal)
+ : KDialogBase( parent, name, modal, i18n("Select Folder"),
+ Ok|Cancel|User1, Ok, false,
+ KGuiItem( i18n("New Folder..."), "folder_new" ) ),
+ m_localOnly( localOnly )
+{
+ d = new KDirSelectDialogPrivate;
+ d->branch = 0L;
+
+ QFrame *page = makeMainWidget();
+ QHBoxLayout *hlay = new QHBoxLayout( page, 0, spacingHint() );
+ m_mainLayout = new QVBoxLayout();
+ d->speedBar = new KFileSpeedBar( page, "speedbar" );
+ connect( d->speedBar, SIGNAL( activated( const KURL& )),
+ SLOT( setCurrentURL( const KURL& )) );
+ hlay->addWidget( d->speedBar, 0 );
+ hlay->addLayout( m_mainLayout, 1 );
+
+ // Create dir list
+ m_treeView = new KFileTreeView( page );
+ m_treeView->addColumn( i18n("Folders") );
+ m_treeView->setColumnWidthMode( 0, QListView::Maximum );
+ m_treeView->setResizeMode( QListView::AllColumns );
+
+ d->urlCombo = new KHistoryCombo( page, "url combo" );
+ d->urlCombo->setTrapReturnKey( true );
+ d->urlCombo->setPixmapProvider( new KURLPixmapProvider() );
+ KURLCompletion *comp = new KURLCompletion();
+ comp->setMode( KURLCompletion::DirCompletion );
+ d->urlCombo->setCompletionObject( comp, true );
+ d->urlCombo->setAutoDeleteCompletionObject( true );
+ d->urlCombo->setDuplicatesEnabled( false );
+ connect( d->urlCombo, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotComboTextChanged( const QString& ) ));
+
+ m_contextMenu = new QPopupMenu( this );
+ KAction* newFolder = new KAction( i18n("New Folder..."), "folder_new", 0, this, SLOT( slotMkdir() ), this);
+ newFolder->plug(m_contextMenu);
+ m_contextMenu->insertSeparator();
+ m_showHiddenFolders = new KToggleAction ( i18n( "Show Hidden Folders" ), 0, this,
+ SLOT( slotShowHiddenFoldersToggled() ), this);
+ m_showHiddenFolders->plug(m_contextMenu);
+
+ d->startURL = KFileDialog::getStartURL( startDir, d->recentDirClass );
+ if ( localOnly && !d->startURL.isLocalFile() )
+ {
+ d->startURL = KURL();
+ QString docPath = KGlobalSettings::documentPath();
+ if (QDir(docPath).exists())
+ d->startURL.setPath( docPath );
+ else
+ d->startURL.setPath( QDir::homeDirPath() );
+ }
+
+ KURL root = rootUrl(d->startURL);
+
+ m_startDir = d->startURL.url();
+
+ d->branch = createBranch( root );
+
+ readConfig( KGlobal::config(), "DirSelect Dialog" );
+
+ m_mainLayout->addWidget( m_treeView, 1 );
+ m_mainLayout->addWidget( d->urlCombo, 0 );
+
+ connect( m_treeView, SIGNAL( currentChanged( QListViewItem * )),
+ SLOT( slotCurrentChanged() ));
+ connect( m_treeView, SIGNAL( contextMenu( KListView *, QListViewItem *, const QPoint & )),
+ SLOT( slotContextMenu( KListView *, QListViewItem *, const QPoint & )));
+
+ connect( d->urlCombo, SIGNAL( activated( const QString& )),
+ SLOT( slotURLActivated( const QString& )));
+ connect( d->urlCombo, SIGNAL( returnPressed( const QString& )),
+ SLOT( slotURLActivated( const QString& )));
+
+ setCurrentURL( d->startURL );
+}
+
+
+KDirSelectDialog::~KDirSelectDialog()
+{
+ delete d;
+}
+
+void KDirSelectDialog::setCurrentURL( const KURL& url )
+{
+ if ( !url.isValid() )
+ return;
+
+ KURL root = rootUrl(url);
+
+ d->startURL = url;
+ if ( !d->branch ||
+ url.protocol() != d->branch->url().protocol() ||
+ url.host() != d->branch->url().host() )
+ {
+ if ( d->branch )
+ {
+ // removing the root-item causes the currentChanged() signal to be
+ // emitted, but we don't want to update the location-combo yet.
+ d->comboLocked = true;
+ view()->removeBranch( d->branch );
+ d->comboLocked = false;
+ }
+
+ d->branch = createBranch( root );
+ }
+
+ d->branch->disconnect( SIGNAL( populateFinished( KFileTreeViewItem * )),
+ this, SLOT( slotNextDirToList( KFileTreeViewItem *)));
+ connect( d->branch, SIGNAL( populateFinished( KFileTreeViewItem * )),
+ SLOT( slotNextDirToList( KFileTreeViewItem * ) ));
+
+ KURL dirToList = root;
+ d->dirsToList.clear();
+ QString path = url.path(+1);
+ int pos = path.length();
+
+ if ( path.isEmpty() ) // e.g. ftp://host.com/ -> just list the root dir
+ d->dirsToList.push( root );
+
+ else
+ {
+ while ( pos > 0 )
+ {
+ pos = path.findRev( '/', pos -1 );
+ if ( pos >= 0 )
+ {
+ dirToList.setPath( path.left( pos +1 ) );
+ d->dirsToList.push( dirToList );
+// qDebug( "List: %s", dirToList.url().latin1());
+ }
+ }
+ }
+
+ if ( !d->dirsToList.isEmpty() )
+ openNextDir( d->branch->root() );
+}
+
+void KDirSelectDialog::openNextDir( KFileTreeViewItem * /*parent*/ )
+{
+ if ( !d->branch )
+ return;
+
+ KURL url = d->dirsToList.pop();
+
+ KFileTreeViewItem *item = view()->findItem( d->branch, url.path().mid(1));
+ if ( item )
+ {
+ if ( !item->isOpen() )
+ item->setOpen( true );
+ else // already open -> go to next one
+ slotNextDirToList( item );
+ }
+// else
+// qDebug("###### openNextDir: item not found!");
+}
+
+void KDirSelectDialog::slotNextDirToList( KFileTreeViewItem *item )
+{
+ // scroll to make item the topmost item
+ view()->ensureItemVisible( item );
+ QRect r = view()->itemRect( item );
+ if ( r.isValid() )
+ {
+ int x, y;
+ view()->viewportToContents( view()->contentsX(), r.y(), x, y );
+ view()->setContentsPos( x, y );
+ }
+
+ if ( !d->dirsToList.isEmpty() )
+ openNextDir( item );
+ else
+ {
+ d->branch->disconnect( SIGNAL( populateFinished( KFileTreeViewItem * )),
+ this, SLOT( slotNextDirToList( KFileTreeViewItem *)));
+ view()->setCurrentItem( item );
+ item->setSelected( true );
+ }
+}
+
+void KDirSelectDialog::readConfig( KConfig *config, const QString& group )
+{
+ d->urlCombo->clear();
+
+ KConfigGroup conf( config, group );
+ d->urlCombo->setHistoryItems( conf.readPathListEntry( "History Items" ));
+
+ QSize defaultSize( 400, 450 );
+ resize( conf.readSizeEntry( "DirSelectDialog Size", &defaultSize ));
+}
+
+void KDirSelectDialog::saveConfig( KConfig *config, const QString& group )
+{
+ KConfigGroup conf( config, group );
+ conf.writePathEntry( "History Items", d->urlCombo->historyItems(), ',',
+ true, true);
+ conf.writeEntry( "DirSelectDialog Size", size(), true, true );
+
+ d->speedBar->save( config );
+
+ config->sync();
+}
+
+void KDirSelectDialog::slotUser1()
+{
+ slotMkdir();
+}
+
+void KDirSelectDialog::accept()
+{
+ KFileTreeViewItem *item = m_treeView->currentKFileTreeViewItem();
+ if ( !item )
+ return;
+
+ if ( !d->recentDirClass.isEmpty() )
+ {
+ KURL dir = item->url();
+ if ( !item->isDir() )
+ dir = dir.upURL();
+
+ KRecentDirs::add(d->recentDirClass, dir.url());
+ }
+
+ d->urlCombo->addToHistory( item->url().prettyURL() );
+ KFileDialog::setStartDir( url() );
+
+ KDialogBase::accept();
+ saveConfig( KGlobal::config(), "DirSelect Dialog" );
+}
+
+
+KURL KDirSelectDialog::url() const
+{
+ return m_treeView->currentURL();
+}
+
+void KDirSelectDialog::slotCurrentChanged()
+{
+ if ( d->comboLocked )
+ return;
+
+ KFileTreeViewItem *current = view()->currentKFileTreeViewItem();
+ KURL u = current ? current->url() : (d->branch ? d->branch->rootUrl() : KURL());
+
+ if ( u.isValid() )
+ {
+ if ( u.isLocalFile() )
+ d->urlCombo->setEditText( u.path() );
+
+ else // remote url
+ d->urlCombo->setEditText( u.prettyURL() );
+ }
+ else
+ d->urlCombo->setEditText( QString::null );
+}
+
+void KDirSelectDialog::slotURLActivated( const QString& text )
+{
+ if ( text.isEmpty() )
+ return;
+
+ KURL url = KURL::fromPathOrURL( text );
+ d->urlCombo->addToHistory( url.prettyURL() );
+
+ if ( localOnly() && !url.isLocalFile() )
+ return; // ### messagebox
+
+ KURL oldURL = m_treeView->currentURL();
+ if ( oldURL.isEmpty() )
+ oldURL = KURL::fromPathOrURL( m_startDir );
+
+ setCurrentURL( url );
+}
+
+KFileTreeBranch * KDirSelectDialog::createBranch( const KURL& url )
+{
+ QString title = url.isLocalFile() ? url.path() : url.prettyURL();
+ KFileTreeBranch *branch = view()->addBranch( url, title, m_showHiddenFolders->isChecked() );
+ branch->setChildRecurse( false );
+ view()->setDirOnlyMode( branch, true );
+
+ return branch;
+}
+
+void KDirSelectDialog::slotComboTextChanged( const QString& text )
+{
+ if ( d->branch )
+ {
+ KURL url = KURL::fromPathOrURL( KShell::tildeExpand( text ) );
+ KFileTreeViewItem *item = d->branch->findTVIByURL( url );
+ if ( item )
+ {
+ view()->setCurrentItem( item );
+ view()->setSelected( item, true );
+ view()->ensureItemVisible( item );
+ return;
+ }
+ }
+
+ QListViewItem *item = view()->currentItem();
+ if ( item )
+ {
+ item->setSelected( false );
+ // 2002/12/27, deselected item is not repainted, so force it
+ item->repaint();
+ }
+}
+
+void KDirSelectDialog::slotContextMenu( KListView *, QListViewItem *, const QPoint& pos )
+{
+ m_contextMenu->popup( pos );
+}
+
+void KDirSelectDialog::slotMkdir()
+{
+ bool ok;
+ QString where = url().pathOrURL();
+ QString name = i18n( "New Folder" );
+ if ( url().isLocalFile() && QFileInfo( url().path(+1) + name ).exists() )
+ name = KIO::RenameDlg::suggestName( url(), name );
+
+ QString directory = KIO::encodeFileName( KInputDialog::getText( i18n( "New Folder" ),
+ i18n( "Create new folder in:\n%1" ).arg( where ),
+ name, &ok, this));
+ if (!ok)
+ return;
+
+ bool selectDirectory = true;
+ bool writeOk = false;
+ bool exists = false;
+ KURL folderurl( url() );
+
+ QStringList dirs = QStringList::split( QDir::separator(), directory );
+ QStringList::ConstIterator it = dirs.begin();
+
+ for ( ; it != dirs.end(); ++it )
+ {
+ folderurl.addPath( *it );
+ exists = KIO::NetAccess::exists( folderurl, false, 0 );
+ writeOk = !exists && KIO::NetAccess::mkdir( folderurl, topLevelWidget() );
+ }
+
+ if ( exists ) // url was already existant
+ {
+ QString which = folderurl.isLocalFile() ? folderurl.path() : folderurl.prettyURL();
+ KMessageBox::sorry(this, i18n("A file or folder named %1 already exists.").arg(which));
+ selectDirectory = false;
+ }
+ else if ( !writeOk ) {
+ KMessageBox::sorry(this, i18n("You do not have permission to create that folder." ));
+ }
+ else if ( selectDirectory ) {
+ setCurrentURL( folderurl );
+ }
+}
+
+void KDirSelectDialog::slotShowHiddenFoldersToggled()
+{
+ KURL currentURL = url();
+
+ d->comboLocked = true;
+ view()->removeBranch( d->branch );
+ d->comboLocked = false;
+
+ KURL root = rootUrl(d->startURL);
+ d->branch = createBranch( root );
+
+ setCurrentURL( currentURL );
+}
+
+// static
+KURL KDirSelectDialog::selectDirectory( const QString& startDir,
+ bool localOnly,
+ QWidget *parent,
+ const QString& caption)
+{
+ KDirSelectDialog myDialog( startDir, localOnly, parent,
+ "kdirselect dialog", true );
+
+ if ( !caption.isNull() )
+ myDialog.setCaption( caption );
+
+ if ( myDialog.exec() == QDialog::Accepted )
+ return KIO::NetAccess::mostLocalURL(myDialog.url(),parent);
+ else
+ return KURL();
+}
+
+void KDirSelectDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+#include "kdirselectdialog.moc"
diff --git a/kio/kfile/kdirselectdialog.h b/kio/kfile/kdirselectdialog.h
new file mode 100644
index 000000000..7f2bb13c5
--- /dev/null
+++ b/kio/kfile/kdirselectdialog.h
@@ -0,0 +1,131 @@
+/*
+ Copyright (C) 2001 Michael Jarrett <michaelj@corel.com>
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KDIRSELECTDIALOG_H
+#define KDIRSELECTDIALOG_H
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+class QPopupMenu;
+class QVBoxLayout;
+class KConfig;
+class KFileTreeBranch;
+class KFileTreeView;
+class KFileTreeViewItem;
+class KToggleAction;
+
+/**
+ * A pretty dialog for a KDirSelect control for selecting directories.
+ * @author Michael Jarrett <michaelj@corel.com>
+ * @see KFileDialog
+ */
+class KIO_EXPORT KDirSelectDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * The constructor. Creates a dialog to select a directory (url).
+ * @internal use the static selectDirectory function
+ * @param startDir the directory, initially shown
+ * @param localOnly unused. You can only select paths below the startDir
+ * @param parent the parent for the dialog, usually 0L
+ * @param name the QObject::name
+ * @param modal if the dialog is modal or not
+ */
+ KDirSelectDialog(const QString& startDir = QString::null,
+ bool localOnly = false,
+ QWidget *parent = 0L,
+ const char *name = 0, bool modal = false);
+
+ /**
+ */
+ ~KDirSelectDialog();
+
+ /**
+ * Returns the currently-selected URL, or a blank URL if none is selected.
+ * @return The currently-selected URL, if one was selected.
+ */
+ KURL url() const;
+
+ KFileTreeView * view() const { return m_treeView; }
+
+ bool localOnly() const { return m_localOnly; }
+
+ /**
+ * Creates a KDirSelectDialog, and returns the result.
+ * @param startDir the directory, initially shown
+ * The tree will display this directory and subdirectories of it.
+ * @param localOnly unused. You can only select paths below the startDir
+ * @param parent the parent widget to use for the dialog, or NULL to create a parent-less dialog
+ * @param caption the caption to use for the dialog, or QString::null for the default caption
+ * @return The URL selected, or an empty URL if the user canceled
+ * or no URL was selected.
+ */
+ static KURL selectDirectory( const QString& startDir = QString::null,
+ bool localOnly = false, QWidget *parent = 0L,
+ const QString& caption = QString::null);
+
+ /**
+ * @return The path for the root node
+ */
+ QString startDir() const { return m_startDir; }
+
+public slots:
+ void setCurrentURL( const KURL& url );
+
+protected slots:
+ virtual void slotUser1();
+
+protected:
+ virtual void accept();
+
+ // Layouts protected so that subclassing is easy
+ QVBoxLayout *m_mainLayout;
+ QString m_startDir;
+
+private slots:
+ void slotCurrentChanged();
+ void slotURLActivated( const QString& );
+ void slotNextDirToList( KFileTreeViewItem *dirItem );
+ void slotComboTextChanged( const QString& text );
+ void slotContextMenu( KListView *, QListViewItem *, const QPoint & );
+ void slotShowHiddenFoldersToggled();
+ void slotMkdir();
+
+private:
+ void readConfig( KConfig *config, const QString& group );
+ void saveConfig( KConfig *config, const QString& group );
+ void openNextDir( KFileTreeViewItem *parent );
+ KFileTreeBranch * createBranch( const KURL& url );
+
+ KFileTreeView *m_treeView;
+ QPopupMenu *m_contextMenu;
+ KToggleAction *m_showHiddenFolders;
+ bool m_localOnly;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KDirSelectDialogPrivate;
+ KDirSelectDialogPrivate *d;
+};
+
+#endif
diff --git a/kio/kfile/kdirsize.cpp b/kio/kfile/kdirsize.cpp
new file mode 100644
index 000000000..cebe42cbc
--- /dev/null
+++ b/kio/kfile/kdirsize.cpp
@@ -0,0 +1,166 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kdirsize.h"
+#include <kdebug.h>
+#include <kglobal.h>
+#include <qapplication.h>
+#include <qtimer.h>
+#include <config-kfile.h>
+
+using namespace KIO;
+
+KDirSize::KDirSize( const KURL & directory )
+ : KIO::Job(false /*No GUI*/), m_bAsync(true), m_totalSize(0L), m_totalFiles(0L), m_totalSubdirs(0L)
+{
+ startNextJob( directory );
+}
+
+KDirSize::KDirSize( const KFileItemList & lstItems )
+ : KIO::Job(false /*No GUI*/), m_bAsync(true), m_totalSize(0L), m_totalFiles(0L), m_totalSubdirs(0L), m_lstItems(lstItems)
+{
+ QTimer::singleShot( 0, this, SLOT(processList()) );
+}
+
+void KDirSize::processList()
+{
+ while (!m_lstItems.isEmpty())
+ {
+ KFileItem * item = m_lstItems.first();
+ m_lstItems.removeFirst();
+ if ( !item->isLink() )
+ {
+ if ( item->isDir() )
+ {
+ kdDebug(kfile_area) << "KDirSize::processList dir -> listing" << endl;
+ KURL url = item->url();
+ startNextJob( url );
+ return; // we'll come back later, when this one's finished
+ }
+ else
+ {
+ m_totalSize += item->size();
+// no long long with kdDebug()
+// kdDebug(kfile_area) << "KDirSize::processList file -> " << m_totalSize << endl;
+ }
+ }
+ }
+ kdDebug(kfile_area) << "KDirSize::processList finished" << endl;
+ if ( !m_bAsync )
+ qApp->exit_loop();
+ emitResult();
+}
+
+void KDirSize::startNextJob( const KURL & url )
+{
+ KIO::ListJob * listJob = KIO::listRecursive( url, false /* no GUI */ );
+ connect( listJob, SIGNAL(entries( KIO::Job *,
+ const KIO::UDSEntryList& )),
+ SLOT( slotEntries( KIO::Job*,
+ const KIO::UDSEntryList& )));
+ addSubjob( listJob );
+}
+
+void KDirSize::slotEntries( KIO::Job*, const KIO::UDSEntryList & list )
+{
+ static const QString& dot = KGlobal::staticQString( "." );
+ static const QString& dotdot = KGlobal::staticQString( ".." );
+ KIO::UDSEntryListConstIterator it = list.begin();
+ KIO::UDSEntryListConstIterator end = list.end();
+ for (; it != end; ++it) {
+ KIO::UDSEntry::ConstIterator it2 = (*it).begin();
+ KIO::filesize_t size = 0;
+ bool isLink = false;
+ bool isDir = false;
+ QString name;
+ for( ; it2 != (*it).end(); it2++ ) {
+ switch( (*it2).m_uds ) {
+ case KIO::UDS_NAME:
+ name = (*it2).m_str;
+ break;
+ case KIO::UDS_LINK_DEST:
+ isLink = !(*it2).m_str.isEmpty();
+ break;
+ case KIO::UDS_SIZE:
+ size = ((*it2).m_long);
+ break;
+ case KIO::UDS_FILE_TYPE:
+ isDir = S_ISDIR((*it2).m_long);
+ break;
+ default:
+ break;
+ }
+ }
+ if ( name == dot )
+ m_totalSize += size;
+ else if ( name != dotdot )
+ {
+ if (!isLink)
+ m_totalSize += size;
+ if (!isDir)
+ m_totalFiles++;
+ else
+ m_totalSubdirs++;
+ //kdDebug(kfile_area) << name << ":" << size << endl;
+ }
+ }
+}
+
+//static
+KDirSize * KDirSize::dirSizeJob( const KURL & directory )
+{
+ return new KDirSize( directory ); // useless - but consistent with other jobs
+}
+
+//static
+KDirSize * KDirSize::dirSizeJob( const KFileItemList & lstItems )
+{
+ return new KDirSize( lstItems );
+}
+
+//static
+KIO::filesize_t KDirSize::dirSize( const KURL & directory )
+{
+ KDirSize * dirSize = dirSizeJob( directory );
+ dirSize->setSync();
+ qApp->enter_loop();
+ return dirSize->totalSize();
+}
+
+
+void KDirSize::slotResult( KIO::Job * job )
+{
+ kdDebug(kfile_area) << " KDirSize::slotResult( KIO::Job * job ) m_lstItems:" << m_lstItems.count() << endl;
+ if ( !m_lstItems.isEmpty() )
+ {
+ subjobs.remove(job); // Remove job, but don't kill this job.
+ processList();
+ }
+ else
+ {
+ if ( !m_bAsync )
+ qApp->exit_loop();
+ KIO::Job::slotResult( job );
+ }
+}
+
+void KDirSize::virtual_hook( int id, void* data )
+{ KIO::Job::virtual_hook( id, data ); }
+
+#include "kdirsize.moc"
diff --git a/kio/kfile/kdirsize.h b/kio/kfile/kdirsize.h
new file mode 100644
index 000000000..64ae80765
--- /dev/null
+++ b/kio/kfile/kdirsize.h
@@ -0,0 +1,106 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KDIRSIZE_H
+#define __KDIRSIZE_H
+
+#include <kio/job.h>
+#include <kfileitem.h>
+
+/**
+ * Computes a directory size (similar to "du", but doesn't give the same results
+ * since we simply sum up the dir and file sizes, whereas du speaks disk blocks)
+ */
+class KIO_EXPORT KDirSize : public KIO::Job
+{
+ Q_OBJECT
+protected:
+ KDirSize( const KURL & directory );
+ KDirSize( const KFileItemList & lstItems );
+ ~KDirSize() {}
+
+public:
+ /**
+ * @return the size we found
+ */
+ KIO::filesize_t totalSize() const { return m_totalSize; }
+
+ /**
+ * @return the total number of files (counting symlinks to files, sockets
+ * and character devices as files) in this directory and all sub-directories
+ * @since 3.3
+ */
+ KIO::filesize_t totalFiles() const { return m_totalFiles; }
+
+ /**
+ * @return the total number of sub-directories found (not including the
+ * directory the search started from and treating symlinks to directories
+ * as directories)
+ * @since 3.3
+ */
+ KIO::filesize_t totalSubdirs() const { return m_totalSubdirs; }
+
+ /**
+ * Asynchronous method. Connect to the result signal.
+ * This one lists a single directory.
+ */
+ static KDirSize * dirSizeJob( const KURL & directory );
+
+ /**
+ * Asynchronous method. Connect to the result signal.
+ * This one lists the items from @p lstItems.
+ * The reason we asks for items instead of just urls, is so that
+ * we directly know if the item is a file or a directory,
+ * and in case of a file, we already have its size.
+ */
+ static KDirSize * dirSizeJob( const KFileItemList & lstItems );
+
+ /**
+ * Synchronous method - you get the result as soon as
+ * the call returns.
+ */
+ static KIO::filesize_t dirSize( const KURL & directory );
+
+protected:
+ /**
+ * @internal
+ */
+ void setSync() { m_bAsync = false; }
+
+ void startNextJob( const KURL & url );
+
+protected slots:
+
+ virtual void slotResult( KIO::Job *job );
+ void slotEntries( KIO::Job * , const KIO::UDSEntryList &);
+ void processList();
+
+private:
+ bool m_bAsync;
+ KIO::filesize_t m_totalSize;
+ KIO::filesize_t m_totalFiles;
+ KIO::filesize_t m_totalSubdirs;
+ KFileItemList m_lstItems;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KDirSize* d;
+};
+
+#endif
diff --git a/kio/kfile/kdiskfreesp.cpp b/kio/kfile/kdiskfreesp.cpp
new file mode 100644
index 000000000..f748b2a66
--- /dev/null
+++ b/kio/kfile/kdiskfreesp.cpp
@@ -0,0 +1,169 @@
+/*
+ * kdiskfreesp.cpp
+ *
+ * Copyright (c) 1999 Michael Kropfberger <michael.kropfberger@gmx.net>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kdiskfreesp.h"
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <kdebug.h>
+#include <kprocess.h>
+#include <kio/global.h>
+#include <config-kfile.h>
+
+#include "kdiskfreesp.moc"
+
+#define DF_COMMAND "df"
+#define DF_ARGS "-k"
+#define NO_FS_TYPE true
+
+#define BLANK ' '
+#define FULL_PERCENT 95.0
+
+/***************************************************************************
+ * constructor
+**/
+KDiskFreeSp::KDiskFreeSp(QObject *parent, const char *name)
+ : QObject(parent,name)
+{
+ dfProc = new KProcess(); Q_CHECK_PTR(dfProc);
+ dfProc->setEnvironment("LANGUAGE", "C");
+ connect( dfProc, SIGNAL(receivedStdout(KProcess *, char *, int) ),
+ this, SLOT (receivedDFStdErrOut(KProcess *, char *, int)) );
+ connect(dfProc,SIGNAL(processExited(KProcess *) ),
+ this, SLOT(dfDone() ) );
+
+ readingDFStdErrOut=false;
+}
+
+
+/***************************************************************************
+ * destructor
+**/
+KDiskFreeSp::~KDiskFreeSp()
+{
+ delete dfProc;
+}
+
+/***************************************************************************
+ * is called, when the df-command writes on StdOut
+**/
+void KDiskFreeSp::receivedDFStdErrOut(KProcess *, char *data, int len)
+{
+ QCString tmp(data,len+1); // adds a zero-byte
+ dfStringErrOut.append(tmp);
+}
+
+/***************************************************************************
+ * reads the df-commands results
+**/
+int KDiskFreeSp::readDF( const QString & mountPoint )
+{
+ if (readingDFStdErrOut || dfProc->isRunning())
+ return -1;
+ m_mountPoint = mountPoint;
+ dfStringErrOut=""; // yet no data received
+ dfProc->clearArguments();
+ (*dfProc) << QString::fromLocal8Bit(DF_COMMAND) << QString::fromLocal8Bit(DF_ARGS);
+ if (!dfProc->start( KProcess::NotifyOnExit, KProcess::AllOutput ))
+ kdError() << "could not execute ["<< DF_COMMAND << "]" << endl;
+ return 1;
+}
+
+
+/***************************************************************************
+ * is called, when the df-command has finished
+**/
+void KDiskFreeSp::dfDone()
+{
+ readingDFStdErrOut=true;
+
+ QTextStream t (dfStringErrOut, IO_ReadOnly);
+ QString s=t.readLine();
+ if ( (s.isEmpty()) || ( s.left(10) != QString::fromLatin1("Filesystem") ) )
+ kdError() << "Error running df command... got [" << s << "]" << endl;
+ while ( !t.eof() ) {
+ QString u,v;
+ s=t.readLine();
+ s=s.simplifyWhiteSpace();
+ if ( !s.isEmpty() ) {
+ //kdDebug(kfile_area) << "GOT: [" << s << "]" << endl;
+
+ if (s.find(BLANK)<0) // devicename was too long, rest in next line
+ if ( !t.eof() ) { // just appends the next line
+ v=t.readLine();
+ s=s.append(v);
+ s=s.simplifyWhiteSpace();
+ //kdDebug(kfile_area) << "SPECIAL GOT: [" << s << "]" << endl;
+ }//if silly linefeed
+
+ //kdDebug(kfile_area) << "[" << s << "]" << endl;
+
+ //QString deviceName = s.left(s.find(BLANK));
+ s=s.remove(0,s.find(BLANK)+1 );
+ //kdDebug(kfile_area) << " DeviceName: [" << deviceName << "]" << endl;
+
+ if (!NO_FS_TYPE)
+ s=s.remove(0,s.find(BLANK)+1 ); // eat fs type
+
+ u=s.left(s.find(BLANK));
+ unsigned long kBSize = u.toULong();
+ s=s.remove(0,s.find(BLANK)+1 );
+ //kdDebug(kfile_area) << " Size: [" << kBSize << "]" << endl;
+
+ u=s.left(s.find(BLANK));
+ unsigned long kBUsed = u.toULong();
+ s=s.remove(0,s.find(BLANK)+1 );
+ //kdDebug(kfile_area) << " Used: [" << kBUsed << "]" << endl;
+
+ u=s.left(s.find(BLANK));
+ unsigned long kBAvail = u.toULong();
+ s=s.remove(0,s.find(BLANK)+1 );
+ //kdDebug(kfile_area) << " Avail: [" << kBAvail << "]" << endl;
+
+
+ s=s.remove(0,s.find(BLANK)+1 ); // delete the capacity 94%
+ QString mountPoint = s.stripWhiteSpace();
+ //kdDebug(kfile_area) << " MountPoint: [" << mountPoint << "]" << endl;
+
+ if ( mountPoint == m_mountPoint )
+ {
+ //kdDebug(kfile_area) << "Found mount point. Emitting" << endl;
+ emit foundMountPoint( mountPoint, kBSize, kBUsed, kBAvail );
+ emit foundMountPoint( kBSize, kBUsed, kBAvail, mountPoint ); // sic!
+ }
+ }//if not header
+ }//while further lines available
+
+ readingDFStdErrOut=false;
+ emit done();
+ delete this;
+}
+
+KDiskFreeSp * KDiskFreeSp::findUsageInfo( const QString & path )
+{
+ KDiskFreeSp * job = new KDiskFreeSp;
+ QString mountPoint = KIO::findPathMountPoint( path );
+ job->readDF( mountPoint );
+ return job;
+}
diff --git a/kio/kfile/kdiskfreesp.h b/kio/kfile/kdiskfreesp.h
new file mode 100644
index 000000000..53b83ba40
--- /dev/null
+++ b/kio/kfile/kdiskfreesp.h
@@ -0,0 +1,89 @@
+/*
+ * kdiskfreesp.h
+ *
+ * Copyright (c) 1999 Michael Kropfberger <michael.kropfberger@gmx.net>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __KDISKFREESP_H__
+#define __KDISKFREESP_H__
+
+#include <qobject.h>
+#include <qstring.h>
+
+#include <kdelibs_export.h>
+
+class KProcess;
+
+/**
+ * This class parses the output of "df" to find the disk usage
+ * information for a given partition (mount point).
+ */
+class KIO_EXPORT KDiskFreeSp : public QObject
+{ Q_OBJECT
+public:
+ KDiskFreeSp( QObject *parent=0, const char *name=0 );
+ /**
+ * Destructor - this object autodeletes itself when it's done
+ */
+ ~KDiskFreeSp();
+ /**
+ * Call this to fire a search on the disk usage information
+ * for @p mountPoint. foundMountPoint will be emitted
+ * if this mount point is found, with the info requested.
+ * done is emitted in any case.
+ */
+ int readDF( const QString & mountPoint );
+
+ /**
+ * Call this to fire a search on the disk usage information
+ * for the mount point containing @p path.
+ * foundMountPoint will be emitted
+ * if this mount point is found, with the info requested.
+ * done is emitted in any case.
+ */
+ static KDiskFreeSp * findUsageInfo( const QString & path );
+
+signals:
+ void foundMountPoint( const QString & mountPoint, unsigned long kBSize, unsigned long kBUsed, unsigned long kBAvail );
+
+ // This one is a hack around a weird (compiler?) bug. In the former signal,
+ // the slot in KPropsDlg would get 0L, 0L as the last two parameters.
+ // When using const ulong& instead, all is ok.
+ void foundMountPoint( const unsigned long&, const unsigned long&, const unsigned long&, const QString& );
+ void done();
+
+private slots:
+ void receivedDFStdErrOut(KProcess *, char *data, int len);
+ void dfDone();
+
+private:
+ KProcess *dfProc;
+ QCString dfStringErrOut;
+ QString m_mountPoint;
+ bool readingDFStdErrOut;
+ class KDiskFreeSpPrivate;
+ KDiskFreeSpPrivate * d;
+};
+/***************************************************************************/
+
+
+#endif
diff --git a/kio/kfile/kencodingfiledialog.cpp b/kio/kfile/kencodingfiledialog.cpp
new file mode 100644
index 000000000..63ce8a5dc
--- /dev/null
+++ b/kio/kfile/kencodingfiledialog.cpp
@@ -0,0 +1,223 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
+ 2003 Andras Mantia <amantia@freemail.hu>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config-kfile.h"
+
+#include "kencodingfiledialog.h"
+#include <kcombobox.h>
+#include <ktoolbar.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kcharsets.h>
+#include <qtextcodec.h>
+#include <kdiroperator.h>
+#include <krecentdocument.h>
+
+struct KEncodingFileDialogPrivate
+{
+ KComboBox *encoding;
+};
+
+KEncodingFileDialog::KEncodingFileDialog(const QString& startDir, const QString& encoding , const QString& filter,
+ const QString& caption, KFileDialog::OperationMode type, QWidget *parent, const char* name, bool modal)
+ : KFileDialog(startDir,filter,parent,name,modal), d(new KEncodingFileDialogPrivate)
+{
+ setCaption(caption);
+
+ setOperationMode( type );
+
+ KToolBar *tb = toolBar();
+ tb->insertSeparator();
+ int index = tb->insertCombo(QStringList(), -1 /*id*/, false /*writable*/, 0 /*signal*/, 0 /*receiver*/, 0 /*slot*/ );
+ d->encoding = tb->getCombo( tb->idAt( index ) );
+ if ( !d->encoding )
+ return;
+
+ d->encoding->clear ();
+ QString sEncoding = encoding;
+ if (sEncoding.isEmpty())
+ sEncoding = QString::fromLatin1(KGlobal::locale()->encoding());
+
+ QStringList encodings (KGlobal::charsets()->availableEncodingNames());
+ int insert = 0;
+ for (uint i=0; i < encodings.count(); i++)
+ {
+ bool found = false;
+ QTextCodec *codecForEnc = KGlobal::charsets()->codecForName(encodings[i], found);
+
+ if (found)
+ {
+ d->encoding->insertItem (encodings[i]);
+ if ( (codecForEnc->name() == sEncoding) || (encodings[i] == sEncoding) )
+ {
+ d->encoding->setCurrentItem(insert);
+ }
+
+ insert++;
+ }
+ }
+
+
+}
+
+KEncodingFileDialog::~KEncodingFileDialog()
+{
+ delete d;
+}
+
+
+QString KEncodingFileDialog::selectedEncoding() const
+{
+ if (d->encoding)
+ return d->encoding->currentText();
+ else
+ return QString::null;
+}
+
+
+KEncodingFileDialog::Result KEncodingFileDialog::getOpenFileNameAndEncoding(const QString& encoding,
+ const QString& startDir,
+ const QString& filter,
+ QWidget *parent, const QString& caption)
+{
+ KEncodingFileDialog dlg(startDir, encoding,filter,caption.isNull() ? i18n("Open") : caption,Opening,parent,
+ "filedialog", true);
+
+ dlg.setMode( KFile::File | KFile::LocalOnly );
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ Result res;
+ res.fileNames<<dlg.selectedFile();
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+KEncodingFileDialog::Result KEncodingFileDialog::getOpenFileNamesAndEncoding(const QString& encoding,
+ const QString& startDir,
+ const QString& filter,
+ QWidget *parent,
+ const QString& caption)
+{
+ KEncodingFileDialog dlg(startDir, encoding,filter,caption.isNull() ? i18n("Open") : caption,Opening,parent,
+ "filedialog", true);
+ dlg.setMode(KFile::Files | KFile::LocalOnly);
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ Result res;
+ res.fileNames=dlg.selectedFiles();
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+KEncodingFileDialog::Result KEncodingFileDialog::getOpenURLAndEncoding(const QString& encoding, const QString& startDir,
+ const QString& filter, QWidget *parent, const QString& caption)
+{
+ KEncodingFileDialog dlg(startDir, encoding,filter,caption.isNull() ? i18n("Open") : caption,Opening,parent,
+ "filedialog", true);
+
+ dlg.setMode( KFile::File );
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ Result res;
+ res.URLs<<dlg.selectedURL();
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+KEncodingFileDialog::Result KEncodingFileDialog::getOpenURLsAndEncoding(const QString& encoding, const QString& startDir,
+ const QString& filter,
+ QWidget *parent,
+ const QString& caption)
+{
+ KEncodingFileDialog dlg(startDir, encoding,filter,caption.isNull() ? i18n("Open") : caption,Opening,parent,
+ "filedialog", true);
+
+ dlg.setMode(KFile::Files);
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ Result res;
+ res.URLs=dlg.selectedURLs();
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+
+KEncodingFileDialog::Result KEncodingFileDialog::getSaveFileNameAndEncoding(const QString& encoding,
+ const QString& dir,
+ const QString& filter,
+ QWidget *parent,
+ const QString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ KEncodingFileDialog dlg(specialDir?dir:QString::null, encoding,filter,caption.isNull() ? i18n("Save As") : caption,
+ Saving,parent, "filedialog", true);
+
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+ dlg.exec();
+
+ QString filename = dlg.selectedFile();
+ if (!filename.isEmpty())
+ KRecentDocument::add(filename);
+
+ Result res;
+ res.fileNames<<filename;
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+
+KEncodingFileDialog::Result KEncodingFileDialog::getSaveURLAndEncoding(const QString& encoding,
+ const QString& dir, const QString& filter,
+ QWidget *parent, const QString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ KEncodingFileDialog dlg(specialDir?dir:QString::null, encoding,filter,caption.isNull() ? i18n("Save As") :
+ caption, Saving,parent, "filedialog", true);
+
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+
+ dlg.exec();
+
+ KURL url = dlg.selectedURL();
+ if (url.isValid())
+ KRecentDocument::add( url );
+
+ Result res;
+ res.URLs<<url;
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+
+
+void KEncodingFileDialog::virtual_hook( int id, void* data )
+{
+ KFileDialog::virtual_hook( id, data );
+}
+
+
+#include "kencodingfiledialog.moc"
diff --git a/kio/kfile/kencodingfiledialog.h b/kio/kfile/kencodingfiledialog.h
new file mode 100644
index 000000000..fbf3b34e6
--- /dev/null
+++ b/kio/kfile/kencodingfiledialog.h
@@ -0,0 +1,313 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
+ 2003 Andras Mantia <amantia@freemail.hu>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KENCODINGFILEDIALOG_H__
+#define __KENCODINGFILEDIALOG_H__
+
+#include <kfiledialog.h>
+
+struct KEncodingFileDialogPrivate;
+
+/**
+ * Provides a user (and developer) friendly way to
+ * select files with support for choosing encoding
+ *
+ *
+ * The dialog has been designed to allow applications to customise it
+ * by subclassing. It uses geometry management to ensure that subclasses
+ * can easily add children that will be incorporated into the layout.
+ */
+
+class KIO_EXPORT KEncodingFileDialog : public KFileDialog
+{
+ Q_OBJECT
+
+public:
+ class Result {
+ public:
+ QStringList fileNames;
+ KURL::List URLs;
+ QString encoding;
+ };
+
+ /**
+ * Constructs a file dialog for text files with encoding selection possibility.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ *
+ * @param encoding The encoding shown in the encoding combo. If it's
+ * QString::null, the global default encoding will be shown.
+ *
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ *
+ * @param caption The caption of the dialog
+ *
+ * @param type This can either be
+ * @li Opening (open dialog, the default setting)
+ * @li Saving
+ * @param parent The parent widget of this dialog
+ * @param name The name of this object
+ * @param modal Whether to create a modal dialog or not
+ *
+ * @since 3.2
+ */
+ KEncodingFileDialog (const QString& startDir = QString::null,
+ const QString& encoding = QString::null,
+ const QString& filter = QString::null,
+ const QString& caption = QString::null, KFileDialog::OperationMode type = KFileDialog::Opening,
+ QWidget *parent= 0, const char *name="", bool modal = true);
+ /**
+ * Destructs the file dialog.
+ */
+ ~KEncodingFileDialog();
+
+
+ /**
+ * @returns The selected encoding if the constructor with the encoding parameter was used, otherwise QString::null.
+ */
+ QString selectedEncoding() const;
+
+
+ /**
+ * Creates a modal file dialog and return the selected
+ * filename or an empty string if none was chosen additionally a chosen
+ * encoding value is returned.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getOpenFileNameAndEncoding(const QString& encoding=QString::null,
+ const QString& startDir= QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent= 0,
+ const QString& caption = QString::null);
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding and the selected
+ * filenames or an empty list if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getOpenFileNamesAndEncoding(const QString& encoding=QString::null,
+ const QString& startDir= QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent = 0,
+ const QString& caption= QString::null);
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding and
+ * URL or an empty string if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing URL.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getOpenURLAndEncoding(const QString& encoding=QString::null,
+ const QString& startDir = QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent= 0,
+ const QString& caption = QString::null);
+
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding
+ * URLs or an empty list if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getOpenURLsAndEncoding(const QString& encoding=QString::null,
+ const QString& startDir= QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent = 0,
+ const QString& caption= QString::null);
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding and
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with this
+ * method the user need not select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li a relative path or a filename determining the
+ * directory to start in and the file to be selected.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getSaveFileNameAndEncoding(const QString& encoding=QString::null,
+ const QString& startDir=QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent= 0,
+ const QString& caption = QString::null);
+
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding and
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with this
+ * method the user need not select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li a relative path or a filename determining the
+ * directory to start in and the file to be selected.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getSaveURLAndEncoding(const QString& encoding=QString::null,
+ const QString& startDir= QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent= 0,
+ const QString& caption = QString::null);
+
+
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KEncodingFileDialogPrivate *d;
+};
+
+#endif
diff --git a/kio/kfile/kfile.h b/kio/kfile/kfile.h
new file mode 100644
index 000000000..70253f9d8
--- /dev/null
+++ b/kio/kfile/kfile.h
@@ -0,0 +1,129 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ version 2, License as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KFILE_H
+#define KFILE_H
+
+#include <qdir.h>
+
+#include "kdelibs_export.h"
+
+/**
+ * KFile is a class which provides a namespace for some enumerated
+ * values associated with the kfile library. You will never need to
+ * construct a KFile object itself.
+ */
+
+class KIO_EXPORT KFile
+{
+public:
+ /**
+ * Modes of operation for the dialog.
+ * @li @p File - Get a single file name from the user.
+ * @li @p Directory - Get a directory name from the user.
+ * @li @p Files - Get multiple file names from the user.
+ * @li @p ExistingOnly - Never return a filename which does not exist yet
+ * @li @p LocalOnly - Don't return remote filenames
+ */
+ enum Mode {
+ File = 1,
+ Directory = 2,
+ Files = 4,
+ ExistingOnly = 8,
+ LocalOnly = 16,
+ ModeMax = 65536
+ };
+
+ enum FileView {
+ Default = 0,
+ Simple = 1,
+ Detail = 2,
+ SeparateDirs = 4,
+ PreviewContents = 8,
+ PreviewInfo = 16,
+ FileViewMax = 65536
+ };
+
+ enum SelectionMode {
+ Single = 1,
+ Multi = 2,
+ Extended = 4,
+ NoSelection = 8
+ };
+
+
+ //
+ // some bittests
+ //
+
+
+ // sorting specific
+
+ // grr, who had the idea to set QDir::Name to 0x0?
+ static bool isSortByName( const QDir::SortSpec& sort ) {
+ return (sort & QDir::Time) != QDir::Time &&
+ (sort & QDir::Size) != QDir::Size;
+ }
+
+ static bool isSortBySize( const QDir::SortSpec& sort ) {
+ return (sort & QDir::Size) == QDir::Size;
+ }
+
+ static bool isSortByDate( const QDir::SortSpec& sort ) {
+ return (sort & QDir::Time) == QDir::Time;
+ }
+
+ static bool isSortDirsFirst( const QDir::SortSpec& sort ) {
+ return (sort & QDir::DirsFirst) == QDir::DirsFirst;
+ }
+
+ static bool isSortCaseInsensitive( const QDir::SortSpec& sort ) {
+ return (sort & QDir::IgnoreCase) == QDir::IgnoreCase;
+ }
+
+
+ // view specific
+ static bool isDefaultView( const FileView& view ) {
+ return (view & Default) == Default;
+ }
+
+ static bool isSimpleView( const FileView& view ) {
+ return (view & Simple) == Simple;
+ }
+
+ static bool isDetailView( const FileView& view ) {
+ return (view & Detail) == Detail;
+ }
+
+ static bool isSeparateDirs( const FileView& view ) {
+ return (view & SeparateDirs) == SeparateDirs;
+ }
+
+ static bool isPreviewContents( const FileView& view ) {
+ return (view & PreviewContents) == PreviewContents;
+ }
+
+ /**
+ * @since 3.1
+ */
+ static bool isPreviewInfo( const FileView& view ) {
+ return (view & PreviewInfo) == PreviewInfo;
+ }
+
+};
+
+#endif // KFILE_H
diff --git a/kio/kfile/kfilebookmarkhandler.cpp b/kio/kfile/kfilebookmarkhandler.cpp
new file mode 100644
index 000000000..f69ae07a2
--- /dev/null
+++ b/kio/kfile/kfilebookmarkhandler.cpp
@@ -0,0 +1,81 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <kbookmarkimporter.h>
+#include <kbookmarkdombuilder.h>
+#include <kpopupmenu.h>
+#include <kstandarddirs.h>
+
+#include "kfiledialog.h"
+#include "kfilebookmarkhandler.h"
+
+KFileBookmarkHandler::KFileBookmarkHandler( KFileDialog *dialog )
+ : QObject( dialog, "KFileBookmarkHandler" ),
+ KBookmarkOwner(),
+ m_dialog( dialog )
+{
+ m_menu = new KPopupMenu( dialog, "bookmark menu" );
+
+ QString file = locate( "data", "kfile/bookmarks.xml" );
+ if ( file.isEmpty() )
+ file = locateLocal( "data", "kfile/bookmarks.xml" );
+
+ KBookmarkManager *manager = KBookmarkManager::managerForFile( file, false);
+
+ // import old bookmarks
+ if ( !KStandardDirs::exists( file ) ) {
+ QString oldFile = locate( "data", "kfile/bookmarks.html" );
+ if ( !oldFile.isEmpty() )
+ importOldBookmarks( oldFile, manager );
+ }
+
+ manager->setUpdate( true );
+ manager->setShowNSBookmarks( false );
+
+ m_bookmarkMenu = new KBookmarkMenu( manager, this, m_menu,
+ dialog->actionCollection(), true );
+}
+
+KFileBookmarkHandler::~KFileBookmarkHandler()
+{
+ delete m_bookmarkMenu;
+}
+
+QString KFileBookmarkHandler::currentURL() const
+{
+ return m_dialog->baseURL().url();
+}
+
+void KFileBookmarkHandler::importOldBookmarks( const QString& path,
+ KBookmarkManager *manager )
+{
+ KBookmarkDomBuilder *builder = new KBookmarkDomBuilder( manager->root(), manager );
+ KNSBookmarkImporter importer( path );
+ builder->connectImporter( &importer );
+ importer.parseNSBookmarks();
+ delete builder;
+ manager->save();
+}
+
+void KFileBookmarkHandler::virtual_hook( int id, void* data )
+{ KBookmarkOwner::virtual_hook( id, data ); }
+
+#include "kfilebookmarkhandler.moc"
diff --git a/kio/kfile/kfilebookmarkhandler.h b/kio/kfile/kfilebookmarkhandler.h
new file mode 100644
index 000000000..a6ad4fa2a
--- /dev/null
+++ b/kio/kfile/kfilebookmarkhandler.h
@@ -0,0 +1,63 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFILEBOOKMARKHANDLER_H
+#define KFILEBOOKMARKHANDLER_H
+
+#include <kbookmarkmanager.h>
+#include <kbookmarkmenu.h>
+
+class QTextStream;
+class KPopupMenu;
+
+
+class KIO_EXPORT KFileBookmarkHandler : public QObject, public KBookmarkOwner
+{
+ Q_OBJECT
+
+public:
+ KFileBookmarkHandler( KFileDialog *dialog );
+ ~KFileBookmarkHandler();
+
+ QPopupMenu * popupMenu();
+
+ // KBookmarkOwner interface:
+ virtual void openBookmarkURL( const QString& url ) { emit openURL( url ); }
+ virtual QString currentURL() const;
+
+ KPopupMenu *menu() const { return m_menu; }
+
+signals:
+ void openURL( const QString& url );
+
+private:
+ void importOldBookmarks( const QString& path, KBookmarkManager *manager );
+
+ KFileDialog *m_dialog;
+ KPopupMenu *m_menu;
+ KBookmarkMenu *m_bookmarkMenu;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileBookmarkHandlerPrivate;
+ KFileBookmarkHandlerPrivate *d;
+};
+
+
+#endif // KFILEBOOKMARKHANDLER_H
diff --git a/kio/kfile/kfiledetailview.cpp b/kio/kfile/kfiledetailview.cpp
new file mode 100644
index 000000000..78aef5fb0
--- /dev/null
+++ b/kio/kfile/kfiledetailview.cpp
@@ -0,0 +1,686 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
+ 2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qevent.h>
+#include <qkeycode.h>
+#include <qheader.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include <kapplication.h>
+#include <kfileitem.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kicontheme.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kurldrag.h>
+
+#include "kfiledetailview.h"
+#include "config-kfile.h"
+
+#define COL_NAME 0
+#define COL_SIZE 1
+#define COL_DATE 2
+#define COL_PERM 3
+#define COL_OWNER 4
+#define COL_GROUP 5
+
+class KFileDetailView::KFileDetailViewPrivate
+{
+public:
+ KFileDetailViewPrivate() : dropItem(0)
+ { }
+
+ KFileListViewItem *dropItem;
+ QTimer autoOpenTimer;
+};
+
+KFileDetailView::KFileDetailView(QWidget *parent, const char *name)
+ : KListView(parent, name), KFileView(), d(new KFileDetailViewPrivate())
+{
+ // this is always the static section, not the index depending on column order
+ m_sortingCol = COL_NAME;
+ m_blockSortingSignal = false;
+ setViewName( i18n("Detailed View") );
+
+ addColumn( i18n( "Name" ) );
+ addColumn( i18n( "Size" ) );
+ addColumn( i18n( "Date" ) );
+ addColumn( i18n( "Permissions" ) );
+ addColumn( i18n( "Owner" ) );
+ addColumn( i18n( "Group" ) );
+ setShowSortIndicator( true );
+ setAllColumnsShowFocus( true );
+ setDragEnabled(true);
+
+ connect( header(), SIGNAL( clicked(int)),
+ SLOT(slotSortingChanged(int) ));
+
+
+ connect( this, SIGNAL( returnPressed(QListViewItem *) ),
+ SLOT( slotActivate( QListViewItem *) ) );
+
+ connect( this, SIGNAL( clicked(QListViewItem *, const QPoint&, int)),
+ SLOT( selected( QListViewItem *) ) );
+ connect( this, SIGNAL( doubleClicked(QListViewItem *, const QPoint&, int)),
+ SLOT( slotActivate( QListViewItem *) ) );
+
+ connect( this, SIGNAL(contextMenuRequested( QListViewItem *,
+ const QPoint &, int )),
+ this, SLOT( slotActivateMenu( QListViewItem *, const QPoint& )));
+
+ KFile::SelectionMode sm = KFileView::selectionMode();
+ switch ( sm ) {
+ case KFile::Multi:
+ QListView::setSelectionMode( QListView::Multi );
+ break;
+ case KFile::Extended:
+ QListView::setSelectionMode( QListView::Extended );
+ break;
+ case KFile::NoSelection:
+ QListView::setSelectionMode( QListView::NoSelection );
+ break;
+ default: // fall through
+ case KFile::Single:
+ QListView::setSelectionMode( QListView::Single );
+ break;
+ }
+
+ // for highlighting
+ if ( sm == KFile::Multi || sm == KFile::Extended )
+ connect( this, SIGNAL( selectionChanged() ),
+ SLOT( slotSelectionChanged() ));
+ else
+ connect( this, SIGNAL( selectionChanged( QListViewItem * ) ),
+ SLOT( highlighted( QListViewItem * ) ));
+
+ // DND
+ connect( &(d->autoOpenTimer), SIGNAL( timeout() ),
+ this, SLOT( slotAutoOpen() ));
+
+ setSorting( sorting() );
+
+ m_resolver =
+ new KMimeTypeResolver<KFileListViewItem,KFileDetailView>( this );
+}
+
+KFileDetailView::~KFileDetailView()
+{
+ delete m_resolver;
+ delete d;
+}
+
+void KFileDetailView::readConfig( KConfig *config, const QString& group )
+{
+ restoreLayout( config, group );
+}
+
+void KFileDetailView::writeConfig( KConfig *config, const QString& group )
+{
+ saveLayout( config, group );
+}
+
+void KFileDetailView::setSelected( const KFileItem *info, bool enable )
+{
+ if ( !info )
+ return;
+
+ // we can only hope that this casts works
+ KFileListViewItem *item = (KFileListViewItem*)info->extraData( this );
+
+ if ( item )
+ KListView::setSelected( item, enable );
+}
+
+void KFileDetailView::setCurrentItem( const KFileItem *item )
+{
+ if ( !item )
+ return;
+ KFileListViewItem *it = (KFileListViewItem*) item->extraData( this );
+ if ( it )
+ KListView::setCurrentItem( it );
+}
+
+KFileItem * KFileDetailView::currentFileItem() const
+{
+ KFileListViewItem *current = static_cast<KFileListViewItem*>( currentItem() );
+ if ( current )
+ return current->fileInfo();
+
+ return 0L;
+}
+
+void KFileDetailView::clearSelection()
+{
+ KListView::clearSelection();
+}
+
+void KFileDetailView::selectAll()
+{
+ if (KFileView::selectionMode() == KFile::NoSelection ||
+ KFileView::selectionMode() == KFile::Single)
+ return;
+
+ KListView::selectAll( true );
+}
+
+void KFileDetailView::invertSelection()
+{
+ KListView::invertSelection();
+}
+
+void KFileDetailView::slotActivateMenu (QListViewItem *item,const QPoint& pos )
+{
+ if ( !item ) {
+ sig->activateMenu( 0, pos );
+ return;
+ }
+ KFileListViewItem *i = (KFileListViewItem*) item;
+ sig->activateMenu( i->fileInfo(), pos );
+}
+
+void KFileDetailView::clearView()
+{
+ m_resolver->m_lstPendingMimeIconItems.clear();
+ KListView::clear();
+}
+
+void KFileDetailView::insertItem( KFileItem *i )
+{
+ KFileView::insertItem( i );
+
+ KFileListViewItem *item = new KFileListViewItem( (QListView*) this, i );
+
+ setSortingKey( item, i );
+
+ i->setExtraData( this, item );
+
+ if ( !i->isMimeTypeKnown() )
+ m_resolver->m_lstPendingMimeIconItems.append( item );
+}
+
+void KFileDetailView::slotActivate( QListViewItem *item )
+{
+ if ( !item )
+ return;
+
+ const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
+ if ( fi )
+ sig->activate( fi );
+}
+
+void KFileDetailView::selected( QListViewItem *item )
+{
+ if ( !item )
+ return;
+
+ if ( KGlobalSettings::singleClick() ) {
+ const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
+ if ( fi && (fi->isDir() || !onlyDoubleClickSelectsFiles()) )
+ sig->activate( fi );
+ }
+}
+
+void KFileDetailView::highlighted( QListViewItem *item )
+{
+ if ( !item )
+ return;
+
+ const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
+ if ( fi )
+ sig->highlightFile( fi );
+}
+
+
+void KFileDetailView::setSelectionMode( KFile::SelectionMode sm )
+{
+ disconnect( this, SIGNAL( selectionChanged() ));
+ disconnect( this, SIGNAL( selectionChanged( QListViewItem * ) ));
+
+ KFileView::setSelectionMode( sm );
+
+ switch ( KFileView::selectionMode() ) {
+ case KFile::Multi:
+ QListView::setSelectionMode( QListView::Multi );
+ break;
+ case KFile::Extended:
+ QListView::setSelectionMode( QListView::Extended );
+ break;
+ case KFile::NoSelection:
+ QListView::setSelectionMode( QListView::NoSelection );
+ break;
+ default: // fall through
+ case KFile::Single:
+ QListView::setSelectionMode( QListView::Single );
+ break;
+ }
+
+ if ( sm == KFile::Multi || sm == KFile::Extended )
+ connect( this, SIGNAL( selectionChanged() ),
+ SLOT( slotSelectionChanged() ));
+ else
+ connect( this, SIGNAL( selectionChanged( QListViewItem * )),
+ SLOT( highlighted( QListViewItem * )));
+}
+
+bool KFileDetailView::isSelected( const KFileItem *i ) const
+{
+ if ( !i )
+ return false;
+
+ KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
+ return (item && item->isSelected());
+}
+
+
+void KFileDetailView::updateView( bool b )
+{
+ if ( !b )
+ return;
+
+ QListViewItemIterator it( (QListView*)this );
+ for ( ; it.current(); ++it ) {
+ KFileListViewItem *item=static_cast<KFileListViewItem *>(it.current());
+ item->setPixmap( 0, item->fileInfo()->pixmap(KIcon::SizeSmall) );
+ }
+}
+
+void KFileDetailView::updateView( const KFileItem *i )
+{
+ if ( !i )
+ return;
+
+ KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
+ if ( !item )
+ return;
+
+ item->init();
+ setSortingKey( item, i );
+
+ //item->repaint(); // only repaints if visible
+}
+
+void KFileDetailView::setSortingKey( KFileListViewItem *item,
+ const KFileItem *i )
+{
+ // see also setSorting()
+ QDir::SortSpec spec = KFileView::sorting();
+
+ if ( spec & QDir::Time )
+ item->setKey( sortingKey( i->time( KIO::UDS_MODIFICATION_TIME ),
+ i->isDir(), spec ));
+ else if ( spec & QDir::Size )
+ item->setKey( sortingKey( i->size(), i->isDir(), spec ));
+
+ else // Name or Unsorted
+ item->setKey( sortingKey( i->text(), i->isDir(), spec ));
+}
+
+
+void KFileDetailView::removeItem( const KFileItem *i )
+{
+ if ( !i )
+ return;
+
+ KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
+ m_resolver->m_lstPendingMimeIconItems.remove( item );
+ delete item;
+
+ KFileView::removeItem( i );
+}
+
+void KFileDetailView::slotSortingChanged( int col )
+{
+ // col is the section here, not the index!
+
+ QDir::SortSpec sort = sorting();
+ int sortSpec = -1;
+ bool reversed = (col == m_sortingCol) && (sort & QDir::Reversed) == 0;
+ m_sortingCol = col;
+
+ switch( col ) {
+ case COL_NAME:
+ sortSpec = (sort & ~QDir::SortByMask | QDir::Name);
+ break;
+ case COL_SIZE:
+ sortSpec = (sort & ~QDir::SortByMask | QDir::Size);
+ break;
+ case COL_DATE:
+ sortSpec = (sort & ~QDir::SortByMask | QDir::Time);
+ break;
+
+ // the following columns have no equivalent in QDir, so we set it
+ // to QDir::Unsorted and remember the column (m_sortingCol)
+ case COL_OWNER:
+ case COL_GROUP:
+ case COL_PERM:
+ // grmbl, QDir::Unsorted == SortByMask.
+ sortSpec = (sort & ~QDir::SortByMask);// | QDir::Unsorted;
+ break;
+ default:
+ break;
+ }
+
+ if ( reversed )
+ sortSpec |= QDir::Reversed;
+ else
+ sortSpec &= ~QDir::Reversed;
+
+ if ( sort & QDir::IgnoreCase )
+ sortSpec |= QDir::IgnoreCase;
+ else
+ sortSpec &= ~QDir::IgnoreCase;
+
+
+ KFileView::setSorting( static_cast<QDir::SortSpec>( sortSpec ) );
+
+ KFileItem *item;
+ KFileItemListIterator it( *items() );
+
+ if ( sortSpec & QDir::Time ) {
+ for ( ; (item = it.current()); ++it )
+ viewItem(item)->setKey( sortingKey( item->time( KIO::UDS_MODIFICATION_TIME ), item->isDir(), sortSpec ));
+ }
+
+ else if ( sortSpec & QDir::Size ) {
+ for ( ; (item = it.current()); ++it )
+ viewItem(item)->setKey( sortingKey( item->size(), item->isDir(),
+ sortSpec ));
+ }
+ else { // Name or Unsorted -> use column text
+ for ( ; (item = it.current()); ++it ) {
+ KFileListViewItem *i = viewItem( item );
+ i->setKey( sortingKey( i->text(m_sortingCol), item->isDir(),
+ sortSpec ));
+ }
+ }
+
+ KListView::setSorting( m_sortingCol, !reversed );
+ KListView::sort();
+
+ if ( !m_blockSortingSignal )
+ sig->changeSorting( static_cast<QDir::SortSpec>( sortSpec ) );
+}
+
+
+void KFileDetailView::setSorting( QDir::SortSpec spec )
+{
+ int col = 0;
+ if ( spec & QDir::Time )
+ col = COL_DATE;
+ else if ( spec & QDir::Size )
+ col = COL_SIZE;
+ else if ( spec & QDir::Unsorted )
+ col = m_sortingCol;
+ else
+ col = COL_NAME;
+
+ // inversed, because slotSortingChanged will reverse it
+ if ( spec & QDir::Reversed )
+ spec = (QDir::SortSpec) (spec & ~QDir::Reversed);
+ else
+ spec = (QDir::SortSpec) (spec | QDir::Reversed);
+
+ m_sortingCol = col;
+ KFileView::setSorting( (QDir::SortSpec) spec );
+
+
+ // don't emit sortingChanged() when called via setSorting()
+ m_blockSortingSignal = true; // can't use blockSignals()
+ slotSortingChanged( col );
+ m_blockSortingSignal = false;
+}
+
+void KFileDetailView::ensureItemVisible( const KFileItem *i )
+{
+ if ( !i )
+ return;
+
+ KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
+
+ if ( item )
+ KListView::ensureItemVisible( item );
+}
+
+// we're in multiselection mode
+void KFileDetailView::slotSelectionChanged()
+{
+ sig->highlightFile( 0L );
+}
+
+KFileItem * KFileDetailView::firstFileItem() const
+{
+ KFileListViewItem *item = static_cast<KFileListViewItem*>( firstChild() );
+ if ( item )
+ return item->fileInfo();
+ return 0L;
+}
+
+KFileItem * KFileDetailView::nextItem( const KFileItem *fileItem ) const
+{
+ if ( fileItem ) {
+ KFileListViewItem *item = viewItem( fileItem );
+ if ( item && item->itemBelow() )
+ return ((KFileListViewItem*) item->itemBelow())->fileInfo();
+ else
+ return 0L;
+ }
+ else
+ return firstFileItem();
+}
+
+KFileItem * KFileDetailView::prevItem( const KFileItem *fileItem ) const
+{
+ if ( fileItem ) {
+ KFileListViewItem *item = viewItem( fileItem );
+ if ( item && item->itemAbove() )
+ return ((KFileListViewItem*) item->itemAbove())->fileInfo();
+ else
+ return 0L;
+ }
+ else
+ return firstFileItem();
+}
+
+void KFileDetailView::keyPressEvent( QKeyEvent *e )
+{
+ KListView::keyPressEvent( e );
+
+ if ( e->key() == Key_Return || e->key() == Key_Enter ) {
+ if ( e->state() & ControlButton )
+ e->ignore();
+ else
+ e->accept();
+ }
+}
+
+//
+// mimetype determination on demand
+//
+void KFileDetailView::mimeTypeDeterminationFinished()
+{
+ // anything to do?
+}
+
+void KFileDetailView::determineIcon( KFileListViewItem *item )
+{
+ (void) item->fileInfo()->determineMimeType();
+ updateView( item->fileInfo() );
+}
+
+void KFileDetailView::listingCompleted()
+{
+ m_resolver->start();
+}
+
+QDragObject *KFileDetailView::dragObject()
+{
+ // create a list of the URL:s that we want to drag
+ KURL::List urls;
+ KFileItemListIterator it( * KFileView::selectedItems() );
+ for ( ; it.current(); ++it ){
+ urls.append( (*it)->url() );
+ }
+ QPixmap pixmap;
+ if( urls.count() > 1 )
+ pixmap = DesktopIcon( "kmultiple", KIcon::SizeSmall );
+ if( pixmap.isNull() )
+ pixmap = currentFileItem()->pixmap( KIcon::SizeSmall );
+
+ QPoint hotspot;
+ hotspot.setX( pixmap.width() / 2 );
+ hotspot.setY( pixmap.height() / 2 );
+ QDragObject* myDragObject = new KURLDrag( urls, widget() );
+ myDragObject->setPixmap( pixmap, hotspot );
+ return myDragObject;
+}
+
+void KFileDetailView::slotAutoOpen()
+{
+ d->autoOpenTimer.stop();
+ if( !d->dropItem )
+ return;
+
+ KFileItem *fileItem = d->dropItem->fileInfo();
+ if (!fileItem)
+ return;
+
+ if( fileItem->isFile() )
+ return;
+
+ if ( fileItem->isDir() || fileItem->isLink())
+ sig->activate( fileItem );
+}
+
+bool KFileDetailView::acceptDrag(QDropEvent* e) const
+{
+ return KURLDrag::canDecode( e ) &&
+ (e->source()!= const_cast<KFileDetailView*>(this)) &&
+ ( e->action() == QDropEvent::Copy
+ || e->action() == QDropEvent::Move
+ || e->action() == QDropEvent::Link );
+}
+
+void KFileDetailView::contentsDragEnterEvent( QDragEnterEvent *e )
+{
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ if ((dropOptions() & AutoOpenDirs) == 0)
+ return;
+
+ KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
+ if ( item ) { // are we over an item ?
+ d->dropItem = item;
+ d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
+ }
+ else
+ {
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+ }
+}
+
+void KFileDetailView::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ if ((dropOptions() & AutoOpenDirs) == 0)
+ return;
+
+ KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
+ if ( item ) { // are we over an item ?
+ if (d->dropItem != item)
+ {
+ d->dropItem = item;
+ d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
+ }
+ }
+ else
+ {
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+ }
+}
+
+void KFileDetailView::contentsDragLeaveEvent( QDragLeaveEvent * )
+{
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+}
+
+void KFileDetailView::contentsDropEvent( QDropEvent *e )
+{
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
+ KFileItem * fileItem = 0;
+ if (item)
+ fileItem = item->fileInfo();
+
+ emit dropped(e, fileItem);
+
+ KURL::List urls;
+ if (KURLDrag::decode( e, urls ) && !urls.isEmpty())
+ {
+ emit dropped(e, urls, fileItem ? fileItem->url() : KURL());
+ sig->dropURLs(fileItem, e, urls);
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////
+
+
+void KFileListViewItem::init()
+{
+ KFileListViewItem::setPixmap( COL_NAME, inf->pixmap(KIcon::SizeSmall));
+
+ setText( COL_NAME, inf->text() );
+ setText( COL_SIZE, KGlobal::locale()->formatNumber( inf->size(), 0));
+ setText( COL_DATE, inf->timeString() );
+ setText( COL_PERM, inf->permissionsString() );
+ setText( COL_OWNER, inf->user() );
+ setText( COL_GROUP, inf->group() );
+}
+
+
+void KFileDetailView::virtual_hook( int id, void* data )
+{ KListView::virtual_hook( id, data );
+ KFileView::virtual_hook( id, data ); }
+
+#include "kfiledetailview.moc"
diff --git a/kio/kfile/kfiledetailview.h b/kio/kfile/kfiledetailview.h
new file mode 100644
index 000000000..174a2483d
--- /dev/null
+++ b/kio/kfile/kfiledetailview.h
@@ -0,0 +1,219 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFILEDETAILVIEW_H
+#define KFILEDETAILVIEW_H
+
+class KFileItem;
+class QWidget;
+class QKeyEvent;
+
+#include <klistview.h>
+#include <kmimetyperesolver.h>
+
+#include "kfileview.h"
+
+/**
+ * An item for the listiew, that has a reference to its corresponding
+ * KFileItem.
+ */
+class KIO_EXPORT KFileListViewItem : public KListViewItem
+{
+public:
+ KFileListViewItem( QListView *parent, const QString &text,
+ const QPixmap &icon, KFileItem *fi )
+ : KListViewItem( parent, text ), inf( fi ) {
+ setPixmap( 0, icon );
+ setText( 0, text );
+ }
+
+ /**
+ * @since 3.1
+ */
+ KFileListViewItem( QListView *parent, KFileItem *fi )
+ : KListViewItem( parent ), inf( fi ) {
+ init();
+ }
+
+ KFileListViewItem( QListView *parent, const QString &text,
+ const QPixmap &icon, KFileItem *fi,
+ QListViewItem *after)
+ : KListViewItem( parent, after ), inf( fi ) {
+ setPixmap( 0, icon );
+ setText( 0, text );
+ }
+ ~KFileListViewItem() {
+ inf->removeExtraData( listView() );
+ }
+
+ /**
+ * @returns the corresponding KFileItem
+ */
+ KFileItem *fileInfo() const {
+ return inf;
+ }
+
+ virtual QString key( int /*column*/, bool /*ascending*/ ) const {
+ return m_key;
+ }
+
+ void setKey( const QString& key ) { m_key = key; }
+
+ QRect rect() const
+ {
+ QRect r = listView()->itemRect(this);
+ return QRect( listView()->viewportToContents( r.topLeft() ),
+ QSize( r.width(), r.height() ) );
+ }
+
+ /**
+ * @since 3.1
+ */
+ void init();
+
+private:
+ KFileItem *inf;
+ QString m_key;
+
+private:
+ class KFileListViewItemPrivate;
+ KFileListViewItemPrivate *d;
+
+};
+
+/**
+ * A list-view capable of showing KFileItem'. Used in the filedialog
+ * for example. Most of the documentation is in KFileView class.
+ *
+ * @see KDirOperator
+ * @see KCombiView
+ * @see KFileIconView
+ */
+class KIO_EXPORT KFileDetailView : public KListView, public KFileView
+{
+ Q_OBJECT
+
+public:
+ KFileDetailView(QWidget *parent, const char *name);
+ virtual ~KFileDetailView();
+
+ virtual QWidget *widget() { return this; }
+ virtual void clearView();
+ virtual void setAutoUpdate( bool ) {} // ### unused. remove in KDE4
+
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+
+ virtual void updateView( bool );
+ virtual void updateView(const KFileItem*);
+ virtual void removeItem( const KFileItem *);
+ virtual void listingCompleted();
+
+ virtual void setSelected(const KFileItem *, bool);
+ virtual bool isSelected(const KFileItem *i) const;
+ virtual void clearSelection();
+ virtual void selectAll();
+ virtual void invertSelection();
+
+ virtual void setCurrentItem( const KFileItem * );
+ virtual KFileItem * currentFileItem() const;
+ virtual KFileItem * firstFileItem() const;
+ virtual KFileItem * nextItem( const KFileItem * ) const;
+ virtual KFileItem * prevItem( const KFileItem * ) const;
+
+ virtual void insertItem( KFileItem *i );
+
+ // implemented to get noticed about sorting changes (for sortingIndicator)
+ virtual void setSorting( QDir::SortSpec );
+
+ void ensureItemVisible( const KFileItem * );
+
+ // for KMimeTypeResolver
+ void mimeTypeDeterminationFinished();
+ void determineIcon( KFileListViewItem *item );
+ QScrollView *scrollWidget() const { return (QScrollView*) this; }
+
+ virtual void readConfig( KConfig *, const QString& group = QString::null );
+ virtual void writeConfig( KConfig *, const QString& group = QString::null);
+
+signals:
+ /**
+ * The user dropped something.
+ * @p fileItem points to the item dropped on or can be 0 if the
+ * user dropped on empty space.
+ * @since 3.2
+ */
+ void dropped(QDropEvent *event, KFileItem *fileItem);
+ /**
+ * The user dropped the URLs @p urls.
+ * @p url points to the item dropped on or can be empty if the
+ * user dropped on empty space.
+ * @since 3.2
+ */
+ void dropped(QDropEvent *event, const KURL::List &urls, const KURL &url);
+
+protected:
+ virtual void keyPressEvent( QKeyEvent * );
+
+ // DND support
+ virtual QDragObject *dragObject();
+ virtual void contentsDragEnterEvent( QDragEnterEvent *e );
+ virtual void contentsDragMoveEvent( QDragMoveEvent *e );
+ virtual void contentsDragLeaveEvent( QDragLeaveEvent *e );
+ virtual void contentsDropEvent( QDropEvent *ev );
+ virtual bool acceptDrag(QDropEvent* e ) const;
+
+ int m_sortingCol;
+
+protected slots:
+ void slotSelectionChanged();
+
+private slots:
+ void slotSortingChanged( int );
+ void selected( QListViewItem *item );
+ void slotActivate( QListViewItem *item );
+ void highlighted( QListViewItem *item );
+ void slotActivateMenu ( QListViewItem *item, const QPoint& pos );
+ void slotAutoOpen();
+
+private:
+ virtual void insertItem(QListViewItem *i) { KListView::insertItem(i); }
+ virtual void setSorting(int i, bool b) { KListView::setSorting(i, b); }
+ virtual void setSelected(QListViewItem *i, bool b) { KListView::setSelected(i, b); }
+
+ inline KFileListViewItem * viewItem( const KFileItem *item ) const {
+ if ( item )
+ return (KFileListViewItem *) item->extraData( this );
+ return 0L;
+ }
+
+ void setSortingKey( KFileListViewItem *item, const KFileItem *i );
+
+
+ bool m_blockSortingSignal;
+ KMimeTypeResolver<KFileListViewItem,KFileDetailView> *m_resolver;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileDetailViewPrivate;
+ KFileDetailViewPrivate *d;
+};
+
+#endif // KFILEDETAILVIEW_H
diff --git a/kio/kfile/kfiledialog.cpp b/kio/kfile/kfiledialog.cpp
new file mode 100644
index 000000000..5668ec616
--- /dev/null
+++ b/kio/kfile/kfiledialog.cpp
@@ -0,0 +1,2372 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997, 1998 Richard Moore <rich@kde.org>
+ 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2003 Clarence Dang <dang@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kfiledialog.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <qptrcollection.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qptrlist.h>
+#include <qpixmap.h>
+#include <qtextcodec.h>
+#include <qtooltip.h>
+#include <qtimer.h>
+#include <qwhatsthis.h>
+#include <qfiledialog.h>
+
+#include <kaccel.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kcharsets.h>
+#include <kcmdlineargs.h>
+#include <kcompletionbox.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kimageio.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <kio/scheduler.h>
+#include <kio/kservicetypefactory.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kpopupmenu.h>
+#include <kprotocolinfo.h>
+#include <kpushbutton.h>
+#include <krecentdirs.h>
+#include <kshell.h>
+#include <kstandarddirs.h>
+#include <kstdguiitem.h>
+#include <kstaticdeleter.h>
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+#include <kurl.h>
+#include <kurlcombobox.h>
+#include <kurlcompletion.h>
+#include <kuser.h>
+
+#include "config-kfile.h"
+#include "kpreviewwidgetbase.h"
+
+#include <kdirselectdialog.h>
+#include <kfileview.h>
+#include <krecentdocument.h>
+#include <kfilefiltercombo.h>
+#include <kdiroperator.h>
+#include <kimagefilepreview.h>
+
+#include <kfilespeedbar.h>
+#include <kfilebookmarkhandler.h>
+
+#ifdef Q_WS_X11
+#include <X11/Xlib.h>
+#include <fixx11h.h>
+#endif
+
+enum Buttons { HOTLIST_BUTTON,
+ PATH_COMBO, CONFIGURE_BUTTON };
+
+template class QPtrList<KIO::StatJob>;
+
+namespace {
+ static void silenceQToolBar(QtMsgType, const char *)
+ {
+ }
+}
+
+struct KFileDialogPrivate
+{
+ // the last selected url
+ KURL url;
+
+ // the selected filenames in multiselection mode -- FIXME
+ QString filenames;
+
+ // the name of the filename set by setSelection
+ QString selection;
+
+ // now following all kind of widgets, that I need to rebuild
+ // the geometry management
+ QBoxLayout *boxLayout;
+ QWidget *mainWidget;
+
+ QLabel *locationLabel;
+
+ // @deprecated remove in KDE4
+ QLabel *filterLabel;
+ KURLComboBox *pathCombo;
+ KPushButton *okButton, *cancelButton;
+ KFileSpeedBar *urlBar;
+ QHBoxLayout *urlBarLayout;
+ QWidget *customWidget;
+
+ // Automatically Select Extension stuff
+ QCheckBox *autoSelectExtCheckBox;
+ bool autoSelectExtChecked; // whether or not the _user_ has checked the above box
+ QString extension; // current extension for this filter
+
+ QPtrList<KIO::StatJob> statJobs;
+
+ KURL::List urlList; //the list of selected urls
+
+ QStringList mimetypes; //the list of possible mimetypes to save as
+
+ // indicates if the location edit should be kept or cleared when changing
+ // directories
+ bool keepLocation :1;
+
+ // the KDirOperators view is set in KFileDialog::show(), so to avoid
+ // setting it again and again, we have this nice little boolean :)
+ bool hasView :1;
+
+ bool hasDefaultFilter :1; // necessary for the operationMode
+ KFileDialog::OperationMode operationMode;
+
+ // The file class used for KRecentDirs
+ QString fileClass;
+
+ KFileBookmarkHandler *bookmarkHandler;
+
+ // the ID of the path drop down so subclasses can place their custom widgets properly
+ int m_pathComboIndex;
+};
+
+KURL *KFileDialog::lastDirectory; // to set the start path
+
+static KStaticDeleter<KURL> ldd;
+
+KFileDialog::KFileDialog(const QString& startDir, const QString& filter,
+ QWidget *parent, const char* name, bool modal)
+ : KDialogBase( parent, name, modal, QString::null, 0 )
+{
+ init( startDir, filter, 0 );
+}
+
+KFileDialog::KFileDialog(const QString& startDir, const QString& filter,
+ QWidget *parent, const char* name, bool modal, QWidget* widget)
+ : KDialogBase( parent, name, modal, QString::null, 0 )
+{
+ init( startDir, filter, widget );
+}
+
+
+KFileDialog::~KFileDialog()
+{
+ hide();
+
+ KConfig *config = KGlobal::config();
+
+ if (d->urlBar)
+ d->urlBar->save( config );
+
+ config->sync();
+
+ delete d->bookmarkHandler; // Should be deleted before ops!
+ delete ops;
+ delete d;
+}
+
+void KFileDialog::setLocationLabel(const QString& text)
+{
+ d->locationLabel->setText(text);
+}
+
+void KFileDialog::setFilter(const QString& filter)
+{
+ int pos = filter.find('/');
+
+ // Check for an un-escaped '/', if found
+ // interpret as a MIME filter.
+
+ if (pos > 0 && filter[pos - 1] != '\\') {
+ QStringList filters = QStringList::split( " ", filter );
+ setMimeFilter( filters );
+ return;
+ }
+
+ // Strip the escape characters from
+ // escaped '/' characters.
+
+ QString copy (filter);
+ for (pos = 0; (pos = copy.find("\\/", pos)) != -1; ++pos)
+ copy.remove(pos, 1);
+
+ ops->clearFilter();
+ filterWidget->setFilter(copy);
+ ops->setNameFilter(filterWidget->currentFilter());
+ d->hasDefaultFilter = false;
+ filterWidget->setEditable( true );
+
+ updateAutoSelectExtension ();
+}
+
+QString KFileDialog::currentFilter() const
+{
+ return filterWidget->currentFilter();
+}
+
+// deprecated
+void KFileDialog::setFilterMimeType(const QString &label,
+ const KMimeType::List &types,
+ const KMimeType::Ptr &defaultType)
+{
+ d->mimetypes.clear();
+ d->filterLabel->setText(label);
+
+ KMimeType::List::ConstIterator it;
+ for( it = types.begin(); it != types.end(); ++it)
+ d->mimetypes.append( (*it)->name() );
+
+ setMimeFilter( d->mimetypes, defaultType->name() );
+}
+
+void KFileDialog::setMimeFilter( const QStringList& mimeTypes,
+ const QString& defaultType )
+{
+ d->mimetypes = mimeTypes;
+ filterWidget->setMimeFilter( mimeTypes, defaultType );
+
+ QStringList types = QStringList::split(" ", filterWidget->currentFilter());
+ types.append( QString::fromLatin1( "inode/directory" ));
+ ops->clearFilter();
+ ops->setMimeFilter( types );
+ d->hasDefaultFilter = !defaultType.isEmpty();
+ filterWidget->setEditable( !d->hasDefaultFilter ||
+ d->operationMode != Saving );
+
+ updateAutoSelectExtension ();
+}
+
+void KFileDialog::clearFilter()
+{
+ d->mimetypes.clear();
+ filterWidget->setFilter( QString::null );
+ ops->clearFilter();
+ d->hasDefaultFilter = false;
+ filterWidget->setEditable( true );
+
+ updateAutoSelectExtension ();
+}
+
+QString KFileDialog::currentMimeFilter() const
+{
+ int i = filterWidget->currentItem();
+ if (filterWidget->showsAllTypes())
+ i--;
+
+ if ((i >= 0) && (i < (int) d->mimetypes.count()))
+ return d->mimetypes[i];
+ return QString::null; // The "all types" item has no mimetype
+}
+
+KMimeType::Ptr KFileDialog::currentFilterMimeType()
+{
+ return KMimeType::mimeType( currentMimeFilter() );
+}
+
+void KFileDialog::setPreviewWidget(const QWidget *w) {
+ ops->setPreviewWidget(w);
+ ops->clearHistory();
+ d->hasView = true;
+}
+
+void KFileDialog::setPreviewWidget(const KPreviewWidgetBase *w) {
+ ops->setPreviewWidget(w);
+ ops->clearHistory();
+ d->hasView = true;
+}
+
+KURL KFileDialog::getCompleteURL(const QString &_url)
+{
+ QString url = KShell::tildeExpand(_url);
+ KURL u;
+
+ if ( KURL::isRelativeURL(url) ) // only a full URL isn't relative. Even /path is.
+ {
+ if (!url.isEmpty() && !QDir::isRelativePath(url) ) // absolute path
+ u.setPath( url );
+ else
+ {
+ u = ops->url();
+ u.addPath( url ); // works for filenames and relative paths
+ u.cleanPath(); // fix "dir/.."
+ }
+ }
+ else // complete URL
+ u = url;
+
+ return u;
+}
+
+// FIXME: check for "existing" flag here?
+void KFileDialog::slotOk()
+{
+ kdDebug(kfile_area) << "slotOK\n";
+
+ // a list of all selected files/directories (if any)
+ // can only be used if the user didn't type any filenames/urls himself
+ const KFileItemList *items = ops->selectedItems();
+
+ if ( (mode() & KFile::Directory) != KFile::Directory ) {
+ if ( locationEdit->currentText().stripWhiteSpace().isEmpty() ) {
+ if ( !items || items->isEmpty() )
+ {
+ QString msg;
+ if ( d->operationMode == Saving )
+ msg = i18n("Please specify the filename to save to.");
+ else
+ msg = i18n("Please select the file to open.");
+ KMessageBox::information(this, msg);
+ return;
+ }
+
+ // weird case: the location edit is empty, but there are
+ // highlighted files
+ else {
+
+ bool multi = (mode() & KFile::Files) != 0;
+ KFileItemListIterator it( *items );
+ QString endQuote = QString::fromLatin1("\" ");
+ QString name, files;
+ while ( it.current() ) {
+ name = (*it)->name();
+ if ( multi ) {
+ name.prepend( '"' );
+ name.append( endQuote );
+ }
+
+ files.append( name );
+ ++it;
+ }
+ setLocationText( files );
+ return;
+ }
+ }
+ }
+
+ bool dirOnly = ops->dirOnlyMode();
+
+ // we can use our kfileitems, no need to parse anything
+ if ( items && !locationEdit->lineEdit()->edited() &&
+ !(items->isEmpty() && !dirOnly) ) {
+
+ d->urlList.clear();
+ d->filenames = QString::null;
+
+ if ( dirOnly ) {
+ d->url = ops->url();
+ }
+ else {
+ if ( !(mode() & KFile::Files) ) {// single selection
+ d->url = items->getFirst()->url();
+ }
+
+ else { // multi (dirs and/or files)
+ d->url = ops->url();
+ KFileItemListIterator it( *items );
+ while ( it.current() ) {
+ d->urlList.append( (*it)->url() );
+ ++it;
+ }
+ }
+ }
+
+ KURL url = KIO::NetAccess::mostLocalURL(d->url,topLevelWidget());
+ if ( (mode() & KFile::LocalOnly) == KFile::LocalOnly &&
+ !url.isLocalFile() ) {
+// ### after message freeze, add message for directories!
+ KMessageBox::sorry( d->mainWidget,
+ i18n("You can only select local files."),
+ i18n("Remote Files Not Accepted") );
+ return;
+ }
+
+ d->url = url;
+ accept();
+ return;
+ }
+
+
+ KURL selectedURL;
+
+ if ( (mode() & KFile::Files) == KFile::Files ) {// multiselection mode
+ QString locationText = locationEdit->currentText();
+ if ( locationText.contains( '/' )) {
+ // relative path? -> prepend the current directory
+ KURL u( ops->url(), KShell::tildeExpand(locationText));
+ if ( u.isValid() )
+ selectedURL = u;
+ else
+ selectedURL = ops->url();
+ }
+ else // simple filename -> just use the current URL
+ selectedURL = ops->url();
+ }
+
+ else {
+ selectedURL = getCompleteURL(locationEdit->currentText());
+
+ // appendExtension() may change selectedURL
+ appendExtension (selectedURL);
+ }
+
+ if ( !selectedURL.isValid() ) {
+ KMessageBox::sorry( d->mainWidget, i18n("%1\ndoes not appear to be a valid URL.\n").arg(d->url.url()), i18n("Invalid URL") );
+ return;
+ }
+
+ KURL url = KIO::NetAccess::mostLocalURL(selectedURL,topLevelWidget());
+ if ( (mode() & KFile::LocalOnly) == KFile::LocalOnly &&
+ !url.isLocalFile() ) {
+ KMessageBox::sorry( d->mainWidget,
+ i18n("You can only select local files."),
+ i18n("Remote Files Not Accepted") );
+ return;
+ }
+
+ d->url = url;
+
+ // d->url is a correct URL now
+
+ if ( (mode() & KFile::Directory) == KFile::Directory ) {
+ kdDebug(kfile_area) << "Directory" << endl;
+ bool done = true;
+ if ( d->url.isLocalFile() ) {
+ if ( locationEdit->currentText().stripWhiteSpace().isEmpty() ) {
+ QFileInfo info( d->url.path() );
+ if ( info.isDir() ) {
+ d->filenames = QString::null;
+ d->urlList.clear();
+ d->urlList.append( d->url );
+ accept();
+ }
+ else if (!info.exists() && (mode() & KFile::File) != KFile::File) {
+ // directory doesn't exist, create and enter it
+ if ( ops->mkdir( d->url.url(), true ))
+ return;
+ else
+ accept();
+ }
+ else { // d->url is not a directory,
+ // maybe we are in File(s) | Directory mode
+ if ( (mode() & KFile::File) == KFile::File ||
+ (mode() & KFile::Files) == KFile::Files )
+ done = false;
+ }
+ }
+ else // Directory mode, with file[s]/dir[s] selected
+ {
+ if ( mode() & KFile::ExistingOnly )
+ {
+ if ( ops->dirOnlyMode() )
+ {
+ KURL fullURL(d->url, locationEdit->currentText());
+ if ( QFile::exists( fullURL.path() ) )
+ {
+ d->url = fullURL;
+ d->filenames = QString::null;
+ d->urlList.clear();
+ accept();
+ return;
+ }
+ else // doesn't exist -> reject
+ return;
+ }
+ }
+
+ d->filenames = locationEdit->currentText();
+ accept(); // what can we do?
+ }
+
+ }
+ else { // FIXME: remote directory, should we allow that?
+// qDebug( "**** Selected remote directory: %s", d->url.url().latin1());
+ d->filenames = QString::null;
+ d->urlList.clear();
+ d->urlList.append( d->url );
+
+ if ( mode() & KFile::ExistingOnly )
+ done = false;
+ else
+ accept();
+ }
+
+ if ( done )
+ return;
+ }
+
+ if (!kapp->authorizeURLAction("open", KURL(), d->url))
+ {
+ QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, d->url.prettyURL());
+ KMessageBox::error( d->mainWidget, msg);
+ return;
+ }
+
+ KIO::StatJob *job = 0L;
+ d->statJobs.clear();
+ d->filenames = KShell::tildeExpand(locationEdit->currentText());
+
+ if ( (mode() & KFile::Files) == KFile::Files &&
+ !locationEdit->currentText().contains( '/' )) {
+ kdDebug(kfile_area) << "Files\n";
+ KURL::List list = parseSelectedURLs();
+ for ( KURL::List::ConstIterator it = list.begin();
+ it != list.end(); ++it )
+ {
+ if (!kapp->authorizeURLAction("open", KURL(), *it))
+ {
+ QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, (*it).prettyURL());
+ KMessageBox::error( d->mainWidget, msg);
+ return;
+ }
+ }
+ for ( KURL::List::ConstIterator it = list.begin();
+ it != list.end(); ++it )
+ {
+ job = KIO::stat( *it, !(*it).isLocalFile() );
+ job->setWindow (topLevelWidget());
+ KIO::Scheduler::scheduleJob( job );
+ d->statJobs.append( job );
+ connect( job, SIGNAL( result(KIO::Job *) ),
+ SLOT( slotStatResult( KIO::Job *) ));
+ }
+ return;
+ }
+
+ job = KIO::stat(d->url,!d->url.isLocalFile());
+ job->setWindow (topLevelWidget());
+ d->statJobs.append( job );
+ connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotStatResult(KIO::Job*)));
+}
+
+
+static bool isDirectory (const KIO::UDSEntry &t)
+{
+ bool isDir = false;
+
+ for (KIO::UDSEntry::ConstIterator it = t.begin();
+ it != t.end();
+ it++)
+ {
+ if ((*it).m_uds == KIO::UDS_FILE_TYPE)
+ {
+ isDir = S_ISDIR ((mode_t) ((*it).m_long));
+ break;
+ }
+ }
+
+ return isDir;
+}
+
+// FIXME : count all errors and show messagebox when d->statJobs.count() == 0
+// in case of an error, we cancel the whole operation (clear d->statJobs and
+// don't call accept)
+void KFileDialog::slotStatResult(KIO::Job* job)
+{
+ kdDebug(kfile_area) << "slotStatResult" << endl;
+ KIO::StatJob *sJob = static_cast<KIO::StatJob *>( job );
+
+ if ( !d->statJobs.removeRef( sJob ) ) {
+ return;
+ }
+
+ int count = d->statJobs.count();
+
+ // errors mean in general, the location is no directory ;/
+ // Can we be sure that it is exististant at all? (pfeiffer)
+ if (sJob->error() && count == 0 && !ops->dirOnlyMode())
+ {
+ accept();
+ return;
+ }
+
+ KIO::UDSEntry t = sJob->statResult();
+ if (isDirectory (t))
+ {
+ if ( ops->dirOnlyMode() )
+ {
+ d->filenames = QString::null;
+ d->urlList.clear();
+ accept();
+ }
+ else // in File[s] mode, directory means error -> cd into it
+ {
+ if ( count == 0 ) {
+ locationEdit->clearEdit();
+ locationEdit->lineEdit()->setEdited( false );
+ setURL( sJob->url() );
+ }
+ }
+ d->statJobs.clear();
+ return;
+ }
+ else if ( ops->dirOnlyMode() )
+ {
+ return; // ### error message?
+ }
+
+ kdDebug(kfile_area) << "filename " << sJob->url().url() << endl;
+
+ if ( count == 0 )
+ accept();
+}
+
+void KFileDialog::accept()
+{
+ setResult( QDialog::Accepted ); // parseSelectedURLs() checks that
+
+ *lastDirectory = ops->url();
+ if (!d->fileClass.isEmpty())
+ KRecentDirs::add(d->fileClass, ops->url().url());
+
+ // clear the topmost item, we insert it as full path later on as item 1
+ locationEdit->changeItem( QString::null, 0 );
+
+ KURL::List list = selectedURLs();
+ QValueListConstIterator<KURL> it = list.begin();
+ for ( ; it != list.end(); ++it ) {
+ const KURL& url = *it;
+ // we strip the last slash (-1) because KURLComboBox does that as well
+ // when operating in file-mode. If we wouldn't , dupe-finding wouldn't
+ // work.
+ QString file = url.isLocalFile() ? url.path(-1) : url.prettyURL(-1);
+
+ // remove dupes
+ for ( int i = 1; i < locationEdit->count(); i++ ) {
+ if ( locationEdit->text( i ) == file ) {
+ locationEdit->removeItem( i-- );
+ break;
+ }
+ }
+ locationEdit->insertItem( file, 1 );
+ }
+
+ KConfig *config = KGlobal::config();
+ config->setForceGlobal( true );
+ writeConfig( config, ConfigGroup );
+ config->setForceGlobal( false );
+
+ saveRecentFiles( config );
+ config->sync();
+
+ KDialogBase::accept();
+
+ addToRecentDocuments();
+
+ if ( (mode() & KFile::Files) != KFile::Files ) // single selection
+ emit fileSelected(d->url.url());
+
+ ops->close();
+ emit okClicked();
+}
+
+
+void KFileDialog::fileHighlighted(const KFileItem *i)
+{
+ if (i && i->isDir())
+ return;
+
+
+ if ( (ops->mode() & KFile::Files) != KFile::Files ) {
+ if ( !i )
+ return;
+
+ d->url = i->url();
+
+ if ( !locationEdit->hasFocus() ) { // don't disturb while editing
+ setLocationText( i->name() );
+ }
+ emit fileHighlighted(d->url.url());
+ }
+
+ else {
+ multiSelectionChanged();
+ emit selectionChanged();
+ }
+}
+
+void KFileDialog::fileSelected(const KFileItem *i)
+{
+ if (i && i->isDir())
+ return;
+
+ if ( (ops->mode() & KFile::Files) != KFile::Files ) {
+ if ( !i )
+ return;
+
+ d->url = i->url();
+ setLocationText( i->name() );
+ }
+ else {
+ multiSelectionChanged();
+ emit selectionChanged();
+ }
+ slotOk();
+}
+
+
+// I know it's slow to always iterate thru the whole filelist
+// (ops->selectedItems()), but what can we do?
+void KFileDialog::multiSelectionChanged()
+{
+ if ( locationEdit->hasFocus() ) // don't disturb
+ return;
+
+ locationEdit->lineEdit()->setEdited( false );
+ KFileItem *item;
+ const KFileItemList *list = ops->selectedItems();
+ if ( !list ) {
+ locationEdit->clearEdit();
+ return;
+ }
+
+ static const QString &begin = KGlobal::staticQString(" \"");
+ KFileItemListIterator it ( *list );
+ QString text;
+ while ( (item = it.current()) ) {
+ text.append( begin ).append( item->name() ).append( '\"' );
+ ++it;
+ }
+
+ setLocationText( text.stripWhiteSpace() );
+}
+
+void KFileDialog::setLocationText( const QString& text )
+{
+ // setCurrentItem() will cause textChanged() being emitted,
+ // so slotLocationChanged() will be called. Make sure we don't clear
+ // the KDirOperator's view-selection in there
+ disconnect( locationEdit, SIGNAL( textChanged( const QString& ) ),
+ this, SLOT( slotLocationChanged( const QString& ) ) );
+ locationEdit->setCurrentItem( 0 );
+ connect( locationEdit, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotLocationChanged( const QString& )) );
+ locationEdit->setEditText( text );
+
+ // don't change selection when user has clicked on an item
+ if ( d->operationMode == Saving && !locationEdit->isVisible())
+ setNonExtSelection();
+}
+
+static const char autocompletionWhatsThisText[] = I18N_NOOP("<p>While typing in the text area, you may be presented "
+ "with possible matches. "
+ "This feature can be controlled by clicking with the right mouse button "
+ "and selecting a preferred mode from the <b>Text Completion</b> menu.") "</qt>";
+void KFileDialog::updateLocationWhatsThis (void)
+{
+ QString whatsThisText;
+ if (d->operationMode == KFileDialog::Saving)
+ {
+ whatsThisText = "<qt>" + i18n("This is the name to save the file as.") +
+ i18n (autocompletionWhatsThisText);
+ }
+ else if (ops->mode() & KFile::Files)
+ {
+ whatsThisText = "<qt>" + i18n("This is the list of files to open. More than "
+ "one file can be specified by listing several "
+ "files, separated by spaces.") +
+ i18n (autocompletionWhatsThisText);
+ }
+ else
+ {
+ whatsThisText = "<qt>" + i18n("This is the name of the file to open.") +
+ i18n (autocompletionWhatsThisText);
+ }
+
+ QWhatsThis::add(d->locationLabel, whatsThisText);
+ QWhatsThis::add(locationEdit, whatsThisText);
+}
+
+void KFileDialog::init(const QString& startDir, const QString& filter, QWidget* widget)
+{
+ initStatic();
+ d = new KFileDialogPrivate();
+
+ d->boxLayout = 0;
+ d->keepLocation = false;
+ d->operationMode = Opening;
+ d->bookmarkHandler = 0;
+ d->hasDefaultFilter = false;
+ d->hasView = false;
+ d->mainWidget = new QWidget( this, "KFileDialog::mainWidget");
+ setMainWidget( d->mainWidget );
+ d->okButton = new KPushButton( KStdGuiItem::ok(), d->mainWidget );
+ d->okButton->setDefault( true );
+ d->cancelButton = new KPushButton(KStdGuiItem::cancel(), d->mainWidget);
+ connect( d->okButton, SIGNAL( clicked() ), SLOT( slotOk() ));
+ connect( d->cancelButton, SIGNAL( clicked() ), SLOT( slotCancel() ));
+ d->customWidget = widget;
+ d->autoSelectExtCheckBox = 0; // delayed loading
+ d->autoSelectExtChecked = false;
+ d->urlBar = 0; // delayed loading
+
+ QtMsgHandler oldHandler = qInstallMsgHandler( silenceQToolBar );
+ toolbar = new KToolBar( d->mainWidget, "KFileDialog::toolbar", true);
+ toolbar->setFlat(true);
+ qInstallMsgHandler( oldHandler );
+
+ d->pathCombo = new KURLComboBox( KURLComboBox::Directories, true,
+ toolbar, "path combo" );
+ QToolTip::add( d->pathCombo, i18n("Current location") );
+ QWhatsThis::add( d->pathCombo, "<qt>" + i18n("This is the currently listed location. "
+ "The drop-down list also lists commonly used locations. "
+ "This includes standard locations, such as your home folder, as well as "
+ "locations that have been visited recently.") + i18n (autocompletionWhatsThisText));
+
+ KURL u;
+ u.setPath( QDir::rootDirPath() );
+ QString text = i18n("Root Folder: %1").arg( u.path() );
+ d->pathCombo->addDefaultURL( u,
+ KMimeType::pixmapForURL( u, 0, KIcon::Small ),
+ text );
+
+ u.setPath( QDir::homeDirPath() );
+ text = i18n("Home Folder: %1").arg( u.path( +1 ) );
+ d->pathCombo->addDefaultURL( u, KMimeType::pixmapForURL( u, 0, KIcon::Small ),
+ text );
+
+ KURL docPath;
+ docPath.setPath( KGlobalSettings::documentPath() );
+ if ( (u.path(+1) != docPath.path(+1)) &&
+ QDir(docPath.path(+1)).exists() )
+ {
+ text = i18n("Documents: %1").arg( docPath.path( +1 ) );
+ d->pathCombo->addDefaultURL( docPath,
+ KMimeType::pixmapForURL( docPath, 0, KIcon::Small ),
+ text );
+ }
+
+ u.setPath( KGlobalSettings::desktopPath() );
+ text = i18n("Desktop: %1").arg( u.path( +1 ) );
+ d->pathCombo->addDefaultURL( u,
+ KMimeType::pixmapForURL( u, 0, KIcon::Small ),
+ text );
+
+ d->url = getStartURL( startDir, d->fileClass );
+ d->selection = d->url.url();
+
+ // If local, check it exists. If not, go up until it exists.
+ if ( d->url.isLocalFile() )
+ {
+ if ( !QFile::exists( d->url.path() ) )
+ {
+ d->url = d->url.upURL();
+ QDir dir( d->url.path() );
+ while ( !dir.exists() )
+ {
+ d->url = d->url.upURL();
+ dir.setPath( d->url.path() );
+ }
+ }
+ }
+
+ ops = new KDirOperator(d->url, d->mainWidget, "KFileDialog::ops");
+ ops->setOnlyDoubleClickSelectsFiles( true );
+ connect(ops, SIGNAL(urlEntered(const KURL&)),
+ SLOT(urlEntered(const KURL&)));
+ connect(ops, SIGNAL(fileHighlighted(const KFileItem *)),
+ SLOT(fileHighlighted(const KFileItem *)));
+ connect(ops, SIGNAL(fileSelected(const KFileItem *)),
+ SLOT(fileSelected(const KFileItem *)));
+ connect(ops, SIGNAL(finishedLoading()),
+ SLOT(slotLoadingFinished()));
+
+ ops->setupMenu(KDirOperator::SortActions |
+ KDirOperator::FileActions |
+ KDirOperator::ViewActions);
+ KActionCollection *coll = ops->actionCollection();
+
+ // plug nav items into the toolbar
+ coll->action( "up" )->plug( toolbar );
+ coll->action( "up" )->setWhatsThis(i18n("<qt>Click this button to enter the parent folder.<p>"
+ "For instance, if the current location is file:/home/%1 clicking this "
+ "button will take you to file:/home.</qt>").arg( KUser().loginName() ));
+ coll->action( "back" )->plug( toolbar );
+ coll->action( "back" )->setWhatsThis(i18n("Click this button to move backwards one step in the browsing history."));
+ coll->action( "forward" )->plug( toolbar );
+ coll->action( "forward" )->setWhatsThis(i18n("Click this button to move forward one step in the browsing history."));
+ coll->action( "reload" )->plug( toolbar );
+ coll->action( "reload" )->setWhatsThis(i18n("Click this button to reload the contents of the current location."));
+ coll->action( "mkdir" )->setShortcut(Key_F10);
+ coll->action( "mkdir" )->plug( toolbar );
+ coll->action( "mkdir" )->setWhatsThis(i18n("Click this button to create a new folder."));
+
+ KToggleAction *showSidebarAction =
+ new KToggleAction(i18n("Show Quick Access Navigation Panel"), Key_F9, coll,"toggleSpeedbar");
+ showSidebarAction->setCheckedState(i18n("Hide Quick Access Navigation Panel"));
+ connect( showSidebarAction, SIGNAL( toggled( bool ) ),
+ SLOT( toggleSpeedbar( bool )) );
+
+ KToggleAction *showBookmarksAction =
+ new KToggleAction(i18n("Show Bookmarks"), 0, coll, "toggleBookmarks");
+ showBookmarksAction->setCheckedState(i18n("Hide Bookmarks"));
+ connect( showBookmarksAction, SIGNAL( toggled( bool ) ),
+ SLOT( toggleBookmarks( bool )) );
+
+ KActionMenu *menu = new KActionMenu( i18n("Configure"), "configure", this, "extra menu" );
+ menu->setWhatsThis(i18n("<qt>This is the configuration menu for the file dialog. "
+ "Various options can be accessed from this menu including: <ul>"
+ "<li>how files are sorted in the list</li>"
+ "<li>types of view, including icon and list</li>"
+ "<li>showing of hidden files</li>"
+ "<li>the Quick Access navigation panel</li>"
+ "<li>file previews</li>"
+ "<li>separating folders from files</li></ul></qt>"));
+ menu->insert( coll->action( "sorting menu" ));
+ menu->insert( coll->action( "separator" ));
+ coll->action( "short view" )->setShortcut(Key_F6);
+ menu->insert( coll->action( "short view" ));
+ coll->action( "detailed view" )->setShortcut(Key_F7);
+ menu->insert( coll->action( "detailed view" ));
+ menu->insert( coll->action( "separator" ));
+ coll->action( "show hidden" )->setShortcut(Key_F8);
+ menu->insert( coll->action( "show hidden" ));
+ menu->insert( showSidebarAction );
+ menu->insert( showBookmarksAction );
+ coll->action( "preview" )->setShortcut(Key_F11);
+ menu->insert( coll->action( "preview" ));
+ coll->action( "separate dirs" )->setShortcut(Key_F12);
+ menu->insert( coll->action( "separate dirs" ));
+
+ menu->setDelayed( false );
+ connect( menu->popupMenu(), SIGNAL( aboutToShow() ),
+ ops, SLOT( updateSelectionDependentActions() ));
+ menu->plug( toolbar );
+
+ //Insert a separator.
+ KToolBarSeparator* spacerWidget = new KToolBarSeparator(Horizontal, false /*no line*/,
+ toolbar);
+ d->m_pathComboIndex = toolbar->insertWidget(-1, -1, spacerWidget);
+ toolbar->insertWidget(PATH_COMBO, 0, d->pathCombo);
+
+
+ toolbar->setItemAutoSized (PATH_COMBO);
+ toolbar->setIconText(KToolBar::IconOnly);
+ toolbar->setBarPos(KToolBar::Top);
+ toolbar->setMovingEnabled(false);
+ toolbar->adjustSize();
+
+ KURLCompletion *pathCompletionObj = new KURLCompletion( KURLCompletion::DirCompletion );
+ d->pathCombo->setCompletionObject( pathCompletionObj );
+ d->pathCombo->setAutoDeleteCompletionObject( true );
+
+ connect( d->pathCombo, SIGNAL( urlActivated( const KURL& )),
+ this, SLOT( enterURL( const KURL& ) ));
+ connect( d->pathCombo, SIGNAL( returnPressed( const QString& )),
+ this, SLOT( enterURL( const QString& ) ));
+
+ QString whatsThisText;
+
+ // the Location label/edit
+ d->locationLabel = new QLabel(i18n("&Location:"), d->mainWidget);
+ locationEdit = new KURLComboBox(KURLComboBox::Files, true,
+ d->mainWidget, "LocationEdit");
+ connect( locationEdit, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotLocationChanged( const QString& )) );
+
+ updateLocationWhatsThis ();
+ d->locationLabel->setBuddy(locationEdit);
+
+ locationEdit->setFocus();
+ KURLCompletion *fileCompletionObj = new KURLCompletion( KURLCompletion::FileCompletion );
+ QString dir = d->url.url(+1);
+ pathCompletionObj->setDir( dir );
+ fileCompletionObj->setDir( dir );
+ locationEdit->setCompletionObject( fileCompletionObj );
+ locationEdit->setAutoDeleteCompletionObject( true );
+ connect( fileCompletionObj, SIGNAL( match( const QString& ) ),
+ SLOT( fileCompletion( const QString& )) );
+
+ connect( locationEdit, SIGNAL( returnPressed() ),
+ this, SLOT( slotOk()));
+ connect(locationEdit, SIGNAL( activated( const QString& )),
+ this, SLOT( locationActivated( const QString& ) ));
+
+ // the Filter label/edit
+ whatsThisText = i18n("<qt>This is the filter to apply to the file list. "
+ "File names that do not match the filter will not be shown.<p>"
+ "You may select from one of the preset filters in the "
+ "drop down menu, or you may enter a custom filter "
+ "directly into the text area.<p>"
+ "Wildcards such as * and ? are allowed.</qt>");
+ d->filterLabel = new QLabel(i18n("&Filter:"), d->mainWidget);
+ QWhatsThis::add(d->filterLabel, whatsThisText);
+ filterWidget = new KFileFilterCombo(d->mainWidget,
+ "KFileDialog::filterwidget");
+ QWhatsThis::add(filterWidget, whatsThisText);
+ setFilter(filter);
+ d->filterLabel->setBuddy(filterWidget);
+ connect(filterWidget, SIGNAL(filterChanged()), SLOT(slotFilterChanged()));
+
+ // the Automatically Select Extension checkbox
+ // (the text, visibility etc. is set in updateAutoSelectExtension(), which is called by readConfig())
+ d->autoSelectExtCheckBox = new QCheckBox (d->mainWidget);
+ connect(d->autoSelectExtCheckBox, SIGNAL(clicked()), SLOT(slotAutoSelectExtClicked()));
+
+ initGUI(); // activate GM
+
+ KConfig* config = KGlobal::config();
+ readRecentFiles( config );
+
+ adjustSize();
+
+ ops->setViewConfig( config, ConfigGroup );
+ readConfig( config, ConfigGroup );
+ setSelection(d->selection);
+}
+
+void KFileDialog::initSpeedbar()
+{
+ d->urlBar = new KFileSpeedBar( d->mainWidget, "url bar" );
+ connect( d->urlBar, SIGNAL( activated( const KURL& )),
+ SLOT( enterURL( const KURL& )) );
+
+ // need to set the current url of the urlbar manually (not via urlEntered()
+ // here, because the initial url of KDirOperator might be the same as the
+ // one that will be set later (and then urlEntered() won't be emitted).
+ // ### REMOVE THIS when KDirOperator's initial URL (in the c'tor) is gone.
+ d->urlBar->setCurrentItem( d->url );
+
+ d->urlBarLayout->insertWidget( 0, d->urlBar );
+}
+
+void KFileDialog::initGUI()
+{
+ delete d->boxLayout; // deletes all sub layouts
+
+ d->boxLayout = new QVBoxLayout( d->mainWidget, 0, KDialog::spacingHint());
+ d->boxLayout->addWidget(toolbar, AlignTop);
+
+ d->urlBarLayout = new QHBoxLayout( d->boxLayout ); // needed for the urlBar that may appear
+ QVBoxLayout *vbox = new QVBoxLayout( d->urlBarLayout );
+
+ vbox->addWidget(ops, 4);
+ vbox->addSpacing(3);
+
+ QGridLayout* lafBox= new QGridLayout(2, 3, KDialog::spacingHint());
+
+ lafBox->addWidget(d->locationLabel, 0, 0, AlignVCenter);
+ lafBox->addWidget(locationEdit, 0, 1, AlignVCenter);
+ lafBox->addWidget(d->okButton, 0, 2, AlignVCenter);
+
+ lafBox->addWidget(d->filterLabel, 1, 0, AlignVCenter);
+ lafBox->addWidget(filterWidget, 1, 1, AlignVCenter);
+ lafBox->addWidget(d->cancelButton, 1, 2, AlignVCenter);
+
+ lafBox->setColStretch(1, 4);
+
+ vbox->addLayout(lafBox, 0);
+ vbox->addSpacing(3);
+
+ // add the Automatically Select Extension checkbox
+ vbox->addWidget (d->autoSelectExtCheckBox);
+ vbox->addSpacing (3);
+
+ setTabOrder(ops, d->autoSelectExtCheckBox);
+ setTabOrder (d->autoSelectExtCheckBox, locationEdit);
+ setTabOrder(locationEdit, filterWidget);
+ setTabOrder(filterWidget, d->okButton);
+ setTabOrder(d->okButton, d->cancelButton);
+ setTabOrder(d->cancelButton, d->pathCombo);
+ setTabOrder(d->pathCombo, ops);
+
+ // If a custom widget was specified...
+ if ( d->customWidget != 0 )
+ {
+ // ...add it to the dialog, below the filter list box.
+
+ // Change the parent so that this widget is a child of the main widget
+ d->customWidget->reparent( d->mainWidget, QPoint() );
+
+ vbox->addWidget( d->customWidget );
+ vbox->addSpacing(3);
+
+ // FIXME: This should adjust the tab orders so that the custom widget
+ // comes after the Cancel button. The code appears to do this, but the result
+ // somehow screws up the tab order of the file path combo box. Not a major
+ // problem, but ideally the tab order with a custom widget should be
+ // the same as the order without one.
+ setTabOrder(d->cancelButton, d->customWidget);
+ setTabOrder(d->customWidget, d->pathCombo);
+ }
+ else
+ {
+ setTabOrder(d->cancelButton, d->pathCombo);
+ }
+
+ setTabOrder(d->pathCombo, ops);
+}
+
+void KFileDialog::slotFilterChanged()
+{
+ QString filter = filterWidget->currentFilter();
+ ops->clearFilter();
+
+ if ( filter.find( '/' ) > -1 ) {
+ QStringList types = QStringList::split( " ", filter );
+ types.prepend( "inode/directory" );
+ ops->setMimeFilter( types );
+ }
+ else
+ ops->setNameFilter( filter );
+
+ ops->updateDir();
+
+ updateAutoSelectExtension ();
+
+ emit filterChanged( filter );
+}
+
+
+void KFileDialog::setURL(const KURL& url, bool clearforward)
+{
+ d->selection = QString::null;
+ ops->setURL( url, clearforward);
+}
+
+// Protected
+void KFileDialog::urlEntered(const KURL& url)
+{
+ QString filename = locationEdit->currentText();
+ d->selection = QString::null;
+
+ if ( d->pathCombo->count() != 0 ) { // little hack
+ d->pathCombo->setURL( url );
+ }
+
+ locationEdit->blockSignals( true );
+ locationEdit->setCurrentItem( 0 );
+ if ( d->keepLocation )
+ locationEdit->setEditText( filename );
+
+ locationEdit->blockSignals( false );
+
+ QString dir = url.url(+1);
+ static_cast<KURLCompletion*>( d->pathCombo->completionObject() )->setDir( dir );
+ static_cast<KURLCompletion*>( locationEdit->completionObject() )->setDir( dir );
+
+ if ( d->urlBar )
+ d->urlBar->setCurrentItem( url );
+}
+
+void KFileDialog::locationActivated( const QString& url )
+{
+ // This guard prevents any URL _typed_ by the user from being interpreted
+ // twice (by returnPressed/slotOk and here, activated/locationActivated)
+ // after the user presses Enter. Without this, _both_ setSelection and
+ // slotOk would "u.addPath( url )" ...so instead we leave it up to just
+ // slotOk....
+ if (!locationEdit->lineEdit()->edited())
+ setSelection( url );
+}
+
+void KFileDialog::enterURL( const KURL& url)
+{
+ setURL( url );
+}
+
+void KFileDialog::enterURL( const QString& url )
+{
+ setURL( KURL::fromPathOrURL( KURLCompletion::replacedPath( url, true, true )) );
+}
+
+void KFileDialog::toolbarCallback(int) // SLOT
+{
+ /*
+ * yes, nothing uses this anymore.
+ * it used to be used to show the configure dialog
+ */
+}
+
+
+void KFileDialog::setSelection(const QString& url)
+{
+ kdDebug(kfile_area) << "setSelection " << url << endl;
+
+ if (url.isEmpty()) {
+ d->selection = QString::null;
+ return;
+ }
+
+ KURL u = getCompleteURL(url);
+ if (!u.isValid()) { // if it still is
+ kdWarning() << url << " is not a correct argument for setSelection!" << endl;
+ return;
+ }
+
+ if (!KProtocolInfo::supportsListing(u)) {
+ locationEdit->lineEdit()->setEdited( true );
+ return;
+ }
+
+ /* we strip the first / from the path to avoid file://usr which means
+ * / on host usr
+ */
+ KFileItem i(KFileItem::Unknown, KFileItem::Unknown, u, true );
+ // KFileItem i(u.path());
+ if ( i.isDir() && u.isLocalFile() && QFile::exists( u.path() ) ) {
+ // trust isDir() only if the file is
+ // local (we cannot stat non-local urls) and if it exists!
+ // (as KFileItem does not check if the file exists or not
+ // -> the statbuffer is undefined -> isDir() is unreliable) (Simon)
+ setURL(u, true);
+ }
+ else {
+ QString filename = u.url();
+ int sep = filename.findRev('/');
+ if (sep >= 0) { // there is a / in it
+ if ( KProtocolInfo::supportsListing( u )) {
+ KURL dir(u);
+ dir.setQuery( QString::null );
+ dir.setFileName( QString::null );
+ setURL(dir, true );
+ }
+
+ // filename must be decoded, or "name with space" would become
+ // "name%20with%20space", so we use KURL::fileName()
+ filename = u.fileName();
+ kdDebug(kfile_area) << "filename " << filename << endl;
+ d->selection = filename;
+ setLocationText( filename );
+
+ // tell the line edit that it has been edited
+ // otherwise we won't know this was set by the user
+ // and it will be ignored if there has been an
+ // auto completion. this caused bugs where automcompletion
+ // would start, the user would pick something from the
+ // history and then hit Ok only to get the autocompleted
+ // selection. OOOPS.
+ locationEdit->lineEdit()->setEdited( true );
+ }
+
+ d->url = ops->url();
+ d->url.addPath(filename);
+ }
+}
+
+void KFileDialog::slotLoadingFinished()
+{
+ if ( !d->selection.isNull() )
+ ops->setCurrentItem( d->selection );
+}
+
+// ### remove in KDE4
+void KFileDialog::pathComboChanged( const QString& )
+{
+}
+void KFileDialog::dirCompletion( const QString& ) // SLOT
+{
+}
+void KFileDialog::fileCompletion( const QString& match )
+{
+ if ( match.isEmpty() && ops->view() )
+ ops->view()->clearSelection();
+ else
+ ops->setCurrentItem( match );
+}
+
+void KFileDialog::slotLocationChanged( const QString& text )
+{
+ if ( text.isEmpty() && ops->view() )
+ ops->view()->clearSelection();
+
+ updateFilter();
+}
+
+void KFileDialog::updateStatusLine(int /* dirs */, int /* files */)
+{
+ kdWarning() << "KFileDialog::updateStatusLine is deprecated! The status line no longer exists. Do not try and use it!" << endl;
+}
+
+QString KFileDialog::getOpenFileName(const QString& startDir,
+ const QString& filter,
+ QWidget *parent, const QString& caption)
+{
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+
+ dlg.setMode( KFile::File | KFile::LocalOnly );
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedFile();
+}
+
+QString KFileDialog::getOpenFileNameWId(const QString& startDir,
+ const QString& filter,
+ WId parent_id, const QString& caption)
+{
+ QWidget* parent = QWidget::find( parent_id );
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+#ifdef Q_WS_X11
+ if( parent == NULL && parent_id != 0 )
+ XSetTransientForHint( qt_xdisplay(), dlg.winId(), parent_id );
+#else
+ // TODO
+#endif
+
+ dlg.setOperationMode( KFileDialog::Opening );
+
+ dlg.setMode( KFile::File | KFile::LocalOnly );
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedFile();
+}
+
+QStringList KFileDialog::getOpenFileNames(const QString& startDir,
+ const QString& filter,
+ QWidget *parent,
+ const QString& caption)
+{
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+ dlg.setMode(KFile::Files | KFile::LocalOnly);
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedFiles();
+}
+
+KURL KFileDialog::getOpenURL(const QString& startDir, const QString& filter,
+ QWidget *parent, const QString& caption)
+{
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+ dlg.setMode( KFile::File );
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedURL();
+}
+
+KURL::List KFileDialog::getOpenURLs(const QString& startDir,
+ const QString& filter,
+ QWidget *parent,
+ const QString& caption)
+{
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+ dlg.setMode(KFile::Files);
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedURLs();
+}
+
+KURL KFileDialog::getExistingURL(const QString& startDir,
+ QWidget *parent,
+ const QString& caption)
+{
+ return KDirSelectDialog::selectDirectory(startDir, false, parent, caption);
+}
+
+QString KFileDialog::getExistingDirectory(const QString& startDir,
+ QWidget *parent,
+ const QString& caption)
+{
+#ifdef Q_WS_WIN
+ return QFileDialog::getExistingDirectory(startDir, parent, "getExistingDirectory",
+ caption, true, true);
+#else
+ KURL url = KDirSelectDialog::selectDirectory(startDir, true, parent,
+ caption);
+ if ( url.isValid() )
+ return url.path();
+
+ return QString::null;
+#endif
+}
+
+KURL KFileDialog::getImageOpenURL( const QString& startDir, QWidget *parent,
+ const QString& caption)
+{
+ QStringList mimetypes = KImageIO::mimeTypes( KImageIO::Reading );
+ KFileDialog dlg(startDir,
+ mimetypes.join(" "),
+ parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+ dlg.setCaption( caption.isNull() ? i18n("Open") : caption );
+ dlg.setMode( KFile::File );
+
+ KImageFilePreview *ip = new KImageFilePreview( &dlg );
+ dlg.setPreviewWidget( ip );
+ dlg.exec();
+
+ return dlg.selectedURL();
+}
+
+KURL KFileDialog::selectedURL() const
+{
+ if ( result() == QDialog::Accepted )
+ return d->url;
+ else
+ return KURL();
+}
+
+KURL::List KFileDialog::selectedURLs() const
+{
+ KURL::List list;
+ if ( result() == QDialog::Accepted ) {
+ if ( (ops->mode() & KFile::Files) == KFile::Files )
+ list = parseSelectedURLs();
+ else
+ list.append( d->url );
+ }
+ return list;
+}
+
+
+KURL::List& KFileDialog::parseSelectedURLs() const
+{
+ if ( d->filenames.isEmpty() ) {
+ return d->urlList;
+ }
+
+ d->urlList.clear();
+ if ( d->filenames.contains( '/' )) { // assume _one_ absolute filename
+ static const QString &prot = KGlobal::staticQString(":/");
+ KURL u;
+ if ( d->filenames.find( prot ) != -1 )
+ u = d->filenames;
+ else
+ u.setPath( d->filenames );
+
+ if ( u.isValid() )
+ d->urlList.append( u );
+ else
+ KMessageBox::error( d->mainWidget,
+ i18n("The chosen filenames do not\n"
+ "appear to be valid."),
+ i18n("Invalid Filenames") );
+ }
+
+ else
+ d->urlList = tokenize( d->filenames );
+
+ d->filenames = QString::null; // indicate that we parsed that one
+
+ return d->urlList;
+}
+
+
+// FIXME: current implementation drawback: a filename can't contain quotes
+KURL::List KFileDialog::tokenize( const QString& line ) const
+{
+ KURL::List urls;
+ KURL u( ops->url() );
+ QString name;
+
+ int count = line.contains( '"' );
+ if ( count == 0 ) { // no " " -> assume one single file
+ u.setFileName( line );
+ if ( u.isValid() )
+ urls.append( u );
+
+ return urls;
+ }
+
+ if ( (count % 2) == 1 ) { // odd number of " -> error
+ QWidget *that = const_cast<KFileDialog *>(this);
+ KMessageBox::sorry(that, i18n("The requested filenames\n"
+ "%1\n"
+ "do not appear to be valid;\n"
+ "make sure every filename is enclosed in double quotes.").arg(line),
+ i18n("Filename Error"));
+ return urls;
+ }
+
+ int start = 0;
+ int index1 = -1, index2 = -1;
+ while ( true ) {
+ index1 = line.find( '"', start );
+ index2 = line.find( '"', index1 + 1 );
+
+ if ( index1 < 0 )
+ break;
+
+ // get everything between the " "
+ name = line.mid( index1 + 1, index2 - index1 - 1 );
+ u.setFileName( name );
+ if ( u.isValid() )
+ urls.append( u );
+
+ start = index2 + 1;
+ }
+ return urls;
+}
+
+
+QString KFileDialog::selectedFile() const
+{
+ if ( result() == QDialog::Accepted )
+ {
+ KURL url = KIO::NetAccess::mostLocalURL(d->url,topLevelWidget());
+ if (url.isLocalFile())
+ return url.path();
+ else {
+ KMessageBox::sorry( d->mainWidget,
+ i18n("You can only select local files."),
+ i18n("Remote Files Not Accepted") );
+ }
+ }
+ return QString::null;
+}
+
+QStringList KFileDialog::selectedFiles() const
+{
+ QStringList list;
+ KURL url;
+
+ if ( result() == QDialog::Accepted ) {
+ if ( (ops->mode() & KFile::Files) == KFile::Files ) {
+ KURL::List urls = parseSelectedURLs();
+ QValueListConstIterator<KURL> it = urls.begin();
+ while ( it != urls.end() ) {
+ url = KIO::NetAccess::mostLocalURL(*it,topLevelWidget());
+ if ( url.isLocalFile() )
+ list.append( url.path() );
+ ++it;
+ }
+ }
+
+ else { // single-selection mode
+ if ( d->url.isLocalFile() )
+ list.append( d->url.path() );
+ }
+ }
+
+ return list;
+}
+
+KURL KFileDialog::baseURL() const
+{
+ return ops->url();
+}
+
+QString KFileDialog::getSaveFileName(const QString& dir, const QString& filter,
+ QWidget *parent,
+ const QString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ KFileDialog dlg( specialDir ? dir : QString::null, filter, parent, "filedialog", true);
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+
+ dlg.setOperationMode( Saving );
+ dlg.setCaption(caption.isNull() ? i18n("Save As") : caption);
+
+ dlg.exec();
+
+ QString filename = dlg.selectedFile();
+ if (!filename.isEmpty())
+ KRecentDocument::add(filename);
+
+ return filename;
+}
+
+QString KFileDialog::getSaveFileNameWId(const QString& dir, const QString& filter,
+ WId parent_id,
+ const QString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ QWidget* parent = QWidget::find( parent_id );
+ KFileDialog dlg( specialDir ? dir : QString::null, filter, parent, "filedialog", true);
+#ifdef Q_WS_X11
+ if( parent == NULL && parent_id != 0 )
+ XSetTransientForHint(qt_xdisplay(), dlg.winId(), parent_id);
+#else
+ // TODO
+#endif
+
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+
+ dlg.setOperationMode( KFileDialog::Saving);
+ dlg.setCaption(caption.isNull() ? i18n("Save As") : caption);
+
+ dlg.exec();
+
+ QString filename = dlg.selectedFile();
+ if (!filename.isEmpty())
+ KRecentDocument::add(filename);
+
+ return filename;
+}
+
+KURL KFileDialog::getSaveURL(const QString& dir, const QString& filter,
+ QWidget *parent, const QString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ KFileDialog dlg(specialDir ? dir : QString::null, filter, parent, "filedialog", true);
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+
+ dlg.setCaption(caption.isNull() ? i18n("Save As") : caption);
+ dlg.setOperationMode( Saving );
+
+ dlg.exec();
+
+ KURL url = dlg.selectedURL();
+ if (url.isValid())
+ KRecentDocument::add( url );
+
+ return url;
+}
+
+void KFileDialog::show()
+{
+ if ( !d->hasView ) { // delayed view-creation
+ ops->setView(KFile::Default);
+ ops->clearHistory();
+ d->hasView = true;
+ }
+
+ KDialogBase::show();
+}
+
+void KFileDialog::setMode( KFile::Mode m )
+{
+ ops->setMode(m);
+ if ( ops->dirOnlyMode() ) {
+ filterWidget->setDefaultFilter( i18n("*|All Folders") );
+ }
+ else {
+ filterWidget->setDefaultFilter( i18n("*|All Files") );
+ }
+
+ updateAutoSelectExtension ();
+}
+
+void KFileDialog::setMode( unsigned int m )
+{
+ setMode(static_cast<KFile::Mode>( m ));
+}
+
+KFile::Mode KFileDialog::mode() const
+{
+ return ops->mode();
+}
+
+
+void KFileDialog::readConfig( KConfig *kc, const QString& group )
+{
+ if ( !kc )
+ return;
+
+ QString oldGroup = kc->group();
+ if ( !group.isEmpty() )
+ kc->setGroup( group );
+
+ ops->readConfig( kc, group );
+
+ KURLComboBox *combo = d->pathCombo;
+ combo->setURLs( kc->readPathListEntry( RecentURLs ), KURLComboBox::RemoveTop );
+ combo->setMaxItems( kc->readNumEntry( RecentURLsNumber,
+ DefaultRecentURLsNumber ) );
+ combo->setURL( ops->url() );
+ autoDirectoryFollowing = kc->readBoolEntry( AutoDirectoryFollowing,
+ DefaultDirectoryFollowing );
+
+ KGlobalSettings::Completion cm = (KGlobalSettings::Completion)
+ kc->readNumEntry( PathComboCompletionMode,
+ KGlobalSettings::completionMode() );
+ if ( cm != KGlobalSettings::completionMode() )
+ combo->setCompletionMode( cm );
+
+ cm = (KGlobalSettings::Completion)
+ kc->readNumEntry( LocationComboCompletionMode,
+ KGlobalSettings::completionMode() );
+ if ( cm != KGlobalSettings::completionMode() )
+ locationEdit->setCompletionMode( cm );
+
+ // show or don't show the speedbar
+ toggleSpeedbar( kc->readBoolEntry(ShowSpeedbar, true) );
+
+ // show or don't show the bookmarks
+ toggleBookmarks( kc->readBoolEntry(ShowBookmarks, false) );
+
+ // does the user want Automatically Select Extension?
+ d->autoSelectExtChecked = kc->readBoolEntry (AutoSelectExtChecked, DefaultAutoSelectExtChecked);
+ updateAutoSelectExtension ();
+
+ int w1 = minimumSize().width();
+ int w2 = toolbar->sizeHint().width() + 10;
+ if (w1 < w2)
+ setMinimumWidth(w2);
+
+ QSize size = configDialogSize( group );
+ resize( size );
+ kc->setGroup( oldGroup );
+}
+
+void KFileDialog::writeConfig( KConfig *kc, const QString& group )
+{
+ if ( !kc )
+ return;
+
+ QString oldGroup = kc->group();
+ if ( !group.isEmpty() )
+ kc->setGroup( group );
+
+ kc->writePathEntry( RecentURLs, d->pathCombo->urls() );
+ saveDialogSize( group, true );
+ kc->writeEntry( PathComboCompletionMode, static_cast<int>(d->pathCombo->completionMode()) );
+ kc->writeEntry( LocationComboCompletionMode, static_cast<int>(locationEdit->completionMode()) );
+ kc->writeEntry( ShowSpeedbar, d->urlBar && !d->urlBar->isHidden() );
+ kc->writeEntry( ShowBookmarks, d->bookmarkHandler != 0 );
+ kc->writeEntry( AutoSelectExtChecked, d->autoSelectExtChecked );
+
+ ops->writeConfig( kc, group );
+ kc->setGroup( oldGroup );
+}
+
+
+void KFileDialog::readRecentFiles( KConfig *kc )
+{
+ QString oldGroup = kc->group();
+ kc->setGroup( ConfigGroup );
+
+ locationEdit->setMaxItems( kc->readNumEntry( RecentFilesNumber,
+ DefaultRecentURLsNumber ) );
+ locationEdit->setURLs( kc->readPathListEntry( RecentFiles ),
+ KURLComboBox::RemoveBottom );
+ locationEdit->insertItem( QString::null, 0 ); // dummy item without pixmap
+ locationEdit->setCurrentItem( 0 );
+
+ kc->setGroup( oldGroup );
+}
+
+void KFileDialog::saveRecentFiles( KConfig *kc )
+{
+ QString oldGroup = kc->group();
+ kc->setGroup( ConfigGroup );
+
+ kc->writePathEntry( RecentFiles, locationEdit->urls() );
+
+ kc->setGroup( oldGroup );
+}
+
+KPushButton * KFileDialog::okButton() const
+{
+ return d->okButton;
+}
+
+KPushButton * KFileDialog::cancelButton() const
+{
+ return d->cancelButton;
+}
+
+KURLBar * KFileDialog::speedBar()
+{
+ return d->urlBar;
+}
+
+void KFileDialog::slotCancel()
+{
+ ops->close();
+ KDialogBase::slotCancel();
+
+ KConfig *config = KGlobal::config();
+ config->setForceGlobal( true );
+ writeConfig( config, ConfigGroup );
+ config->setForceGlobal( false );
+}
+
+void KFileDialog::setKeepLocation( bool keep )
+{
+ d->keepLocation = keep;
+}
+
+bool KFileDialog::keepsLocation() const
+{
+ return d->keepLocation;
+}
+
+void KFileDialog::setOperationMode( OperationMode mode )
+{
+ d->operationMode = mode;
+ d->keepLocation = (mode == Saving);
+ filterWidget->setEditable( !d->hasDefaultFilter || mode != Saving );
+ if ( mode == Opening )
+ d->okButton->setGuiItem( KGuiItem( i18n("&Open"), "fileopen") );
+ else if ( mode == Saving ) {
+ d->okButton->setGuiItem( KStdGuiItem::save() );
+ setNonExtSelection();
+ }
+ else
+ d->okButton->setGuiItem( KStdGuiItem::ok() );
+ updateLocationWhatsThis ();
+ updateAutoSelectExtension ();
+}
+
+KFileDialog::OperationMode KFileDialog::operationMode() const
+{
+ return d->operationMode;
+}
+
+void KFileDialog::slotAutoSelectExtClicked()
+{
+ kdDebug (kfile_area) << "slotAutoSelectExtClicked(): "
+ << d->autoSelectExtCheckBox->isChecked () << endl;
+
+ // whether the _user_ wants it on/off
+ d->autoSelectExtChecked = d->autoSelectExtCheckBox->isChecked ();
+
+ // update the current filename's extension
+ updateLocationEditExtension (d->extension /* extension hasn't changed */);
+}
+
+static QString getExtensionFromPatternList (const QStringList &patternList)
+{
+ QString ret;
+ kdDebug (kfile_area) << "\tgetExtension " << patternList << endl;
+
+ QStringList::ConstIterator patternListEnd = patternList.end ();
+ for (QStringList::ConstIterator it = patternList.begin ();
+ it != patternListEnd;
+ it++)
+ {
+ kdDebug (kfile_area) << "\t\ttry: \'" << (*it) << "\'" << endl;
+
+ // is this pattern like "*.BMP" rather than useless things like:
+ //
+ // README
+ // *.
+ // *.*
+ // *.JP*G
+ // *.JP?
+ if ((*it).startsWith ("*.") &&
+ (*it).length () > 2 &&
+ (*it).find ('*', 2) < 0 && (*it).find ('?', 2) < 0)
+ {
+ ret = (*it).mid (1);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static QString stripUndisplayable (const QString &string)
+{
+ QString ret = string;
+
+ ret.remove (':');
+ ret.remove ('&');
+
+ return ret;
+}
+
+
+QString KFileDialog::currentFilterExtension (void)
+{
+ return d->extension;
+}
+
+void KFileDialog::updateAutoSelectExtension (void)
+{
+ if (!d->autoSelectExtCheckBox) return;
+
+ //
+ // Figure out an extension for the Automatically Select Extension thing
+ // (some Windows users apparently don't know what to do when confronted
+ // with a text file called "COPYING" but do know what to do with
+ // COPYING.txt ...)
+ //
+
+ kdDebug (kfile_area) << "Figure out an extension: " << endl;
+ QString lastExtension = d->extension;
+ d->extension = QString::null;
+
+ // Automatically Select Extension is only valid if the user is _saving_ a _file_
+ if ((operationMode () == Saving) && (mode () & KFile::File))
+ {
+ //
+ // Get an extension from the filter
+ //
+
+ QString filter = currentFilter ();
+ if (!filter.isEmpty ())
+ {
+ // e.g. "*.cpp"
+ if (filter.find ('/') < 0)
+ {
+ d->extension = getExtensionFromPatternList (QStringList::split (" ", filter)).lower ();
+ kdDebug (kfile_area) << "\tsetFilter-style: pattern ext=\'"
+ << d->extension << "\'" << endl;
+ }
+ // e.g. "text/html"
+ else
+ {
+ KMimeType::Ptr mime = KMimeType::mimeType (filter);
+
+ // first try X-KDE-NativeExtension
+ QString nativeExtension = mime->property ("X-KDE-NativeExtension").toString ();
+ if (nativeExtension.at (0) == '.')
+ {
+ d->extension = nativeExtension.lower ();
+ kdDebug (kfile_area) << "\tsetMimeFilter-style: native ext=\'"
+ << d->extension << "\'" << endl;
+ }
+
+ // no X-KDE-NativeExtension
+ if (d->extension.isEmpty ())
+ {
+ d->extension = getExtensionFromPatternList (mime->patterns ()).lower ();
+ kdDebug (kfile_area) << "\tsetMimeFilter-style: pattern ext=\'"
+ << d->extension << "\'" << endl;
+ }
+ }
+ }
+
+
+ //
+ // GUI: checkbox
+ //
+
+ QString whatsThisExtension;
+ if (!d->extension.isEmpty ())
+ {
+ // remember: sync any changes to the string with below
+ d->autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension (%1)").arg (d->extension));
+ whatsThisExtension = i18n ("the extension <b>%1</b>").arg (d->extension);
+
+ d->autoSelectExtCheckBox->setEnabled (true);
+ d->autoSelectExtCheckBox->setChecked (d->autoSelectExtChecked);
+ }
+ else
+ {
+ // remember: sync any changes to the string with above
+ d->autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension"));
+ whatsThisExtension = i18n ("a suitable extension");
+
+ d->autoSelectExtCheckBox->setChecked (false);
+ d->autoSelectExtCheckBox->setEnabled (false);
+ }
+
+ const QString locationLabelText = stripUndisplayable (d->locationLabel->text ());
+ const QString filterLabelText = stripUndisplayable (d->filterLabel->text ());
+ QWhatsThis::add (d->autoSelectExtCheckBox,
+ "<qt>" +
+ i18n (
+ "This option enables some convenient features for "
+ "saving files with extensions:<br>"
+ "<ol>"
+ "<li>Any extension specified in the <b>%1</b> text "
+ "area will be updated if you change the file type "
+ "to save in.<br>"
+ "<br></li>"
+ "<li>If no extension is specified in the <b>%2</b> "
+ "text area when you click "
+ "<b>Save</b>, %3 will be added to the end of the "
+ "filename (if the filename does not already exist). "
+ "This extension is based on the file type that you "
+ "have chosen to save in.<br>"
+ "<br>"
+ "If you do not want KDE to supply an extension for the "
+ "filename, you can either turn this option off or you "
+ "can suppress it by adding a period (.) to the end of "
+ "the filename (the period will be automatically "
+ "removed)."
+ "</li>"
+ "</ol>"
+ "If unsure, keep this option enabled as it makes your "
+ "files more manageable."
+ )
+ .arg (locationLabelText)
+ .arg (locationLabelText)
+ .arg (whatsThisExtension)
+ + "</qt>"
+ );
+
+ d->autoSelectExtCheckBox->show ();
+
+
+ // update the current filename's extension
+ updateLocationEditExtension (lastExtension);
+ }
+ // Automatically Select Extension not valid
+ else
+ {
+ d->autoSelectExtCheckBox->setChecked (false);
+ d->autoSelectExtCheckBox->hide ();
+ }
+}
+
+// Updates the extension of the filename specified in locationEdit if the
+// Automatically Select Extension feature is enabled.
+// (this prevents you from accidently saving "file.kwd" as RTF, for example)
+void KFileDialog::updateLocationEditExtension (const QString &lastExtension)
+{
+ if (!d->autoSelectExtCheckBox->isChecked () || d->extension.isEmpty ())
+ return;
+
+ QString urlStr = locationEdit->currentText ();
+ if (urlStr.isEmpty ())
+ return;
+
+ KURL url = getCompleteURL (urlStr);
+ kdDebug (kfile_area) << "updateLocationEditExtension (" << url << ")" << endl;
+
+ const int fileNameOffset = urlStr.findRev ('/') + 1;
+ QString fileName = urlStr.mid (fileNameOffset);
+
+ const int dot = fileName.findRev ('.');
+ const int len = fileName.length ();
+ if (dot > 0 && // has an extension already and it's not a hidden file
+ // like ".hidden" (but we do accept ".hidden.ext")
+ dot != len - 1 // and not deliberately suppressing extension
+ )
+ {
+ // exists?
+ KIO::UDSEntry t;
+ if (KIO::NetAccess::stat (url, t, topLevelWidget()))
+ {
+ kdDebug (kfile_area) << "\tfile exists" << endl;
+
+ if (isDirectory (t))
+ {
+ kdDebug (kfile_area) << "\tisDir - won't alter extension" << endl;
+ return;
+ }
+
+ // --- fall through ---
+ }
+
+
+ //
+ // try to get rid of the current extension
+ //
+
+ // catch "double extensions" like ".tar.gz"
+ if (lastExtension.length () && fileName.endsWith (lastExtension))
+ fileName.truncate (len - lastExtension.length ());
+ // can only handle "single extensions"
+ else
+ fileName.truncate (dot);
+
+ // add extension
+ const QString newText = urlStr.left (fileNameOffset) + fileName + d->extension;
+ if ( newText != locationEdit->currentText() )
+ {
+ locationEdit->setCurrentText (urlStr.left (fileNameOffset) + fileName + d->extension);
+ locationEdit->lineEdit()->setEdited (true);
+ }
+ }
+}
+
+// Updates the filter if the extension of the filename specified in locationEdit is changed
+// (this prevents you from accidently saving "file.kwd" as RTF, for example)
+void KFileDialog::updateFilter ()
+{
+ if ((operationMode() == Saving) && (mode() & KFile::File) ) {
+ const QString urlStr = locationEdit->currentText ();
+ if (urlStr.isEmpty ())
+ return;
+
+ KMimeType::Ptr mime = KMimeType::findByPath(urlStr, 0, true);
+ if (mime && mime->name() != KMimeType::defaultMimeType()) {
+ if (filterWidget->currentFilter() != mime->name() &&
+ filterWidget->filters.findIndex(mime->name()) != -1) {
+ filterWidget->setCurrentFilter(mime->name());
+ }
+ }
+ }
+}
+
+// applies only to a file that doesn't already exist
+void KFileDialog::appendExtension (KURL &url)
+{
+ if (!d->autoSelectExtCheckBox->isChecked () || d->extension.isEmpty ())
+ return;
+
+ QString fileName = url.fileName ();
+ if (fileName.isEmpty ())
+ return;
+
+ kdDebug (kfile_area) << "appendExtension(" << url << ")" << endl;
+
+ const int len = fileName.length ();
+ const int dot = fileName.findRev ('.');
+
+ const bool suppressExtension = (dot == len - 1);
+ const bool unspecifiedExtension = (dot <= 0);
+
+ // don't KIO::NetAccess::Stat if unnecessary
+ if (!(suppressExtension || unspecifiedExtension))
+ return;
+
+ // exists?
+ KIO::UDSEntry t;
+ if (KIO::NetAccess::stat (url, t, topLevelWidget()))
+ {
+ kdDebug (kfile_area) << "\tfile exists - won't append extension" << endl;
+ return;
+ }
+
+ // suppress automatically append extension?
+ if (suppressExtension)
+ {
+ //
+ // Strip trailing dot
+ // This allows lazy people to have autoSelectExtCheckBox->isChecked
+ // but don't want a file extension to be appended
+ // e.g. "README." will make a file called "README"
+ //
+ // If you really want a name like "README.", then type "README.."
+ // and the trailing dot will be removed (or just stop being lazy and
+ // turn off this feature so that you can type "README.")
+ //
+ kdDebug (kfile_area) << "\tstrip trailing dot" << endl;
+ url.setFileName (fileName.left (len - 1));
+ }
+ // evilmatically append extension :) if the user hasn't specified one
+ else if (unspecifiedExtension)
+ {
+ kdDebug (kfile_area) << "\tappending extension \'" << d->extension << "\'..." << endl;
+ url.setFileName (fileName + d->extension);
+ kdDebug (kfile_area) << "\tsaving as \'" << url << "\'" << endl;
+ }
+}
+
+
+// adds the selected files/urls to 'recent documents'
+void KFileDialog::addToRecentDocuments()
+{
+ int m = ops->mode();
+
+ if ( m & KFile::LocalOnly ) {
+ QStringList files = selectedFiles();
+ QStringList::ConstIterator it = files.begin();
+ for ( ; it != files.end(); ++it )
+ KRecentDocument::add( *it );
+ }
+
+ else { // urls
+ KURL::List urls = selectedURLs();
+ KURL::List::ConstIterator it = urls.begin();
+ for ( ; it != urls.end(); ++it ) {
+ if ( (*it).isValid() )
+ KRecentDocument::add( *it );
+ }
+ }
+}
+
+KActionCollection * KFileDialog::actionCollection() const
+{
+ return ops->actionCollection();
+}
+
+void KFileDialog::keyPressEvent( QKeyEvent *e )
+{
+ if ( e->key() == Key_Escape )
+ {
+ e->accept();
+ d->cancelButton->animateClick();
+ }
+ else
+ KDialogBase::keyPressEvent( e );
+}
+
+void KFileDialog::toggleSpeedbar( bool show )
+{
+ if ( show )
+ {
+ if ( !d->urlBar )
+ initSpeedbar();
+
+ d->urlBar->show();
+
+ // check to see if they have a home item defined, if not show the home button
+ KURLBarItem *urlItem = static_cast<KURLBarItem*>( d->urlBar->listBox()->firstItem() );
+ KURL homeURL;
+ homeURL.setPath( QDir::homeDirPath() );
+ while ( urlItem )
+ {
+ if ( homeURL.equals( urlItem->url(), true ) )
+ {
+ ops->actionCollection()->action( "home" )->unplug( toolbar );
+ break;
+ }
+
+ urlItem = static_cast<KURLBarItem*>( urlItem->next() );
+ }
+ }
+ else
+ {
+ if (d->urlBar)
+ d->urlBar->hide();
+
+ if ( !ops->actionCollection()->action( "home" )->isPlugged( toolbar ) )
+ ops->actionCollection()->action( "home" )->plug( toolbar, 3 );
+ }
+
+ static_cast<KToggleAction *>(actionCollection()->action("toggleSpeedbar"))->setChecked( show );
+}
+
+void KFileDialog::toggleBookmarks(bool show)
+{
+ if (show)
+ {
+ if (d->bookmarkHandler)
+ {
+ return;
+ }
+
+ d->bookmarkHandler = new KFileBookmarkHandler( this );
+ connect( d->bookmarkHandler, SIGNAL( openURL( const QString& )),
+ SLOT( enterURL( const QString& )));
+
+ toolbar->insertButton(QString::fromLatin1("bookmark"),
+ (int)HOTLIST_BUTTON, true,
+ i18n("Bookmarks"), 5);
+ toolbar->getButton(HOTLIST_BUTTON)->setPopup(d->bookmarkHandler->menu(),
+ true);
+ QWhatsThis::add(toolbar->getButton(HOTLIST_BUTTON),
+ i18n("<qt>This button allows you to bookmark specific locations. "
+ "Click on this button to open the bookmark menu where you may add, "
+ "edit or select a bookmark.<p>"
+ "These bookmarks are specific to the file dialog, but otherwise operate "
+ "like bookmarks elsewhere in KDE.</qt>"));
+ }
+ else if (d->bookmarkHandler)
+ {
+ delete d->bookmarkHandler;
+ d->bookmarkHandler = 0;
+ toolbar->removeItem(HOTLIST_BUTTON);
+ }
+
+ static_cast<KToggleAction *>(actionCollection()->action("toggleBookmarks"))->setChecked( show );
+}
+
+int KFileDialog::pathComboIndex()
+{
+ return d->m_pathComboIndex;
+}
+
+// static
+void KFileDialog::initStatic()
+{
+ if ( lastDirectory )
+ return;
+
+ lastDirectory = ldd.setObject(lastDirectory, new KURL());
+}
+
+// static
+KURL KFileDialog::getStartURL( const QString& startDir,
+ QString& recentDirClass )
+{
+ initStatic();
+
+ recentDirClass = QString::null;
+ KURL ret;
+
+ bool useDefaultStartDir = startDir.isEmpty();
+ if ( !useDefaultStartDir )
+ {
+ if (startDir[0] == ':')
+ {
+ recentDirClass = startDir;
+ ret = KURL::fromPathOrURL( KRecentDirs::dir(recentDirClass) );
+ }
+ else
+ {
+ ret = KCmdLineArgs::makeURL( QFile::encodeName(startDir) );
+ // If we won't be able to list it (e.g. http), then use default
+ if ( !KProtocolInfo::supportsListing( ret ) )
+ useDefaultStartDir = true;
+ }
+ }
+
+ if ( useDefaultStartDir )
+ {
+ if (lastDirectory->isEmpty()) {
+ lastDirectory->setPath(KGlobalSettings::documentPath());
+ KURL home;
+ home.setPath( QDir::homeDirPath() );
+ // if there is no docpath set (== home dir), we prefer the current
+ // directory over it. We also prefer the homedir when our CWD is
+ // different from our homedirectory or when the document dir
+ // does not exist
+ if ( lastDirectory->path(+1) == home.path(+1) ||
+ QDir::currentDirPath() != QDir::homeDirPath() ||
+ !QDir(lastDirectory->path(+1)).exists() )
+ lastDirectory->setPath(QDir::currentDirPath());
+ }
+ ret = *lastDirectory;
+ }
+
+ return ret;
+}
+
+void KFileDialog::setStartDir( const KURL& directory )
+{
+ initStatic();
+ if ( directory.isValid() )
+ *lastDirectory = directory;
+}
+
+void KFileDialog::setNonExtSelection()
+{
+ // Enhanced rename: Don't highlight the file extension.
+ QString pattern, filename = locationEdit->currentText().stripWhiteSpace();
+ KServiceTypeFactory::self()->findFromPattern( filename, &pattern );
+
+ if ( !pattern.isEmpty() && pattern.at( 0 ) == '*' && pattern.find( '*' , 1 ) == -1 )
+ locationEdit->lineEdit()->setSelection( 0, filename.length() - pattern.stripWhiteSpace().length()+1 );
+ else
+ {
+ int lastDot = filename.findRev( '.' );
+ if ( lastDot > 0 )
+ locationEdit->lineEdit()->setSelection( 0, lastDot );
+ }
+}
+
+void KFileDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+
+#include "kfiledialog.moc"
diff --git a/kio/kfile/kfiledialog.h b/kio/kfile/kfiledialog.h
new file mode 100644
index 000000000..e90338608
--- /dev/null
+++ b/kio/kfile/kfiledialog.h
@@ -0,0 +1,989 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997, 1998 Richard Moore <rich@kde.org>
+ 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2001 Frerich Raabe <raabe@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KFILEDIALOG_H__
+#define __KFILEDIALOG_H__
+
+#include <qstring.h>
+
+#include <kdialogbase.h>
+#include <kfile.h>
+#include <kurl.h>
+#include <kmimetype.h>
+#include <kio/jobclasses.h>
+
+class QCheckBox;
+class QHBoxLayout;
+class QGridLayout;
+class QLabel;
+class QPopupMenu;
+class QVBoxLayout;
+
+class KActionCollection;
+class KDirOperator;
+class KURLBar;
+class KURLComboBox;
+class KFileFilterCombo;
+class KFileView;
+class KFileItem;
+class KPushButton;
+class KToolBar;
+class KPreviewWidgetBase;
+
+struct KFileDialogPrivate;
+
+/**
+ * Provides a user (and developer) friendly way to
+ * select files and directories.
+ *
+ * The widget can be used as a drop in replacement for the
+ * QFileDialog widget, but has greater functionality and a nicer GUI.
+ *
+ * You will usually want to use one of the static methods
+ * getOpenFileName(), getSaveFileName(), getOpenURL()
+ * or for multiple files getOpenFileNames() or getOpenURLs().
+ *
+ * The dialog has been designed to allow applications to customise it
+ * by subclassing. It uses geometry management to ensure that subclasses
+ * can easily add children that will be incorporated into the layout.
+ *
+ * \image html kfiledialog.png "KDE File Dialog"
+ *
+ * @short A file selection dialog.
+ *
+ * @author Richard J. Moore <rich@kde.org>, Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class KIO_EXPORT KFileDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Defines some default behavior of the filedialog.
+ * E.g. in mode @p Opening and @p Saving, the selected files/urls will
+ * be added to the "recent documents" list. The Saving mode also implies
+ * setKeepLocation() being set.
+ *
+ * @p Other means that no default actions are performed.
+ *
+ * @see setOperationMode
+ * @see operationMode
+ */
+ enum OperationMode { Other = 0, Opening, Saving };
+
+ /**
+ * Constructs a file dialog.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ *
+ * @param filter A shell glob or a mime-type-filter that specifies
+ * which files to display.
+ * @param parent The parent widget of this dialog
+ * @param name The name of this object
+ * @param modal Whether to create a modal dialog or not
+ * See setFilter() for details on how to use this argument.
+ *
+ */
+ KFileDialog(const QString& startDir, const QString& filter,
+ QWidget *parent, const char *name,
+ bool modal);
+
+ /**
+ * Constructs a file dialog.
+ *
+ * The parameters here are identical to the first constructor except
+ * for the addition of a QWidget parameter.
+ *
+ * Historical note: The original version of KFileDialog did not have this extra
+ * parameter. It was added later, and, in order to maintain binary compatibility,
+ * it was placed in a new constructor instead of added to the original one.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ *
+ * @param filter A shell glob or a mime-type-filter that specifies
+ * which files to display.
+ * See setFilter() for details on how to use this argument.
+ *
+ * @param widget A widget, or a widget of widgets, for displaying custom
+ * data in the dialog. This can be used, for example, to
+ * display a check box with the caption "Open as read-only".
+ * When creating this widget, you don't need to specify a parent,
+ * since the widget's parent will be set automatically by KFileDialog.
+ * @param parent The parent widget of this dialog
+ * @param name The name of this object
+ * @param modal Whether to create a modal dialog or not
+ * @since 3.1
+ */
+ KFileDialog(const QString& startDir, const QString& filter,
+ QWidget *parent, const char *name,
+ bool modal, QWidget* widget);
+
+
+ /**
+ * Destructs the file dialog.
+ */
+ ~KFileDialog();
+
+ /**
+ * @returns The selected fully qualified filename.
+ */
+ KURL selectedURL() const;
+
+ /**
+ * @returns The list of selected URLs.
+ */
+ KURL::List selectedURLs() const;
+
+ /**
+ * @returns the currently shown directory.
+ */
+ KURL baseURL() const;
+
+ /**
+ * Returns the full path of the selected file in the local filesystem.
+ * (Local files only)
+ */
+ QString selectedFile() const;
+
+ /**
+ * Returns a list of all selected local files.
+ */
+ QStringList selectedFiles() const;
+
+ /**
+ * Sets the directory to view.
+ *
+ * @param url URL to show.
+ * @param clearforward Indicates whether the forward queue
+ * should be cleared.
+ */
+ void setURL(const KURL &url, bool clearforward = true);
+
+ /**
+ * Sets the file name to preselect to @p name
+ *
+ * This takes absolute URLs and relative file names.
+ */
+ void setSelection(const QString& name);
+
+ /**
+ * Sets the operational mode of the filedialog to @p Saving, @p Opening
+ * or @p Other. This will set some flags that are specific to loading
+ * or saving files. E.g. setKeepLocation() makes mostly sense for
+ * a save-as dialog. So setOperationMode( KFileDialog::Saving ); sets
+ * setKeepLocation for example.
+ *
+ * The mode @p Saving, together with a default filter set via
+ * setMimeFilter() will make the filter combobox read-only.
+ *
+ * The default mode is @p Opening.
+ *
+ * Call this method right after instantiating KFileDialog.
+ *
+ * @see operationMode
+ * @see KFileDialog::OperationMode
+ */
+ void setOperationMode( KFileDialog::OperationMode );
+
+ /**
+ * @returns the current operation mode, Opening, Saving or Other. Default
+ * is Other.
+ *
+ * @see operationMode
+ * @see KFileDialog::OperationMode
+ */
+ OperationMode operationMode() const;
+
+ /**
+ * Sets whether the filename/url should be kept when changing directories.
+ * This is for example useful when having a predefined filename where
+ * the full path for that file is searched.
+ *
+ * This is implicitly set when operationMode() is KFileDialog::Saving
+ *
+ * getSaveFileName() and getSaveURL() set this to true by default, so that
+ * you can type in the filename and change the directory without having
+ * to type the name again.
+ */
+ void setKeepLocation( bool keep );
+
+ /**
+ * @returns whether the contents of the location edit are kept when
+ * changing directories.
+ */
+ bool keepsLocation() const;
+
+ /**
+ * Sets the filter to be used to @p filter.
+ *
+ * You can set more
+ * filters for the user to select separated by '\n'. Every
+ * filter entry is defined through namefilter|text to diplay.
+ * If no | is found in the expression, just the namefilter is
+ * shown. Examples:
+ *
+ * \code
+ * kfile->setFilter("*.cpp|C++ Source Files\n*.h|Header files");
+ * kfile->setFilter("*.cpp");
+ * kfile->setFilter("*.cpp|Sources (*.cpp)");
+ * kfile->setFilter("*.cpp|" + i18n("Sources (*.cpp)"));
+ * kfile->setFilter("*.cpp *.cc *.C|C++ Source Files\n*.h *.H|Header files");
+ * \endcode
+ *
+ * Note: The text to display is not parsed in any way. So, if you
+ * want to show the suffix to select by a specific filter, you must
+ * repeat it.
+ *
+ * If the filter contains an unescaped '/', a mimetype-filter is assumed.
+ * If you would like a '/' visible in your filter it can be escaped with
+ * a '\'. You can specify multiple mimetypes like this (separated with
+ * space):
+ *
+ * \code
+ * kfile->setFilter( "image/png text/html text/plain" );
+ * kfile->setFilter( "*.cue|CUE\\/BIN Files (*.cue)" );
+ * \endcode
+ *
+ * @see filterChanged
+ * @see setMimeFilter
+ */
+ void setFilter(const QString& filter);
+
+ /**
+ * Returns the current filter as entered by the user or one of the
+ * predefined set via setFilter().
+ *
+ * @see setFilter()
+ * @see filterChanged()
+ */
+ QString currentFilter() const;
+
+ /**
+ * Sets the filter up to specify the output type.
+ *
+ * @param label the label to use instead of "Filter:"
+ * @param types a list of mimetypes that can be used as output format
+ * @param defaultType the default mimetype to use as output format.
+ *
+ * Do not use in conjunction with setFilter()
+ * @deprecated
+ */
+ void setFilterMimeType(const QString &label, const KMimeType::List &types, const KMimeType::Ptr &defaultType) KDE_DEPRECATED;
+
+ /**
+ * Returns the mimetype for the desired output format.
+ *
+ * This is only valid if setFilterMimeType() has been called
+ * previously.
+ *
+ * @see setFilterMimeType()
+ */
+ KMimeType::Ptr currentFilterMimeType();
+
+ /**
+ * Sets the filter up to specify the output type.
+ *
+ * @param types a list of mimetypes that can be used as output format
+ * @param defaultType the default mimetype to use as output format, if any.
+ * If @p defaultType is set, it will be set as the current item.
+ * Otherwise, a first item showing all the mimetypes will be created.
+ * Typically, @p defaultType should be empty for loading and set for saving.
+ *
+ * Do not use in conjunction with setFilter()
+ */
+ void setMimeFilter( const QStringList& types,
+ const QString& defaultType = QString::null );
+
+ /**
+ * The mimetype for the desired output format.
+ *
+ * This is only valid if setMimeFilter() has been called
+ * previously.
+ *
+ * @see setMimeFilter()
+ */
+ QString currentMimeFilter() const;
+
+ /**
+ * Clears any mime- or namefilter. Does not reload the directory.
+ */
+ void clearFilter();
+
+ /**
+ * @deprecated
+ * Add a preview widget and enter the preview mode.
+ *
+ * In this mode
+ * the dialog is split and the right part contains your widget.
+ * This widget has to inherit QWidget and it has to implement
+ * a slot showPreview(const KURL &); which is called
+ * every time the file changes. You may want to look at
+ * koffice/lib/kofficecore/koFilterManager.cc for some hints :)
+ *
+ * Ownership is transferred to KFileDialog. You need to create the
+ * preview-widget with "new", i.e. on the heap.
+ */
+ void setPreviewWidget(const QWidget *w) KDE_DEPRECATED;
+
+ /**
+ * Adds a preview widget and enters the preview mode.
+ *
+ * In this mode the dialog is split and the right part contains your
+ * preview widget.
+ *
+ * Ownership is transferred to KFileDialog. You need to create the
+ * preview-widget with "new", i.e. on the heap.
+ *
+ * @param w The widget to be used for the preview.
+ */
+ void setPreviewWidget(const KPreviewWidgetBase *w);
+
+ /**
+ * Creates a modal file dialog and return the selected
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static QString getOpenFileName(const QString& startDir= QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent= 0,
+ const QString& caption = QString::null);
+
+
+ /**
+ * Use this version only if you have no QWidget available as
+ * parent widget. This can be the case if the parent widget is
+ * a widget in another process or if the parent widget is a
+ * non-Qt widget. For example, in a GTK program.
+ *
+ * @since 3.4
+ */
+ static QString getOpenFileNameWId(const QString& startDir,
+ const QString& filter,
+ WId parent_id, const QString& caption);
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * filenames or an empty list if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static QStringList getOpenFileNames(const QString& startDir= QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent = 0,
+ const QString& caption= QString::null);
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * URL or an empty string if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing URL.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static KURL getOpenURL(const QString& startDir = QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent= 0,
+ const QString& caption = QString::null);
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * URLs or an empty list if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static KURL::List getOpenURLs(const QString& startDir= QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent = 0,
+ const QString& caption= QString::null);
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with this
+ * method the user need not select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li a relative path or a filename determining the
+ * directory to start in and the file to be selected.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static QString getSaveFileName(const QString& startDir= QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent= 0,
+ const QString& caption = QString::null);
+
+
+ /**
+ * This function accepts the window id of the parent window, instead
+ * of QWidget*. It should be used only when necessary.
+ * @since 3.4
+ */
+ static QString getSaveFileNameWId(const QString& dir, const QString& filter,
+ WId parent_id,
+ const QString& caption);
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with this
+ * method the user need not select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li a relative path or a filename determining the
+ * directory to start in and the file to be selected.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static KURL getSaveURL(const QString& startDir= QString::null,
+ const QString& filter= QString::null,
+ QWidget *parent= 0,
+ const QString& caption = QString::null);
+
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * directory or an empty string if none was chosen.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static QString getExistingDirectory(const QString & startDir = QString::null,
+ QWidget * parent = 0,
+ const QString& caption= QString::null);
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * directory or an empty string if none was chosen.
+ *
+ * Contrary to getExistingDirectory(), this method allows the
+ * selection of a remote directory.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ * @since 3.1
+ */
+ static KURL getExistingURL(const QString & startDir = QString::null,
+ QWidget * parent = 0,
+ const QString& caption= QString::null);
+ /**
+ * Creates a modal file dialog with an image previewer and returns the
+ * selected url or an empty string if none was chosen.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li QString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static KURL getImageOpenURL( const QString& startDir = QString::null,
+ QWidget *parent = 0,
+ const QString& caption = QString::null );
+ virtual void show();
+
+ /**
+ * Convenient overload of the other setMode(unsigned int) method.
+ */
+ void setMode( KFile::Mode m );
+
+ /**
+ * Sets the mode of the dialog.
+ *
+ * The mode is defined as (in kfile.h):
+ * \code
+ * enum Mode {
+ * File = 1,
+ * Directory = 2,
+ * Files = 4,
+ * ExistingOnly = 8,
+ * LocalOnly = 16
+ * };
+ * \endcode
+ * You can OR the values, e.g.
+ * \code
+ * KFile::Mode mode = static_cast<KFile::Mode>( KFile::Files |
+ * KFile::ExistingOnly |
+ * KFile::LocalOnly );
+ * setMode( mode );
+ * \endcode
+ */
+ void setMode( unsigned int m );
+
+ /**
+ * Returns the mode of the filedialog.
+ * @see setMode()
+ */
+ KFile::Mode mode() const;
+
+ /**
+ * Sets the text to be displayed in front of the selection.
+ *
+ * The default is "Location".
+ * Most useful if you want to make clear what
+ * the location is used for.
+ */
+ void setLocationLabel(const QString& text);
+
+ /**
+ * Returns a pointer to the toolbar.
+ *
+ * You can use this to insert custom
+ * items into it, e.g.:
+ * \code
+ * yourAction = new KAction( i18n("Your Action"), 0,
+ * this, SLOT( yourSlot() ),
+ * this, "action name" );
+ * yourAction->plug( kfileDialog->toolBar() );
+ * \endcode
+ */
+ KToolBar *toolBar() const { return toolbar; }
+
+ /**
+ * @returns a pointer to the OK-Button in the filedialog. You may use it
+ * e.g. to set a custom text to it.
+ */
+ KPushButton *okButton() const;
+
+ /**
+ * @returns a pointer to the Cancel-Button in the filedialog. You may use
+ * it e.g. to set a custom text to it.
+ */
+ KPushButton *cancelButton() const;
+
+ /**
+ * @returns the KURLBar object used as the "speed bar". You can add custom
+ * entries to it like that:
+ * \code
+ * KURLBar *urlBar = fileDialog->speedBar();
+ * if ( urlBar )
+ * urlBar->insertDynamicItem( someURL, i18n("The URL's description") );
+ * \endcode
+ *
+ * Note that this method may return a null-pointer if the user configured
+ * to not use the speed-bar.
+ * @see KURLBar
+ * @see KURLBar::insertDynamicItem
+ * @since 3.2
+ */
+ KURLBar *speedBar();
+
+ /**
+ * @returns a pointer to the action collection, holding all the used
+ * KActions.
+ */
+ KActionCollection *actionCollection() const;
+
+ /**
+ * @returns the index of the path combobox so when inserting widgets into
+ * the dialog (e.g. subclasses) they can do so without hardcoding in an index
+ */
+ int pathComboIndex();
+
+ /**
+ * This method implements the logic to determine the user's default directory
+ * to be listed. E.g. the documents direcory, home directory or a recently
+ * used directory.
+ * @param startDir A url/directory, to be used. May use the ':' and '::' syntax
+ * as documented in the KFileDialog() constructor.
+ * @param recentDirClass If the ':' or '::' syntax is used, recentDirClass
+ * will contain the string to be used later for KRecentDir::dir()
+ * @return The URL that should be listed by default (e.g. by KFileDialog or
+ * KDirSelectDialog).
+ * @since 3.1
+ */
+ static KURL getStartURL( const QString& startDir, QString& recentDirClass );
+
+ /**
+ * @internal
+ * Used by KDirSelectDialog to share the dialog's start directory.
+ */
+ static void setStartDir( const KURL& directory );
+
+signals:
+ /**
+ * Emitted when the user selects a file. It is only emitted in single-
+ * selection mode. The best way to get notified about selected file(s)
+ * is to connect to the okClicked() signal inherited from KDialogBase
+ * and call selectedFile(), selectedFiles(),
+ * selectedURL() or selectedURLs().
+ */
+ void fileSelected(const QString&);
+
+ /**
+ * Emitted when the user highlights a file.
+ */
+ void fileHighlighted(const QString&);
+
+ /**
+ * Emitted when the user hilights one or more files in multiselection mode.
+ *
+ * Note: fileHighlighted() or fileSelected() are @em not
+ * emitted in multiselection mode. You may use selectedItems() to
+ * ask for the current highlighted items.
+ * @see fileSelected
+ */
+ void selectionChanged();
+
+ /**
+ * Emitted when the filter changed, i.e. the user entered an own filter
+ * or chose one of the predefined set via setFilter().
+ *
+ * @param filter contains the new filter (only the extension part,
+ * not the explanation), i.e. "*.cpp" or "*.cpp *.cc".
+ *
+ * @see setFilter()
+ * @see currentFilter()
+ */
+ void filterChanged( const QString& filter );
+
+protected:
+ KToolBar *toolbar;
+
+ static KURL *lastDirectory;
+
+ KURLComboBox *locationEdit;
+
+ KFileFilterCombo *filterWidget;
+
+ /**
+ * Reimplemented to animate the cancel button.
+ */
+ virtual void keyPressEvent( QKeyEvent *e );
+
+ /**
+ * Perform basic initialization tasks. Called by constructors.
+ * @since 3.1
+ */
+ void init(const QString& startDir, const QString& filter, QWidget* widget);
+
+ /**
+ * rebuild geometry management.
+ *
+ */
+ virtual void initGUI();
+
+ /**
+ * called when an item is highlighted/selected in multiselection mode.
+ * handles setting the locationEdit.
+ */
+ void multiSelectionChanged();
+
+ /**
+ * Reads configuration and applies it (size, recent directories, ...)
+ */
+ virtual void readConfig( KConfig *, const QString& group = QString::null );
+
+ /**
+ * Saves the current configuration
+ */
+ virtual void writeConfig( KConfig *, const QString& group = QString::null );
+
+ /**
+ * Reads the recent used files and inserts them into the location combobox
+ */
+ virtual void readRecentFiles( KConfig * );
+
+ /**
+ * Saves the entries from the location combobox.
+ */
+ virtual void saveRecentFiles( KConfig * );
+
+ /**
+ * Parses the string "line" for files. If line doesn't contain any ", the
+ * whole line will be interpreted as one file. If the number of " is odd,
+ * an empty list will be returned. Otherwise, all items enclosed in " "
+ * will be returned as correct urls.
+ */
+ KURL::List tokenize(const QString& line) const;
+
+ /**
+ * Returns the absolute version of the URL specified in locationEdit.
+ * @since 3.2
+ */
+ KURL getCompleteURL(const QString&);
+
+ /**
+ * Returns the filename extension associated with the currentFilter().
+ * QString::null is returned if an extension is not available or if
+ * operationMode() != Saving.
+ * @since 3.2
+ */
+ QString currentFilterExtension();
+
+ /**
+ * Updates the currentFilterExtension and the availability of the
+ * Automatically Select Extension Checkbox (visible if operationMode()
+ * == Saving and enabled if an extension _will_ be associated with the
+ * currentFilter(), _after_ this call). You should call this after
+ * filterWidget->setCurrentItem().
+ * @since 3.2
+ */
+ void updateAutoSelectExtension();
+
+
+protected slots:
+ void urlEntered( const KURL& );
+ void enterURL( const KURL& url );
+ void enterURL( const QString& url );
+ void locationActivated( const QString& url );
+
+ /**
+ * @deprecated,
+ */
+ // ### remove in KDE4
+ void toolbarCallback(int);
+ /**
+ * @deprecated
+ */
+ // ### remove in KDE4
+ void pathComboChanged( const QString& );
+ /**
+ * @deprecated
+ */
+ // ### remove in KDE4
+ void dirCompletion( const QString& );
+
+ void slotFilterChanged();
+ void fileHighlighted(const KFileItem *i);
+ void fileSelected(const KFileItem *i);
+ void slotStatResult(KIO::Job* job);
+ void slotLoadingFinished();
+
+ void fileCompletion( const QString& );
+ /**
+ * @since 3.1
+ */
+ void toggleSpeedbar( bool );
+
+ /**
+ * @since 3.4
+ */
+ void toggleBookmarks(bool show);
+
+ /**
+ * @deprecated
+ */
+ virtual void updateStatusLine(int dirs, int files);
+
+ virtual void slotOk();
+ virtual void accept();
+ virtual void slotCancel();
+
+ void slotAutoSelectExtClicked();
+ void addToRecentDocuments();
+ void initSpeedbar();
+
+private slots:
+ void slotLocationChanged( const QString& text );
+
+private:
+ KFileDialog(const KFileDialog&);
+ KFileDialog operator=(const KFileDialog&);
+
+ void setLocationText( const QString& text );
+ void updateLocationWhatsThis();
+
+ void appendExtension(KURL &url);
+ void updateLocationEditExtension(const QString &);
+ void updateFilter();
+
+ static void initStatic();
+
+ void setNonExtSelection();
+
+protected:
+ KDirOperator *ops;
+ bool autoDirectoryFollowing;
+
+ KURL::List& parseSelectedURLs() const;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KFileDialogPrivate *d;
+};
+
+#endif
diff --git a/kio/kfile/kfilefiltercombo.cpp b/kio/kfile/kfilefiltercombo.cpp
new file mode 100644
index 000000000..747a738fe
--- /dev/null
+++ b/kio/kfile/kfilefiltercombo.cpp
@@ -0,0 +1,203 @@
+/* This file is part of the KDE libraries
+ Copyright (C) Stephan Kulow <coolo@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+#include <config-kfile.h>
+
+#include "kfilefiltercombo.h"
+
+class KFileFilterCombo::KFileFilterComboPrivate
+{
+public:
+ KFileFilterComboPrivate() {
+ hasAllSupportedFiles = false;
+ defaultFilter = i18n("*|All Files");
+ isMimeFilter = false;
+ }
+
+ // when we have more than 3 mimefilters and no default-filter,
+ // we don't show the comments of all mimefilters in one line,
+ // instead we show "All supported files". We have to translate
+ // that back to the list of mimefilters in currentFilter() tho.
+ bool hasAllSupportedFiles;
+ // true when setMimeFilter was called
+ bool isMimeFilter;
+ QString lastFilter;
+ QString defaultFilter;
+};
+
+KFileFilterCombo::KFileFilterCombo( QWidget *parent, const char *name)
+ : KComboBox(true, parent, name), d( new KFileFilterComboPrivate )
+{
+ setTrapReturnKey( true );
+ setInsertionPolicy(NoInsertion);
+ connect( this, SIGNAL( activated( int )), this, SIGNAL( filterChanged() ));
+ connect( this, SIGNAL( returnPressed() ), this, SIGNAL( filterChanged() ));
+ connect( this, SIGNAL( filterChanged() ), SLOT( slotFilterChanged() ));
+ m_allTypes = false;
+}
+
+KFileFilterCombo::~KFileFilterCombo()
+{
+ delete d;
+}
+
+void KFileFilterCombo::setFilter(const QString& filter)
+{
+ clear();
+ filters.clear();
+ d->hasAllSupportedFiles = false;
+
+ if (!filter.isEmpty()) {
+ QString tmp = filter;
+ int index = tmp.find('\n');
+ while (index > 0) {
+ filters.append(tmp.left(index));
+ tmp = tmp.mid(index + 1);
+ index = tmp.find('\n');
+ }
+ filters.append(tmp);
+ }
+ else
+ filters.append( d->defaultFilter );
+
+ QStringList::ConstIterator it;
+ QStringList::ConstIterator end(filters.end());
+ for (it = filters.begin(); it != end; ++it) {
+ int tab = (*it).find('|');
+ insertItem((tab < 0) ? *it :
+ (*it).mid(tab + 1));
+ }
+
+ d->lastFilter = currentText();
+ d->isMimeFilter = false;
+}
+
+QString KFileFilterCombo::currentFilter() const
+{
+ QString f = currentText();
+ if (f == text(currentItem())) { // user didn't edit the text
+ f = *filters.at(currentItem());
+ if ( d->isMimeFilter || (currentItem() == 0 && d->hasAllSupportedFiles) ) {
+ return f; // we have a mimetype as filter
+ }
+ }
+
+ int tab = f.find('|');
+ if (tab < 0)
+ return f;
+ else
+ return f.left(tab);
+}
+
+void KFileFilterCombo::setCurrentFilter( const QString& filter )
+{
+ int pos = 0;
+ for( QStringList::ConstIterator it = filters.begin();
+ it != filters.end();
+ ++it, ++pos ) {
+ if( *it == filter ) {
+ setCurrentItem( pos );
+ filterChanged();
+ return;
+ }
+ }
+ setCurrentText( filter );
+ filterChanged();
+}
+
+void KFileFilterCombo::setMimeFilter( const QStringList& types,
+ const QString& defaultType )
+{
+ clear();
+ filters.clear();
+ QString delim = QString::fromLatin1(", ");
+ d->hasAllSupportedFiles = false;
+
+ m_allTypes = defaultType.isEmpty() && (types.count() > 1);
+
+ QString allComments, allTypes;
+ int i = 0;
+ for(QStringList::ConstIterator it = types.begin(); it != types.end(); ++it, ++i)
+ {
+ if ( m_allTypes && it != types.begin() ) {
+ allComments += delim;
+ allTypes += ' ';
+ }
+
+ kdDebug(kfile_area) << *it << endl;
+ KMimeType::Ptr type = KMimeType::mimeType( *it );
+ filters.append( type->name() );
+ if ( m_allTypes )
+ {
+ allTypes += type->name();
+ allComments += type->comment();
+ }
+ insertItem( type->comment() );
+ if ( type->name() == defaultType )
+ setCurrentItem( i );
+ }
+
+ if ( m_allTypes )
+ {
+ if ( i < 3 ) // show the mime-comments of at max 3 types
+ insertItem( allComments, 0 );
+ else {
+ insertItem( i18n("All Supported Files"), 0 );
+ d->hasAllSupportedFiles = true;
+ }
+
+ filters.prepend( allTypes );
+ }
+
+ d->lastFilter = currentText();
+ d->isMimeFilter = true;
+}
+
+void KFileFilterCombo::slotFilterChanged()
+{
+ d->lastFilter = currentText();
+}
+
+bool KFileFilterCombo::eventFilter( QObject *o, QEvent *e )
+{
+ if ( o == lineEdit() && e->type() == QEvent::FocusOut ) {
+ if ( currentText() != d->lastFilter )
+ emit filterChanged();
+ }
+
+ return KComboBox::eventFilter( o, e );
+}
+
+void KFileFilterCombo::setDefaultFilter( const QString& filter )
+{
+ d->defaultFilter = filter;
+}
+
+QString KFileFilterCombo::defaultFilter() const
+{
+ return d->defaultFilter;
+}
+
+void KFileFilterCombo::virtual_hook( int id, void* data )
+{ KComboBox::virtual_hook( id, data ); }
+
+#include "kfilefiltercombo.moc"
diff --git a/kio/kfile/kfilefiltercombo.h b/kio/kfile/kfilefiltercombo.h
new file mode 100644
index 000000000..9b7c103bf
--- /dev/null
+++ b/kio/kfile/kfilefiltercombo.h
@@ -0,0 +1,104 @@
+/* This file is part of the KDE libraries
+ Copyright (C) Stephan Kulow <coolo@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFILEFILTERCOMBO_H
+#define KFILEFILTERCOMBO_H
+
+#include <qstringlist.h>
+#include <qptrdict.h>
+
+#include <kcombobox.h>
+#include <kmimetype.h>
+
+class KFileFilterComboPrivate;
+
+class KIO_EXPORT KFileFilterCombo : public KComboBox
+{
+ Q_OBJECT
+
+ public:
+ KFileFilterCombo(QWidget *parent= 0, const char *name= 0);
+ ~KFileFilterCombo();
+
+ void setFilter(const QString& filter);
+
+ /**
+ * @returns the current filter, either something like "*.cpp *.h"
+ * or the current mimetype, like "text/html", or a list of those, like
+ " "text/html text/plain image/png", all separated with one space.
+ */
+ QString currentFilter() const;
+
+ /**
+ * Sets the current filter. Filter must match one of the filter items
+ * passed before to this widget.
+ * @since 3.4
+ */
+ void setCurrentFilter( const QString& filter );
+
+ /**
+ * Sets a list of mimetypes.
+ * If @p defaultType is set, it will be set as the current item.
+ * Otherwise, a first item showing all the mimetypes will be created.
+ */
+ void setMimeFilter( const QStringList& types, const QString& defaultType );
+
+ /**
+ * @return true if the filter's first item is the list of all mimetypes
+ */
+ bool showsAllTypes() const { return m_allTypes; }
+
+ /**
+ * This method allows you to set a default-filter, that is used when an
+ * empty filter is set. Make sure you call this before calling
+ * setFilter().
+ *
+ * By default, this is set to i18n("*|All Files")
+ * @see defaultFilter
+ */
+ void setDefaultFilter( const QString& filter );
+
+ /**
+ * @return the default filter, used when an empty filter is set.
+ * @see setDefaultFilter
+ */
+ QString defaultFilter() const;
+
+ protected:
+ virtual bool eventFilter( QObject *o, QEvent *e );
+
+// KDE4: those variables are private. filters() was added
+ QStringList filters;
+ bool m_allTypes;
+
+ signals:
+ void filterChanged();
+
+private slots:
+ void slotFilterChanged();
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ friend class KFileDialog; // gone in KDE4
+ class KFileFilterComboPrivate;
+ KFileFilterComboPrivate *d;
+};
+
+#endif
diff --git a/kio/kfile/kfileiconview.cpp b/kio/kfile/kfileiconview.cpp
new file mode 100644
index 000000000..0668e91e2
--- /dev/null
+++ b/kio/kfile/kfileiconview.cpp
@@ -0,0 +1,942 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
+ 2000,2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qfontmetrics.h>
+#include <qkeycode.h>
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qregexp.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kfileitem.h>
+#include <kiconeffect.h>
+#include <kglobalsettings.h>
+#include <kurldrag.h>
+#include <kio/previewjob.h>
+
+#include "kfileiconview.h"
+#include "config-kfile.h"
+
+#define DEFAULT_PREVIEW_SIZE 60
+#define DEFAULT_SHOW_PREVIEWS false
+#define DEFAULT_VIEW_MODE "SmallColumns"
+
+KFileIconViewItem::~KFileIconViewItem()
+{
+ fileInfo()->removeExtraData( iconView() );
+}
+
+class KFileIconView::KFileIconViewPrivate
+{
+public:
+ KFileIconViewPrivate( KFileIconView *parent ) {
+ previewIconSize = 60;
+ job = 0;
+ dropItem = 0;
+
+ noArrangement = false;
+ ignoreMaximumSize = false;
+ smallColumns = new KRadioAction( i18n("Small Icons"), 0, parent,
+ SLOT( slotSmallColumns() ),
+ parent->actionCollection(),
+ "small columns" );
+
+ largeRows = new KRadioAction( i18n("Large Icons"), 0, parent,
+ SLOT( slotLargeRows() ),
+ parent->actionCollection(),
+ "large rows" );
+
+ smallColumns->setExclusiveGroup(QString::fromLatin1("IconView mode"));
+ largeRows->setExclusiveGroup(QString::fromLatin1("IconView mode"));
+
+ previews = new KToggleAction( i18n("Thumbnail Previews"), 0,
+ parent->actionCollection(),
+ "show previews" );
+ zoomIn = KStdAction::zoomIn( parent, SLOT( zoomIn() ),
+ parent->actionCollection(), "zoomIn" );
+ zoomOut = KStdAction::zoomOut( parent, SLOT( zoomOut() ),
+ parent->actionCollection(), "zoomOut" );
+
+ previews->setGroup("previews");
+ zoomIn->setGroup("previews");
+ zoomOut->setGroup("previews");
+
+ connect( previews, SIGNAL( toggled( bool )),
+ parent, SLOT( slotPreviewsToggled( bool )));
+
+ connect( &previewTimer, SIGNAL( timeout() ),
+ parent, SLOT( showPreviews() ));
+ connect( &autoOpenTimer, SIGNAL( timeout() ),
+ parent, SLOT( slotAutoOpen() ));
+ }
+
+ ~KFileIconViewPrivate() {
+ if ( job )
+ job->kill();
+ }
+
+ KRadioAction *smallColumns, *largeRows;
+ KAction *zoomIn, *zoomOut;
+ KToggleAction *previews;
+ KIO::PreviewJob *job;
+ KFileIconViewItem *dropItem;
+ QTimer previewTimer;
+ QTimer autoOpenTimer;
+ QStringList previewMimeTypes;
+ int previewIconSize;
+ bool noArrangement :1;
+ bool ignoreMaximumSize :1;
+};
+
+KFileIconView::KFileIconView(QWidget *parent, const char *name)
+ : KIconView(parent, name), KFileView()
+{
+ d = new KFileIconViewPrivate( this );
+
+ setViewName( i18n("Icon View") );
+
+ toolTip = 0;
+ setResizeMode( Adjust );
+ setMaxItemWidth( 300 );
+ setWordWrapIconText( false );
+ setArrangement( TopToBottom );
+ setAutoArrange( true );
+ setItemsMovable( false );
+ setMode( KIconView::Select );
+ KIconView::setSorting( true );
+ // as long as QIconView only shows tooltips when the cursor is over the
+ // icon (and not the text), we have to create our own tooltips
+ setShowToolTips( false );
+ slotSmallColumns();
+ d->smallColumns->setChecked( true );
+
+ connect( this, SIGNAL( returnPressed(QIconViewItem *) ),
+ SLOT( slotActivate( QIconViewItem *) ) );
+
+ // we want single click _and_ double click (as convenience)
+ connect( this, SIGNAL( clicked(QIconViewItem *, const QPoint&) ),
+ SLOT( selected( QIconViewItem *) ) );
+ connect( this, SIGNAL( doubleClicked(QIconViewItem *, const QPoint&) ),
+ SLOT( slotActivate( QIconViewItem *) ) );
+
+ connect( this, SIGNAL( onItem( QIconViewItem * ) ),
+ SLOT( showToolTip( QIconViewItem * ) ) );
+ connect( this, SIGNAL( onViewport() ),
+ SLOT( removeToolTip() ) );
+ connect( this, SIGNAL( contextMenuRequested(QIconViewItem*,const QPoint&)),
+ SLOT( slotActivateMenu( QIconViewItem*, const QPoint& ) ) );
+
+ KFile::SelectionMode sm = KFileView::selectionMode();
+ switch ( sm ) {
+ case KFile::Multi:
+ QIconView::setSelectionMode( QIconView::Multi );
+ break;
+ case KFile::Extended:
+ QIconView::setSelectionMode( QIconView::Extended );
+ break;
+ case KFile::NoSelection:
+ QIconView::setSelectionMode( QIconView::NoSelection );
+ break;
+ default: // fall through
+ case KFile::Single:
+ QIconView::setSelectionMode( QIconView::Single );
+ break;
+ }
+
+ if ( sm == KFile::Multi || sm == KFile::Extended )
+ connect( this, SIGNAL( selectionChanged() ),
+ SLOT( slotSelectionChanged() ));
+ else
+ connect( this, SIGNAL( selectionChanged( QIconViewItem * )),
+ SLOT( highlighted( QIconViewItem * )));
+
+ viewport()->installEventFilter( this );
+
+ // for mimetype resolving
+ m_resolver = new KMimeTypeResolver<KFileIconViewItem,KFileIconView>(this);
+}
+
+KFileIconView::~KFileIconView()
+{
+ delete m_resolver;
+ removeToolTip();
+ delete d;
+}
+
+void KFileIconView::readConfig( KConfig *kc, const QString& group )
+{
+ QString gr = group.isEmpty() ? QString("KFileIconView") : group;
+ KConfigGroupSaver cs( kc, gr );
+ QString small = QString::fromLatin1("SmallColumns");
+ d->previewIconSize = kc->readNumEntry( "Preview Size", DEFAULT_PREVIEW_SIZE );
+ d->previews->setChecked( kc->readBoolEntry( "ShowPreviews", DEFAULT_SHOW_PREVIEWS ) );
+
+ if ( kc->readEntry("ViewMode", DEFAULT_VIEW_MODE ) == small ) {
+ d->smallColumns->setChecked( true );
+ slotSmallColumns();
+ }
+ else {
+ d->largeRows->setChecked( true );
+ slotLargeRows();
+ }
+
+ if ( d->previews->isChecked() )
+ showPreviews();
+}
+
+void KFileIconView::writeConfig( KConfig *kc, const QString& group )
+{
+ QString gr = group.isEmpty() ? QString("KFileIconView") : group;
+ KConfigGroupSaver cs( kc, gr );
+
+ QString viewMode = d->smallColumns->isChecked() ?
+ QString::fromLatin1("SmallColumns") :
+ QString::fromLatin1("LargeRows");
+ if(!kc->hasDefault( "ViewMode" ) && viewMode == DEFAULT_VIEW_MODE )
+ kc->revertToDefault( "ViewMode" );
+ else
+ kc->writeEntry( "ViewMode", viewMode );
+
+ int previewsIconSize = d->previewIconSize;
+ if(!kc->hasDefault( "Preview Size" ) && previewsIconSize == DEFAULT_PREVIEW_SIZE )
+ kc->revertToDefault( "Preview Size" );
+ else
+ kc->writeEntry( "Preview Size", previewsIconSize );
+
+ bool showPreviews = d->previews->isChecked();
+ if(!kc->hasDefault( "ShowPreviews" ) && showPreviews == DEFAULT_SHOW_PREVIEWS )
+ kc->revertToDefault( "ShowPreviews" );
+ else
+ kc->writeEntry( "ShowPreviews", showPreviews );
+}
+
+void KFileIconView::removeToolTip()
+{
+ delete toolTip;
+ toolTip = 0;
+}
+
+void KFileIconView::showToolTip( QIconViewItem *item )
+{
+ delete toolTip;
+ toolTip = 0;
+
+ if ( !item )
+ return;
+
+ int w = maxItemWidth() - ( itemTextPos() == QIconView::Bottom ? 0 :
+ item->pixmapRect().width() ) - 4;
+ if ( fontMetrics().width( item->text() ) >= w ) {
+ toolTip = new QLabel( QString::fromLatin1(" %1 ").arg(item->text()), 0,
+ "myToolTip",
+ WStyle_StaysOnTop | WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WX11BypassWM );
+ toolTip->setFrameStyle( QFrame::Plain | QFrame::Box );
+ toolTip->setLineWidth( 1 );
+ toolTip->setAlignment( AlignLeft | AlignTop );
+ toolTip->move( QCursor::pos() + QPoint( 14, 14 ) );
+ toolTip->adjustSize();
+ QRect screen = QApplication::desktop()->screenGeometry(
+ QApplication::desktop()->screenNumber(QCursor::pos()));
+ if (toolTip->x()+toolTip->width() > screen.right()) {
+ toolTip->move(toolTip->x()+screen.right()-toolTip->x()-toolTip->width(), toolTip->y());
+ }
+ if (toolTip->y()+toolTip->height() > screen.bottom()) {
+ toolTip->move(toolTip->x(), screen.bottom()-toolTip->y()-toolTip->height()+toolTip->y());
+ }
+ toolTip->setFont( QToolTip::font() );
+ toolTip->setPalette( QToolTip::palette(), true );
+ toolTip->show();
+ }
+}
+
+void KFileIconView::slotActivateMenu( QIconViewItem* item, const QPoint& pos )
+{
+ if ( !item ) {
+ sig->activateMenu( 0, pos );
+ return;
+ }
+ KFileIconViewItem *i = (KFileIconViewItem*) item;
+ sig->activateMenu( i->fileInfo(), pos );
+}
+
+void KFileIconView::hideEvent( QHideEvent *e )
+{
+ removeToolTip();
+ KIconView::hideEvent( e );
+}
+
+void KFileIconView::keyPressEvent( QKeyEvent *e )
+{
+ KIconView::keyPressEvent( e );
+
+ // ignore Ctrl-Return so that the dialog can catch it.
+ if ( (e->state() & ControlButton) &&
+ (e->key() == Key_Return || e->key() == Key_Enter) )
+ e->ignore();
+}
+
+void KFileIconView::setSelected( const KFileItem *info, bool enable )
+{
+ KFileIconViewItem *item = viewItem( info );
+ if ( item )
+ KIconView::setSelected( item, enable, true );
+}
+
+void KFileIconView::selectAll()
+{
+ if (KFileView::selectionMode() == KFile::NoSelection ||
+ KFileView::selectionMode() == KFile::Single)
+ return;
+
+ KIconView::selectAll( true );
+}
+
+void KFileIconView::clearSelection()
+{
+ KIconView::clearSelection();
+}
+
+void KFileIconView::invertSelection()
+{
+ KIconView::invertSelection();
+}
+
+void KFileIconView::clearView()
+{
+ m_resolver->m_lstPendingMimeIconItems.clear();
+
+ KIconView::clear();
+ stopPreview();
+}
+
+void KFileIconView::insertItem( KFileItem *i )
+{
+ KFileView::insertItem( i );
+
+ QIconView* qview = static_cast<QIconView*>( this );
+ // Since creating and initializing an item leads to a repaint,
+ // we disable updates on the IconView for a while.
+ qview->setUpdatesEnabled( false );
+ KFileIconViewItem *item = new KFileIconViewItem( qview, i );
+ initItem( item, i, true );
+ qview->setUpdatesEnabled( true );
+
+ if ( !i->isMimeTypeKnown() )
+ m_resolver->m_lstPendingMimeIconItems.append( item );
+
+ i->setExtraData( this, item );
+}
+
+void KFileIconView::slotActivate( QIconViewItem *item )
+{
+ if ( !item )
+ return;
+ const KFileItem *fi = ( (KFileIconViewItem*)item )->fileInfo();
+ if ( fi )
+ sig->activate( fi );
+}
+
+void KFileIconView::selected( QIconViewItem *item )
+{
+ if ( !item || (KApplication::keyboardMouseState() & (ShiftButton | ControlButton)) != 0 )
+ return;
+
+ if ( KGlobalSettings::singleClick() ) {
+ const KFileItem *fi = ( (KFileIconViewItem*)item )->fileInfo();
+ if ( fi && (fi->isDir() || !onlyDoubleClickSelectsFiles()) )
+ sig->activate( fi );
+ }
+}
+
+void KFileIconView::setCurrentItem( const KFileItem *item )
+{
+ KFileIconViewItem *it = viewItem( item );
+ if ( it )
+ KIconView::setCurrentItem( it );
+}
+
+KFileItem * KFileIconView::currentFileItem() const
+{
+ KFileIconViewItem *current = static_cast<KFileIconViewItem*>( currentItem() );
+ if ( current )
+ return current->fileInfo();
+
+ return 0L;
+}
+
+void KFileIconView::highlighted( QIconViewItem *item )
+{
+ if ( !item )
+ return;
+ const KFileItem *fi = ( (KFileIconViewItem*)item )->fileInfo();
+ if ( fi )
+ sig->highlightFile( fi );
+}
+
+void KFileIconView::setSelectionMode( KFile::SelectionMode sm )
+{
+ disconnect( SIGNAL( selectionChanged() ), this );
+ disconnect( SIGNAL( selectionChanged( QIconViewItem * )), this );
+
+ KFileView::setSelectionMode( sm );
+ switch ( KFileView::selectionMode() ) {
+ case KFile::Multi:
+ QIconView::setSelectionMode( QIconView::Multi );
+ break;
+ case KFile::Extended:
+ QIconView::setSelectionMode( QIconView::Extended );
+ break;
+ case KFile::NoSelection:
+ QIconView::setSelectionMode( QIconView::NoSelection );
+ break;
+ default: // fall through
+ case KFile::Single:
+ QIconView::setSelectionMode( QIconView::Single );
+ break;
+ }
+
+ if ( sm == KFile::Multi || sm == KFile::Extended )
+ connect( this, SIGNAL( selectionChanged() ),
+ SLOT( slotSelectionChanged() ));
+ else
+ connect( this, SIGNAL( selectionChanged( QIconViewItem * )),
+ SLOT( highlighted( QIconViewItem * )));
+}
+
+bool KFileIconView::isSelected( const KFileItem *i ) const
+{
+ KFileIconViewItem *item = viewItem( i );
+ return (item && item->isSelected());
+}
+
+void KFileIconView::updateView( bool b )
+{
+ if ( !b )
+ return; // eh?
+
+ KFileIconViewItem *item = static_cast<KFileIconViewItem*>(QIconView::firstItem());
+ if ( item ) {
+ do {
+ if ( d->previews->isChecked() ) {
+ if ( canPreview( item->fileInfo() ) )
+ item->setPixmapSize( QSize( d->previewIconSize, d->previewIconSize ) );
+ }
+ else {
+ // unset pixmap size (used for previews)
+ if ( !item->pixmapSize().isNull() )
+ item->setPixmapSize( QSize( 0, 0 ) );
+ }
+ // recalculate item parameters but avoid an in-place repaint
+ item->setPixmap( (item->fileInfo())->pixmap( myIconSize ), true, false );
+ item = static_cast<KFileIconViewItem *>(item->nextItem());
+ } while ( item != 0L );
+ }
+}
+
+void KFileIconView::updateView( const KFileItem *i )
+{
+ KFileIconViewItem *item = viewItem( i );
+ if ( item )
+ initItem( item, i, true );
+}
+
+void KFileIconView::removeItem( const KFileItem *i )
+{
+ if ( !i )
+ return;
+
+ if ( d->job )
+ d->job->removeItem( i );
+
+ KFileIconViewItem *item = viewItem( i );
+ m_resolver->m_lstPendingMimeIconItems.remove( item );
+ delete item;
+
+ KFileView::removeItem( i );
+}
+
+void KFileIconView::setIconSize( int size )
+{
+ myIconSize = size;
+ updateIcons();
+}
+
+void KFileIconView::setPreviewSize( int size )
+{
+ if ( size < 30 )
+ size = 30; // minimum
+
+ d->previewIconSize = size;
+ if ( d->previews->isChecked() )
+ showPreviews();
+}
+
+void KFileIconView::setIgnoreMaximumSize(bool ignoreSize)
+{
+ d->ignoreMaximumSize = ignoreSize;
+}
+
+void KFileIconView::updateIcons()
+{
+ updateView( true );
+ arrangeItemsInGrid();
+}
+
+void KFileIconView::ensureItemVisible( const KFileItem *i )
+{
+ KFileIconViewItem *item = viewItem( i );
+ if ( item )
+ KIconView::ensureItemVisible( item );
+}
+
+void KFileIconView::slotSelectionChanged()
+{
+ sig->highlightFile( 0L );
+}
+
+void KFileIconView::slotSmallColumns()
+{
+ // setItemTextPos(), setArrangement(), setWordWrapIconText() and
+ // setIconSize() all call arrangeItemsInGrid() :( Prevent this.
+ d->noArrangement = true; // stop arrangeItemsInGrid()!
+
+ // Make sure to uncheck previews if selected
+ if ( d->previews->isChecked() )
+ {
+ stopPreview();
+ d->previews->setChecked( false );
+ }
+ setGridX( -1 );
+ setMaxItemWidth( 300 );
+ setItemTextPos( Right );
+ setArrangement( TopToBottom );
+ setWordWrapIconText( false );
+ setSpacing( 0 );
+
+ d->noArrangement = false; // now we can arrange
+ setIconSize( KIcon::SizeSmall );
+}
+
+void KFileIconView::slotLargeRows()
+{
+ // setItemTextPos(), setArrangement(), setWordWrapIconText() and
+ // setIconSize() all call arrangeItemsInGrid() :( Prevent this.
+ d->noArrangement = true; // stop arrangeItemsInGrid()!
+
+ setGridX( KGlobal::iconLoader()->currentSize( KIcon::Desktop ) + 50 );
+ setItemTextPos( Bottom );
+ setArrangement( LeftToRight );
+ setWordWrapIconText( true );
+ setSpacing( 5 ); // default in QIconView
+
+ d->noArrangement = false; // now we can arrange
+ setIconSize( KIcon::SizeMedium );
+}
+
+void KFileIconView::stopPreview()
+{
+ if ( d->job ) {
+ d->job->kill();
+ d->job = 0L;
+ }
+}
+
+void KFileIconView::slotPreviewsToggled( bool on )
+{
+ if ( on )
+ showPreviews();
+ else {
+ stopPreview();
+ slotLargeRows();
+ }
+}
+
+void KFileIconView::showPreviews()
+{
+ if ( d->previewMimeTypes.isEmpty() )
+ d->previewMimeTypes = KIO::PreviewJob::supportedMimeTypes();
+
+ stopPreview();
+ d->previews->setChecked( true );
+
+ if ( !d->largeRows->isChecked() ) {
+ d->largeRows->setChecked( true );
+ slotLargeRows(); // also sets the icon size and updates the grid
+ }
+ else {
+ updateIcons();
+ }
+
+ d->job = KIO::filePreview(*items(), d->previewIconSize,d->previewIconSize);
+ d->job->setIgnoreMaximumSize(d->ignoreMaximumSize);
+
+ connect( d->job, SIGNAL( result( KIO::Job * )),
+ this, SLOT( slotPreviewResult( KIO::Job * )));
+ connect( d->job, SIGNAL( gotPreview( const KFileItem*, const QPixmap& )),
+ SLOT( gotPreview( const KFileItem*, const QPixmap& ) ));
+// connect( d->job, SIGNAL( failed( const KFileItem* )),
+// this, SLOT( slotFailed( const KFileItem* ) ));
+}
+
+void KFileIconView::slotPreviewResult( KIO::Job *job )
+{
+ if ( job == d->job )
+ d->job = 0L;
+}
+
+void KFileIconView::gotPreview( const KFileItem *item, const QPixmap& pix )
+{
+ KFileIconViewItem *it = viewItem( item );
+ if ( it )
+ if( item->overlays() & KIcon::HiddenOverlay )
+ {
+ QPixmap p( pix );
+
+ KIconEffect::semiTransparent( p );
+ it->setPixmap( p );
+ }
+ else
+ it->setPixmap( pix );
+}
+
+bool KFileIconView::canPreview( const KFileItem *item ) const
+{
+ QStringList::Iterator it = d->previewMimeTypes.begin();
+ QRegExp r;
+ r.setWildcard( true );
+
+ for ( ; it != d->previewMimeTypes.end(); ++it ) {
+ QString type = *it;
+ // the "mimetype" can be "image/*"
+ if ( type.at( type.length() - 1 ) == '*' ) {
+ r.setPattern( type );
+ if ( r.search( item->mimetype() ) != -1 )
+ return true;
+ }
+ else
+ if ( item->mimetype() == type )
+ return true;
+ }
+
+ return false;
+}
+
+KFileItem * KFileIconView::firstFileItem() const
+{
+ KFileIconViewItem *item = static_cast<KFileIconViewItem*>( firstItem() );
+ if ( item )
+ return item->fileInfo();
+ return 0L;
+}
+
+KFileItem * KFileIconView::nextItem( const KFileItem *fileItem ) const
+{
+ if ( fileItem ) {
+ KFileIconViewItem *item = viewItem( fileItem );
+ if ( item && item->nextItem() )
+ return ((KFileIconViewItem*) item->nextItem())->fileInfo();
+ }
+ return 0L;
+}
+
+KFileItem * KFileIconView::prevItem( const KFileItem *fileItem ) const
+{
+ if ( fileItem ) {
+ KFileIconViewItem *item = viewItem( fileItem );
+ if ( item && item->prevItem() )
+ return ((KFileIconViewItem*) item->prevItem())->fileInfo();
+ }
+ return 0L;
+}
+
+void KFileIconView::setSorting( QDir::SortSpec spec )
+{
+ KFileView::setSorting( spec );
+ KFileItemListIterator it( *items() );
+
+ KFileItem *item;
+
+ if ( spec & QDir::Time ) {
+ for ( ; (item = it.current()); ++it )
+ // warning, time_t is often signed -> cast it
+ viewItem(item)->setKey( sortingKey( (unsigned long)item->time( KIO::UDS_MODIFICATION_TIME ), item->isDir(), spec ));
+ }
+
+ else if ( spec & QDir::Size ) {
+ for ( ; (item = it.current()); ++it )
+ viewItem(item)->setKey( sortingKey( item->size(), item->isDir(),
+ spec ));
+ }
+ else { // Name or Unsorted
+ for ( ; (item = it.current()); ++it )
+ viewItem(item)->setKey( sortingKey( item->text(), item->isDir(),
+ spec ));
+ }
+
+ KIconView::setSorting( true, !isReversed() );
+ sort( !isReversed() );
+}
+
+//
+// mimetype determination on demand
+//
+void KFileIconView::mimeTypeDeterminationFinished()
+{
+ // anything to do?
+}
+
+void KFileIconView::determineIcon( KFileIconViewItem *item )
+{
+ (void) item->fileInfo()->determineMimeType();
+ updateView( item->fileInfo() );
+}
+
+void KFileIconView::listingCompleted()
+{
+ arrangeItemsInGrid();
+
+ // QIconView doesn't set the current item automatically, so we have to do
+ // that. We don't want to emit selectionChanged() tho.
+ if ( !currentItem() ) {
+ bool block = signalsBlocked();
+ blockSignals( true );
+ QIconViewItem *item = viewItem( firstFileItem() );
+ KIconView::setCurrentItem( item );
+ KIconView::setSelected( item, false );
+ blockSignals( block );
+ }
+
+ m_resolver->start( d->previews->isChecked() ? 0 : 10 );
+}
+
+// need to remove our tooltip, eventually
+bool KFileIconView::eventFilter( QObject *o, QEvent *e )
+{
+ if ( o == viewport() || o == this ) {
+ int type = e->type();
+ if ( type == QEvent::Leave ||
+ type == QEvent::FocusOut )
+ removeToolTip();
+ }
+
+ return KIconView::eventFilter( o, e );
+}
+
+/////////////////////////////////////////////////////////////////
+
+// ### workaround for Qt3 Bug
+void KFileIconView::showEvent( QShowEvent *e )
+{
+ KIconView::showEvent( e );
+}
+
+
+void KFileIconView::initItem( KFileIconViewItem *item, const KFileItem *i,
+ bool updateTextAndPixmap )
+{
+ if ( d->previews->isChecked() && canPreview( i ) )
+ item->setPixmapSize( QSize( d->previewIconSize, d->previewIconSize ) );
+
+ if ( updateTextAndPixmap )
+ {
+ // this causes a repaint of the item, which we want to avoid during
+ // directory listing, when all items are created. We want to paint all
+ // items at once, not every single item in that case.
+ item->setText( i->text() , false, false );
+ item->setPixmap( i->pixmap( myIconSize ) );
+ }
+
+ // see also setSorting()
+ QDir::SortSpec spec = KFileView::sorting();
+
+ if ( spec & QDir::Time )
+ // warning, time_t is often signed -> cast it
+ item->setKey( sortingKey( (unsigned long) i->time( KIO::UDS_MODIFICATION_TIME ),
+ i->isDir(), spec ));
+ else if ( spec & QDir::Size )
+ item->setKey( sortingKey( i->size(), i->isDir(), spec ));
+
+ else // Name or Unsorted
+ item->setKey( sortingKey( i->text(), i->isDir(), spec ));
+
+ //qDebug("** key for: %s: %s", i->text().latin1(), item->key().latin1());
+
+ if ( d->previews->isChecked() )
+ d->previewTimer.start( 10, true );
+}
+
+void KFileIconView::arrangeItemsInGrid( bool update )
+{
+ if ( d->noArrangement )
+ return;
+
+ KIconView::arrangeItemsInGrid( update );
+}
+
+void KFileIconView::zoomIn()
+{
+ setPreviewSize( d->previewIconSize + 30 );
+}
+
+void KFileIconView::zoomOut()
+{
+ setPreviewSize( d->previewIconSize - 30 );
+}
+
+QDragObject *KFileIconView::dragObject()
+{
+ // create a list of the URL:s that we want to drag
+ KURL::List urls;
+ KFileItemListIterator it( * KFileView::selectedItems() );
+ for ( ; it.current(); ++it ){
+ urls.append( (*it)->url() );
+ }
+ QPixmap pixmap;
+ if( urls.count() > 1 )
+ pixmap = DesktopIcon( "kmultiple", iconSize() );
+ if( pixmap.isNull() )
+ pixmap = currentFileItem()->pixmap( iconSize() );
+
+ QPoint hotspot;
+ hotspot.setX( pixmap.width() / 2 );
+ hotspot.setY( pixmap.height() / 2 );
+ QDragObject* myDragObject = new KURLDrag( urls, widget() );
+ myDragObject->setPixmap( pixmap, hotspot );
+ return myDragObject;
+}
+
+void KFileIconView::slotAutoOpen()
+{
+ d->autoOpenTimer.stop();
+ if( !d->dropItem )
+ return;
+
+ KFileItem *fileItem = d->dropItem->fileInfo();
+ if (!fileItem)
+ return;
+
+ if( fileItem->isFile() )
+ return;
+
+ if ( fileItem->isDir() || fileItem->isLink())
+ sig->activate( fileItem );
+}
+
+bool KFileIconView::acceptDrag(QDropEvent* e) const
+{
+ return KURLDrag::canDecode( e ) &&
+ (e->source()!=const_cast<KFileIconView*>(this)) &&
+ ( e->action() == QDropEvent::Copy
+ || e->action() == QDropEvent::Move
+ || e->action() == QDropEvent::Link );
+}
+
+void KFileIconView::contentsDragEnterEvent( QDragEnterEvent *e )
+{
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ if ((dropOptions() & AutoOpenDirs) == 0)
+ return;
+
+ KFileIconViewItem *item = dynamic_cast<KFileIconViewItem*>(findItem( contentsToViewport( e->pos() ) ));
+ if ( item ) { // are we over an item ?
+ d->dropItem = item;
+ d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
+ }
+ else
+ {
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+ }
+}
+
+void KFileIconView::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ if ((dropOptions() & AutoOpenDirs) == 0)
+ return;
+
+ KFileIconViewItem *item = dynamic_cast<KFileIconViewItem*>(findItem( contentsToViewport( e->pos() ) ));
+ if ( item ) { // are we over an item ?
+ if (d->dropItem != item)
+ {
+ d->dropItem = item;
+ d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
+ }
+ }
+ else
+ {
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+ }
+}
+
+void KFileIconView::contentsDragLeaveEvent( QDragLeaveEvent * )
+{
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+}
+
+void KFileIconView::contentsDropEvent( QDropEvent *e )
+{
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ KFileIconViewItem *item = dynamic_cast<KFileIconViewItem*>(findItem( contentsToViewport( e->pos() ) ));
+ KFileItem * fileItem = 0;
+ if (item)
+ fileItem = item->fileInfo();
+
+ emit dropped(e, fileItem);
+
+ KURL::List urls;
+ if (KURLDrag::decode( e, urls ) && !urls.isEmpty())
+ {
+ emit dropped(e, urls, fileItem ? fileItem->url() : KURL());
+ sig->dropURLs(fileItem, e, urls);
+ }
+}
+
+void KFileIconView::virtual_hook( int id, void* data )
+{ KIconView::virtual_hook( id, data );
+ KFileView::virtual_hook( id, data ); }
+
+#include "kfileiconview.moc"
diff --git a/kio/kfile/kfileiconview.h b/kio/kfile/kfileiconview.h
new file mode 100644
index 000000000..63a841a8e
--- /dev/null
+++ b/kio/kfile/kfileiconview.h
@@ -0,0 +1,265 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFILEICONVIEW_H
+#define KFILEICONVIEW_H
+
+class KFileItem;
+class QWidget;
+class QLabel;
+
+#include <kiconview.h>
+#include <kiconloader.h>
+#include <kfileview.h>
+#include <kmimetyperesolver.h>
+#include <kfile.h>
+
+/**
+ * An item for the iconview, that has a reference to its corresponding
+ * KFileItem.
+ */
+class KIO_EXPORT KFileIconViewItem : public KIconViewItem
+{
+public:
+ KFileIconViewItem( QIconView *parent, const QString &text,
+ const QPixmap &pixmap,
+ KFileItem *fi )
+ : KIconViewItem( parent, text, pixmap ), inf( fi ) {}
+ /**
+ * @since 3.1
+ */
+ KFileIconViewItem( QIconView *parent, KFileItem *fi )
+ : KIconViewItem( parent ), inf( fi ) {}
+
+ virtual ~KFileIconViewItem();
+
+ /**
+ * @returns the corresponding KFileItem
+ */
+ KFileItem *fileInfo() const {
+ return inf;
+ }
+
+private:
+ KFileItem *inf;
+
+private:
+ class KFileIconViewItemPrivate;
+ KFileIconViewItemPrivate *d;
+
+};
+
+namespace KIO {
+ class Job;
+}
+
+/**
+ * An icon-view capable of showing KFileItem's. Used in the filedialog
+ * for example. Most of the documentation is in KFileView class.
+ *
+ * @see KDirOperator
+ * @see KCombiView
+ * @see KFileDetailView
+ */
+class KIO_EXPORT KFileIconView : public KIconView, public KFileView
+{
+ Q_OBJECT
+
+public:
+ KFileIconView(QWidget *parent, const char *name);
+ virtual ~KFileIconView();
+
+ virtual QWidget *widget() { return this; }
+ virtual void clearView();
+ virtual void setAutoUpdate( bool ) {} // ### unused. remove in KDE4
+
+ virtual void updateView( bool );
+ virtual void updateView(const KFileItem*);
+ virtual void removeItem(const KFileItem*);
+
+ virtual void listingCompleted();
+
+ virtual void insertItem( KFileItem *i );
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+
+ virtual void setSelected(const KFileItem *, bool);
+ virtual bool isSelected(const KFileItem *i) const;
+ virtual void clearSelection();
+ virtual void selectAll();
+ virtual void invertSelection();
+
+ virtual void setCurrentItem( const KFileItem * );
+ virtual KFileItem * currentFileItem() const;
+ virtual KFileItem * firstFileItem() const;
+ virtual KFileItem * nextItem( const KFileItem * ) const;
+ virtual KFileItem * prevItem( const KFileItem * ) const;
+
+ /**
+ * Sets the size of the icons to show. Defaults to KIcon::SizeSmall.
+ */
+ void setIconSize( int size );
+
+ /**
+ * Sets the size of the previews. Defaults to KIcon::SizeLarge.
+ */
+ void setPreviewSize( int size );
+
+ /**
+ * Disables the "Maximum file size" configuration option for previews
+ *
+ * Set this before calling showPreviews()
+ *
+ * @since 3.4
+ **/
+ void setIgnoreMaximumSize(bool ignoreSize=true);
+
+ /**
+ * @returns the current size used for icons.
+ */
+ int iconSize() const { return myIconSize; }
+
+ void ensureItemVisible( const KFileItem * );
+
+ virtual void setSorting(QDir::SortSpec sort);
+
+ virtual void readConfig( KConfig *, const QString& group = QString::null );
+ virtual void writeConfig( KConfig *, const QString& group = QString::null);
+
+ // for KMimeTypeResolver
+ void mimeTypeDeterminationFinished();
+ void determineIcon( KFileIconViewItem *item );
+ QScrollView *scrollWidget() const { return (QScrollView*) this; }
+ void setAcceptDrops(bool b)
+ {
+ KIconView::setAcceptDrops(b);
+ viewport()->setAcceptDrops(b);
+ }
+
+public slots:
+ /**
+ * Starts loading previews for all files shown and shows them. Switches
+ * into 'large rows' mode, if that isn't the current mode yet.
+ *
+ * @sa setIgnoreMaximumSize
+ */
+ void showPreviews();
+
+ void zoomIn();
+
+ void zoomOut();
+
+ /**
+ * Reimplemented for performance reasons.
+ * @since 3.1
+ */
+ virtual void arrangeItemsInGrid( bool updated = true );
+
+protected:
+ /**
+ * Reimplemented to not let QIconView eat return-key events
+ */
+ virtual void keyPressEvent( QKeyEvent * );
+
+ /**
+ * Reimplemented to remove an eventual tooltip
+ */
+ virtual void hideEvent( QHideEvent * );
+
+ // ### workaround for Qt3 bug (see #35080)
+ virtual void showEvent( QShowEvent * );
+
+ virtual bool eventFilter( QObject *o, QEvent *e );
+
+ // DND support
+ virtual QDragObject *dragObject();
+ virtual void contentsDragEnterEvent( QDragEnterEvent *e );
+ virtual void contentsDragMoveEvent( QDragMoveEvent *e );
+ virtual void contentsDragLeaveEvent( QDragLeaveEvent *e );
+ virtual void contentsDropEvent( QDropEvent *ev );
+
+ // KDE4: Make virtual
+ bool acceptDrag(QDropEvent* e ) const;
+
+private slots:
+ void selected( QIconViewItem *item );
+ void slotActivate( QIconViewItem * );
+ void highlighted( QIconViewItem *item );
+ void showToolTip( QIconViewItem *item );
+ void removeToolTip();
+ void slotActivateMenu( QIconViewItem *, const QPoint& );
+ void slotSelectionChanged();
+
+ void slotSmallColumns();
+ void slotLargeRows();
+ void slotPreviewsToggled( bool );
+
+ void slotPreviewResult( KIO::Job * );
+ void gotPreview( const KFileItem *item, const QPixmap& pix );
+ void slotAutoOpen();
+
+signals:
+ /**
+ * The user dropped something.
+ * @p fileItem points to the item dropped on or can be 0 if the
+ * user dropped on empty space.
+ * @since 3.2
+ */
+ void dropped(QDropEvent *event, KFileItem *fileItem);
+ /**
+ * The user dropped the URLs @p urls.
+ * @p url points to the item dropped on or can be empty if the
+ * user dropped on empty space.
+ * @since 3.2
+ */
+ void dropped(QDropEvent *event, const KURL::List &urls, const KURL &url);
+
+private:
+ KMimeTypeResolver<KFileIconViewItem,KFileIconView> *m_resolver;
+
+ QLabel *toolTip;
+ int th;
+ int myIconSize;
+
+ virtual void insertItem(QIconViewItem *a, QIconViewItem *b) { KIconView::insertItem(a, b); }
+ virtual void setSelectionMode(QIconView::SelectionMode m) { KIconView::setSelectionMode(m); }
+ virtual void setSelected(QIconViewItem *i, bool a, bool b) { KIconView::setSelected(i, a, b); }
+
+ bool canPreview( const KFileItem * ) const;
+ void stopPreview();
+
+ void updateIcons();
+
+ inline KFileIconViewItem * viewItem( const KFileItem *item ) const {
+ if ( item )
+ return (KFileIconViewItem *) item->extraData( this );
+ return 0L;
+ }
+
+ void initItem(KFileIconViewItem *item, const KFileItem *i,
+ bool updateTextAndPixmap );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileIconViewPrivate;
+ KFileIconViewPrivate *d;
+};
+
+#endif // KFILESIMPLEVIEW_H
diff --git a/kio/kfile/kfilemetainfowidget.cpp b/kio/kfile/kfilemetainfowidget.cpp
new file mode 100644
index 000000000..ee76c82e2
--- /dev/null
+++ b/kio/kfile/kfilemetainfowidget.cpp
@@ -0,0 +1,375 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Rolf Magnus <ramagnus@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ $Id$
+ */
+
+#include "kfilemetainfowidget.h"
+
+#include <keditcl.h>
+#include <klocale.h>
+#include <knuminput.h>
+#include <kcombobox.h>
+#include <klineedit.h>
+#include <kstringvalidator.h>
+#include <kdebug.h>
+
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qspinbox.h>
+#include <qdatetimeedit.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qlayout.h>
+#include <qvalidator.h>
+
+/*
+ Widgets used for different types:
+
+ bool : QCheckBox
+ int : QSpinBox
+ QString : KComboBox if the validator is a KStringListValidator, else lineedit
+ QDateTime : QDateTimeEdit
+
+*/
+
+KFileMetaInfoWidget::KFileMetaInfoWidget(KFileMetaInfoItem item,
+ QValidator* val,
+ QWidget* parent, const char* name)
+ : QWidget(parent, name),
+ m_value(item.value()),
+ m_item(item),
+ m_validator(val)
+{
+ init(item, ReadWrite);
+}
+
+KFileMetaInfoWidget::KFileMetaInfoWidget(KFileMetaInfoItem item,
+ Mode mode,
+ QValidator* val,
+ QWidget* parent, const char* name)
+ : QWidget(parent, name),
+ m_value(item.value()),
+ m_item(item),
+ m_validator(val)
+{
+ init(item, mode);
+}
+
+void KFileMetaInfoWidget::init(KFileMetaInfoItem item, Mode mode)
+{
+ kdDebug(7033) << "*** item " << m_item.key()
+ << " is a " << value().typeName() << endl;
+
+ if (m_item.isEditable() && !(mode & ReadOnly))
+ m_widget = makeWidget();
+ else
+ switch (m_value.type())
+ {
+ case QVariant::Image :
+ m_widget = new QLabel(this, "info image");
+ static_cast<QLabel*>(m_widget)->setPixmap(QPixmap(m_value.toImage()));
+ break;
+ case QVariant::Pixmap :
+ m_widget = new QLabel(this, "info pixmap");
+ static_cast<QLabel*>(m_widget)->setPixmap(m_value.toPixmap());
+ break;
+ default:
+ m_widget = new QLabel(item.string(true), this, "info label");
+ }
+
+ (new QHBoxLayout(this))->addWidget(m_widget);
+}
+
+KFileMetaInfoWidget::~KFileMetaInfoWidget()
+{
+}
+
+QWidget* KFileMetaInfoWidget::makeWidget()
+{
+ QString valClass;
+ QWidget* w;
+
+ switch (m_value.type())
+ {
+ case QVariant::Invalid: // no type
+ // just make a label
+ w = new QLabel(i18n("<Error>"), this, "label");
+ break;
+
+ case QVariant::Int: // an int
+ case QVariant::UInt: // an unsigned int
+ w = makeIntWidget();
+ break;
+
+ case QVariant::Bool: // a bool
+ w = makeBoolWidget();
+ break;
+
+ case QVariant::Double: // a double
+ w = makeDoubleWidget();
+ break;
+
+
+ case QVariant::Date: // a QDate
+ w = makeDateWidget();
+ break;
+
+ case QVariant::Time: // a QTime
+ w = makeTimeWidget();
+ break;
+
+ case QVariant::DateTime: // a QDateTime
+ w = makeDateTimeWidget();
+ break;
+
+#if 0
+ case QVariant::Size: // a QSize
+ case QVariant::String: // a QString
+ case QVariant::List: // a QValueList
+ case QVariant::Map: // a QMap
+ case QVariant::StringList: // a QStringList
+ case QVariant::Font: // a QFont
+ case QVariant::Pixmap: // a QPixmap
+ case QVariant::Brush: // a QBrush
+ case QVariant::Rect: // a QRect
+ case QVariant::Color: // a QColor
+ case QVariant::Palette: // a QPalette
+ case QVariant::ColorGroup: // a QColorGroup
+ case QVariant::IconSet: // a QIconSet
+ case QVariant::Point: // a QPoint
+ case QVariant::Image: // a QImage
+ case QVariant::CString: // a QCString
+ case QVariant::PointArray: // a QPointArray
+ case QVariant::Region: // a QRegion
+ case QVariant::Bitmap: // a QBitmap
+ case QVariant::Cursor: // a QCursor
+ case QVariant::ByteArray: // a QByteArray
+ case QVariant::BitArray: // a QBitArray
+ case QVariant::SizePolicy: // a QSizePolicy
+ case QVariant::KeySequence: // a QKeySequence
+#endif
+ default:
+ w = makeStringWidget();
+ }
+
+ kdDebug(7033) << "*** item " << m_item.key()
+ << "is a " << m_item.value().typeName() << endl;
+ if (m_validator)
+ kdDebug(7033) << " and validator is a " << m_validator->className() << endl;
+
+ kdDebug(7033) << "*** created a " << w->className() << " for it\n";
+
+ return w;
+}
+
+// ****************************************************************
+// now the different methods to make the widgets for specific types
+// ****************************************************************
+
+QWidget* KFileMetaInfoWidget::makeBoolWidget()
+{
+ QCheckBox* cb = new QCheckBox(this, "metainfo bool widget");
+ cb->setChecked(m_item.value().toBool());
+ connect(cb, SIGNAL(toggled(bool)), this, SLOT(slotChanged(bool)));
+ return cb;
+}
+
+QWidget* KFileMetaInfoWidget::makeIntWidget()
+{
+ QSpinBox* sb = new QSpinBox(this, "metainfo integer widget");
+ sb->setValue(m_item.value().toInt());
+
+ if (m_validator)
+ {
+ if (m_validator->inherits("QIntValidator"))
+ {
+ sb->setMinValue(static_cast<QIntValidator*>(m_validator)->bottom());
+ sb->setMaxValue(static_cast<QIntValidator*>(m_validator)->top());
+ }
+ reparentValidator(sb, m_validator);
+ sb->setValidator(m_validator);
+ }
+
+ // make sure that an uint cannot be set to a value < 0
+ if (m_item.type() == QVariant::UInt)
+ sb->setMinValue(QMAX(sb->minValue(), 0));
+
+ connect(sb, SIGNAL(valueChanged(int)), this, SLOT(slotChanged(int)));
+ return sb;
+}
+
+QWidget* KFileMetaInfoWidget::makeDoubleWidget()
+{
+ KDoubleNumInput* dni = new KDoubleNumInput(m_item.value().toDouble(),
+ this, "metainfo double widget");
+
+
+ if (m_validator)
+ {
+ if (m_validator->inherits("QDoubleValidator"))
+ {
+ dni->setMinValue(static_cast<QDoubleValidator*>(m_validator)->bottom());
+ dni->setMaxValue(static_cast<QDoubleValidator*>(m_validator)->top());
+ }
+ reparentValidator(dni, m_validator);
+ }
+
+ connect(dni, SIGNAL(valueChanged(double)), this, SLOT(slotChanged(double)));
+ return dni;
+}
+
+QWidget* KFileMetaInfoWidget::makeStringWidget()
+{
+ if (m_validator && m_validator->inherits("KStringListValidator"))
+ {
+ KComboBox* b = new KComboBox(true, this, "metainfo combobox");
+ KStringListValidator* val = static_cast<KStringListValidator*>
+ (m_validator);
+ b->insertStringList(val->stringList());
+ b->setCurrentText(m_item.value().toString());
+ connect(b, SIGNAL(activated(const QString &)), this, SLOT(slotComboChanged(const QString &)));
+ b->setValidator(val);
+ reparentValidator(b, val);
+ return b;
+ }
+
+ if ( m_item.attributes() & KFileMimeTypeInfo::MultiLine ) {
+ KEdit *edit = new KEdit( this );
+ edit->setText( m_item.value().toString() );
+ connect( edit, SIGNAL( textChanged() ),
+ this, SLOT( slotMultiLineEditChanged() ));
+ // can't use a validator with a QTextEdit, but we may need to delete it
+ if ( m_validator )
+ reparentValidator( edit, m_validator );
+ return edit;
+ }
+
+ KLineEdit* e = new KLineEdit(m_item.value().toString(), this);
+ if (m_validator)
+ {
+ e->setValidator(m_validator);
+ reparentValidator(e, m_validator);
+ }
+ connect(e, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotLineEditChanged(const QString&)));
+ return e;
+}
+
+QWidget* KFileMetaInfoWidget::makeDateWidget()
+{
+ QWidget *e = new QDateEdit(m_item.value().toDate(), this);
+ connect(e, SIGNAL(valueChanged(const QDate&)),
+ this, SLOT(slotDateChanged(const QDate&)));
+ return e;
+}
+
+QWidget* KFileMetaInfoWidget::makeTimeWidget()
+{
+ return new QTimeEdit(m_item.value().toTime(), this);
+}
+
+QWidget* KFileMetaInfoWidget::makeDateTimeWidget()
+{
+ return new QDateTimeEdit(m_item.value().toDateTime(), this);
+}
+
+void KFileMetaInfoWidget::reparentValidator( QWidget *widget,
+ QValidator *validator )
+{
+ if ( !validator->parent() )
+ widget->insertChild( validator );
+}
+
+// ****************************************************************
+// now the slots that let us get notified if the value changed in the child
+// ****************************************************************
+
+void KFileMetaInfoWidget::slotChanged(bool value)
+{
+ Q_ASSERT(m_widget->inherits("QComboBox"));
+ m_value = QVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotChanged(int value)
+{
+ Q_ASSERT(m_widget->inherits("QSpinBox"));
+ m_value = QVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotChanged(double value)
+{
+ Q_ASSERT(m_widget->inherits("KDoubleNumInput"));
+ m_value = QVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotComboChanged(const QString &value)
+{
+ Q_ASSERT(m_widget->inherits("KComboBox"));
+ m_value = QVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotLineEditChanged(const QString& value)
+{
+ Q_ASSERT(m_widget->inherits("KLineEdit"));
+ m_value = QVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+// that may be a little expensive for long texts, but what can we do?
+void KFileMetaInfoWidget::slotMultiLineEditChanged()
+{
+ Q_ASSERT(m_widget->inherits("QTextEdit"));
+ m_value = QVariant( static_cast<const QTextEdit*>( sender() )->text() );
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotDateChanged(const QDate& value)
+{
+ Q_ASSERT(m_widget->inherits("QDateEdit"));
+ m_value = QVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotTimeChanged(const QTime& value)
+{
+ Q_ASSERT(m_widget->inherits("QTimeEdit"));
+ m_value = QVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotDateTimeChanged(const QDateTime& value)
+{
+ Q_ASSERT(m_widget->inherits("QDateTimeEdit"));
+ m_value = QVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+#include "kfilemetainfowidget.moc"
diff --git a/kio/kfile/kfilemetainfowidget.h b/kio/kfile/kfilemetainfowidget.h
new file mode 100644
index 000000000..4d0070949
--- /dev/null
+++ b/kio/kfile/kfilemetainfowidget.h
@@ -0,0 +1,95 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Rolf Magnus <ramagnus@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ */
+
+#ifndef __KFILEMETAINFOWIDGET_H__
+#define __KFILEMETAINFOWIDGET_H__
+
+#include <qwidget.h>
+#include <qvariant.h>
+#include <kfilemetainfo.h>
+
+/*!
+ * A widget to display file meta infos (like id3 for mp3)
+ */
+class KIO_EXPORT KFileMetaInfoWidget: public QWidget
+{
+ Q_OBJECT
+public:
+ enum Mode
+ {
+ ReadOnly = 1, ///Only display the meta infos, and do not permit the user to edit them
+ ReadWrite = 0, ///Permits user to edit the displayed meta-info
+ Reserve = 0xff
+ };
+
+ KFileMetaInfoWidget(KFileMetaInfoItem item, QValidator* val = 0,
+ QWidget* parent = 0, const char* name = 0);
+
+ KFileMetaInfoWidget(KFileMetaInfoItem item, Mode mode, QValidator* val = 0,
+ QWidget* parent = 0, const char* name = 0);
+
+ virtual ~KFileMetaInfoWidget();
+
+ bool apply()
+ {
+ return m_item.isEditable() && m_item.setValue(m_value);
+ }
+
+ void setValue(const QVariant& value) { m_value = value; }
+ QVariant value()const { return m_value; }
+ QValidator* validator() const { return m_validator; }
+ KFileMetaInfoItem item()const { return m_item; }
+
+signals:
+ void valueChanged(const QVariant& value);
+
+protected:
+ void reparentValidator(QWidget *widget, QValidator *validator);
+ virtual QWidget* makeWidget();
+
+ QWidget* makeBoolWidget();
+ QWidget* makeIntWidget();
+ QWidget* makeDoubleWidget();
+ QWidget* makeStringWidget();
+ QWidget* makeDateWidget();
+ QWidget* makeTimeWidget();
+ QWidget* makeDateTimeWidget();
+
+private slots:
+ void slotChanged(bool value);
+ void slotChanged(int value);
+ void slotChanged(double value);
+ void slotComboChanged(const QString &value);
+ void slotLineEditChanged(const QString& value);
+ void slotMultiLineEditChanged();
+ void slotDateChanged(const QDate& value);
+ void slotTimeChanged(const QTime& value);
+ void slotDateTimeChanged(const QDateTime& value);
+
+private:
+ void init(KFileMetaInfoItem item, Mode mode);
+
+ QVariant m_value; // the value will be saved here until apply() is called
+ KFileMetaInfoItem m_item;
+ QWidget* m_widget;
+ QValidator* m_validator;
+ bool m_dirty : 1;
+};
+
+#endif
diff --git a/kio/kfile/kfilemetapreview.cpp b/kio/kfile/kfilemetapreview.cpp
new file mode 100644
index 000000000..4d5ec339b
--- /dev/null
+++ b/kio/kfile/kfilemetapreview.cpp
@@ -0,0 +1,196 @@
+/*
+ * This file is part of the KDE project.
+ * Copyright (C) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "kfilemetapreview.h"
+
+#include <qlayout.h>
+
+#include <kio/previewjob.h>
+#include <klibloader.h>
+#include <kimagefilepreview.h>
+#include <kmimetype.h>
+
+bool KFileMetaPreview::s_tryAudioPreview = true;
+
+KFileMetaPreview::KFileMetaPreview( QWidget *parent, const char *name )
+ : KPreviewWidgetBase( parent, name ),
+ haveAudioPreview( false )
+{
+ QHBoxLayout *layout = new QHBoxLayout( this, 0, 0 );
+ m_stack = new QWidgetStack( this );
+ layout->addWidget( m_stack );
+
+ // ###
+// m_previewProviders.setAutoDelete( true );
+ initPreviewProviders();
+}
+
+KFileMetaPreview::~KFileMetaPreview()
+{
+}
+
+void KFileMetaPreview::initPreviewProviders()
+{
+ m_previewProviders.clear();
+ // hardcoded so far
+
+ // image previews
+ KImageFilePreview *imagePreview = new KImageFilePreview( m_stack );
+ (void) m_stack->addWidget( imagePreview );
+ m_stack->raiseWidget( imagePreview );
+ resize( imagePreview->sizeHint() );
+
+ QStringList mimeTypes = imagePreview->supportedMimeTypes();
+ QStringList::ConstIterator it = mimeTypes.begin();
+ for ( ; it != mimeTypes.end(); ++it )
+ {
+// qDebug(".... %s", (*it).latin1());
+ m_previewProviders.insert( *it, imagePreview );
+ }
+}
+
+KPreviewWidgetBase * KFileMetaPreview::previewProviderFor( const QString& mimeType )
+{
+// qDebug("### looking for: %s", mimeType.latin1());
+ // often the first highlighted item, where we can be sure, there is no plugin
+ // (this "folders reflect icons" is a konq-specific thing, right?)
+ if ( mimeType == "inode/directory" )
+ return 0L;
+
+ KPreviewWidgetBase *provider = m_previewProviders.find( mimeType );
+ if ( provider )
+ return provider;
+
+//qDebug("#### didn't find anything for: %s", mimeType.latin1());
+
+ if ( s_tryAudioPreview &&
+ !mimeType.startsWith("text/") && !mimeType.startsWith("image/") )
+ {
+ if ( !haveAudioPreview )
+ {
+ KPreviewWidgetBase *audioPreview = createAudioPreview( m_stack );
+ if ( audioPreview )
+ {
+ haveAudioPreview = true;
+ (void) m_stack->addWidget( audioPreview );
+ QStringList mimeTypes = audioPreview->supportedMimeTypes();
+ QStringList::ConstIterator it = mimeTypes.begin();
+ for ( ; it != mimeTypes.end(); ++it )
+ m_previewProviders.insert( *it, audioPreview );
+ }
+ }
+ }
+
+ // with the new mimetypes from the audio-preview, try again
+ provider = m_previewProviders.find( mimeType );
+ if ( provider )
+ return provider;
+
+ // ### mimetype may be image/* for example, try that
+ int index = mimeType.find( '/' );
+ if ( index > 0 )
+ {
+ provider = m_previewProviders.find( mimeType.left( index + 1 ) + "*" );
+ if ( provider )
+ return provider;
+ }
+
+ KMimeType::Ptr mimeInfo = KMimeType::mimeType( mimeType );
+ if ( mimeInfo )
+ {
+ // check mime type inheritance
+ QString parentMimeType = mimeInfo->parentMimeType();
+ while ( !parentMimeType.isEmpty() )
+ {
+ provider = m_previewProviders.find( parentMimeType );
+ if ( provider )
+ return provider;
+
+ KMimeType::Ptr parentMimeInfo = KMimeType::mimeType( parentMimeType );
+ if ( !parentMimeInfo ) break;
+
+ parentMimeType = parentMimeInfo->parentMimeType();
+ }
+
+ // check X-KDE-Text property
+ QVariant textProperty = mimeInfo->property( "X-KDE-text" );
+ if ( textProperty.isValid() && textProperty.type() == QVariant::Bool )
+ {
+ if ( textProperty.toBool() )
+ {
+ provider = m_previewProviders.find( "text/plain" );
+ if ( provider )
+ return provider;
+
+ provider = m_previewProviders.find( "text/*" );
+ if ( provider )
+ return provider;
+ }
+ }
+ }
+
+ return 0L;
+}
+
+void KFileMetaPreview::showPreview(const KURL &url)
+{
+ KMimeType::Ptr mt = KMimeType::findByURL( url );
+ KPreviewWidgetBase *provider = previewProviderFor( mt->name() );
+ if ( provider )
+ {
+ if ( provider != m_stack->visibleWidget() ) // stop the previous preview
+ clearPreview();
+
+ m_stack->setEnabled( true );
+ m_stack->raiseWidget( provider );
+ provider->showPreview( url );
+ }
+ else
+ {
+ clearPreview();
+ m_stack->setEnabled( false );
+ }
+}
+
+void KFileMetaPreview::clearPreview()
+{
+ if ( m_stack->visibleWidget() )
+ static_cast<KPreviewWidgetBase*>( m_stack->visibleWidget() )->clearPreview();
+}
+
+void KFileMetaPreview::addPreviewProvider( const QString& mimeType,
+ KPreviewWidgetBase *provider )
+{
+ m_previewProviders.insert( mimeType, provider );
+}
+
+void KFileMetaPreview::clearPreviewProviders()
+{
+ QDictIterator<KPreviewWidgetBase> it( m_previewProviders );
+ for ( ; it.current(); ++it )
+ m_stack->removeWidget( it.current() );
+
+ m_previewProviders.clear();
+}
+
+// static
+KPreviewWidgetBase * KFileMetaPreview::createAudioPreview( QWidget *parent )
+{
+ KLibFactory *factory = KLibLoader::self()->factory( "kfileaudiopreview" );
+ if ( !factory )
+ {
+ s_tryAudioPreview = false;
+ return 0L;
+ }
+
+ return dynamic_cast<KPreviewWidgetBase*>( factory->create( parent, "kfileaudiopreview" ));
+}
+
+void KFileMetaPreview::virtual_hook( int, void* ) {}
+
+#include "kfilemetapreview.moc"
diff --git a/kio/kfile/kfilemetapreview.h b/kio/kfile/kfilemetapreview.h
new file mode 100644
index 000000000..ae0650ea1
--- /dev/null
+++ b/kio/kfile/kfilemetapreview.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the KDE project.
+ * Copyright (C) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef KFILEMETAPREVIEW_H
+#define KFILEMETAPREVIEW_H
+
+#include <qdict.h>
+#include <qwidgetstack.h>
+
+#include <kpreviewwidgetbase.h>
+#include <kurl.h>
+
+class KIO_EXPORT KFileMetaPreview : public KPreviewWidgetBase
+{
+ Q_OBJECT
+
+public:
+ KFileMetaPreview(QWidget *parent, const char *name = 0);
+ ~KFileMetaPreview();
+
+ virtual void addPreviewProvider( const QString& mimeType,
+ KPreviewWidgetBase *provider );
+ virtual void clearPreviewProviders();
+
+public slots:
+ virtual void showPreview(const KURL &url);
+ virtual void clearPreview();
+
+protected:
+ virtual KPreviewWidgetBase *previewProviderFor( const QString& mimeType );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+
+private:
+ void initPreviewProviders();
+
+ QWidgetStack *m_stack;
+ QDict<KPreviewWidgetBase> m_previewProviders;
+ bool haveAudioPreview;
+
+ // may return 0L
+ static KPreviewWidgetBase * createAudioPreview( QWidget *parent );
+ static bool s_tryAudioPreview;
+
+private:
+ class KFileMetaPreviewPrivate;
+ KFileMetaPreviewPrivate *d;
+};
+
+#endif // KFILEMETAPREVIEW_H
diff --git a/kio/kfile/kfilepreview.cpp b/kio/kfile/kfilepreview.cpp
new file mode 100644
index 000000000..14065c3cb
--- /dev/null
+++ b/kio/kfile/kfilepreview.cpp
@@ -0,0 +1,279 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 2000 Werner Trobin <wtrobin@carinthia.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kaction.h>
+#include <kfilepreview.h>
+#include <kfilepreview.moc>
+#include <klocale.h>
+
+#include <qlabel.h>
+
+#include "config-kfile.h"
+
+KFilePreview::KFilePreview(KFileView *view, QWidget *parent, const char *name)
+ : QSplitter(parent, name), KFileView()
+{
+ if ( view )
+ init( view );
+ else
+ init( new KFileIconView( (QSplitter*) this, "left" ));
+}
+
+
+KFilePreview::KFilePreview(QWidget *parent, const char *name) :
+ QSplitter(parent, name), KFileView()
+{
+ init( new KFileIconView((QSplitter*)this, "left") );
+}
+
+KFilePreview::~KFilePreview()
+{
+ // Why copy the actions in the first place? --ellis, 13 Jan 02.
+ //// don't delete the view's actions (inserted into our collection)!
+ //for ( uint i = 0; i < left->actionCollection()->count(); i++ )
+ // actionCollection()->take( left->actionCollection()->action( i ));
+
+ // don't delete the preview, we can reuse it
+ // (it will get deleted by ~KDirOperator)
+ if ( preview && preview->parentWidget() == this ) {
+ preview->reparent(0L, 0, QPoint(0, 0), false);
+ }
+}
+
+void KFilePreview::init( KFileView *view )
+{
+ setViewName( i18n("Preview") );
+
+ left = 0L;
+ setFileView( view );
+
+ preview = new QWidget((QSplitter*)this, "preview");
+ QString tmp = i18n("No preview available.");
+ QLabel *l = new QLabel(tmp, preview);
+ l->setMinimumSize(l->sizeHint());
+ l->move(10, 5);
+ preview->setMinimumWidth(l->sizeHint().width()+20);
+ setResizeMode(preview, QSplitter::KeepSize);
+
+ // Why copy the actions? --ellis, 13 Jan 02.
+ //for ( uint i = 0; i < view->actionCollection()->count(); i++ )
+ // actionCollection()->insert( view->actionCollection()->action( i ));
+}
+
+void KFilePreview::setFileView( KFileView *view )
+{
+ Q_ASSERT( view );
+
+ // Why copy the actions? --ellis, 13 Jan 02.
+ //if ( left ) { // remove any previous actions
+ // for ( uint i = 0; i < left->actionCollection()->count(); i++ )
+ // actionCollection()->take( left->actionCollection()->action( i ));
+ //}
+
+ delete left;
+ view->widget()->reparent( this, QPoint(0,0) );
+ view->KFileView::setViewMode(All);
+ view->setParentView(this);
+ view->setSorting( sorting() );
+ left = view;
+
+ connect( left->signaler(), SIGNAL( fileHighlighted(const KFileItem*) ),
+ SLOT( slotHighlighted( const KFileItem * )));
+
+ // Why copy the actions? --ellis, 13 Jan 02.
+ //for ( uint i = 0; i < view->actionCollection()->count(); i++ )
+ // actionCollection()->insert( view->actionCollection()->action( i ));
+}
+
+// this url parameter is useless... it's the url of the current directory.
+// what for?
+void KFilePreview::setPreviewWidget(const QWidget *w, const KURL &)
+{
+ left->setOnlyDoubleClickSelectsFiles( onlyDoubleClickSelectsFiles() );
+
+ if (w) {
+ connect(this, SIGNAL( showPreview(const KURL &) ),
+ w, SLOT( showPreview(const KURL &) ));
+ connect( this, SIGNAL( clearPreview() ),
+ w, SLOT( clearPreview() ));
+ }
+ else {
+ preview->hide();
+ return;
+ }
+
+ delete preview;
+ preview = const_cast<QWidget*>(w);
+ preview->reparent((QSplitter*)this, 0, QPoint(0, 0), true);
+ preview->resize(preview->sizeHint());
+ preview->show();
+}
+
+void KFilePreview::insertItem(KFileItem *item)
+{
+ KFileView::insertItem( item );
+ left->insertItem(item);
+}
+
+void KFilePreview::setSorting( QDir::SortSpec sort )
+{
+ left->setSorting( sort );
+ KFileView::setSorting( left->sorting() );
+}
+
+void KFilePreview::clearView()
+{
+ left->clearView();
+ emit clearPreview();
+}
+
+void KFilePreview::updateView(bool b)
+{
+ left->updateView(b);
+ if(preview)
+ preview->repaint(b);
+}
+
+void KFilePreview::updateView(const KFileItem *i)
+{
+ left->updateView(i);
+}
+
+void KFilePreview::removeItem(const KFileItem *i)
+{
+ if ( left->isSelected( i ) )
+ emit clearPreview();
+
+ left->removeItem(i);
+ KFileView::removeItem( i );
+}
+
+void KFilePreview::listingCompleted()
+{
+ left->listingCompleted();
+}
+
+void KFilePreview::clear()
+{
+ KFileView::clear();
+ left->KFileView::clear();
+}
+
+void KFilePreview::clearSelection()
+{
+ left->clearSelection();
+ emit clearPreview();
+}
+
+void KFilePreview::selectAll()
+{
+ left->selectAll();
+}
+
+void KFilePreview::invertSelection()
+{
+ left->invertSelection();
+}
+
+bool KFilePreview::isSelected( const KFileItem *i ) const
+{
+ return left->isSelected( i );
+}
+
+void KFilePreview::setSelectionMode(KFile::SelectionMode sm) {
+ left->setSelectionMode( sm );
+}
+
+void KFilePreview::setSelected(const KFileItem *item, bool enable) {
+ left->setSelected( item, enable );
+}
+
+void KFilePreview::setCurrentItem( const KFileItem *item )
+{
+ left->setCurrentItem( item );
+}
+
+KFileItem * KFilePreview::currentFileItem() const
+{
+ return left->currentFileItem();
+}
+
+void KFilePreview::slotHighlighted(const KFileItem* item)
+{
+ if ( item )
+ emit showPreview( item->url() );
+
+ else { // item = 0 -> multiselection mode
+ const KFileItemList *items = selectedItems();
+ if ( items->count() == 1 )
+ emit showPreview( items->getFirst()->url() );
+ else
+ emit clearPreview();
+ }
+
+ // the preview widget appears and takes some space of the left view,
+ // so we may have to scroll to make the current item visible
+ left->ensureItemVisible(item);
+ }
+
+void KFilePreview::ensureItemVisible(const KFileItem *item)
+{
+ left->ensureItemVisible(item);
+}
+
+KFileItem * KFilePreview::firstFileItem() const
+{
+ return left->firstFileItem();
+}
+
+KFileItem * KFilePreview::nextItem( const KFileItem *item ) const
+{
+ return left->nextItem( item );
+}
+
+KFileItem * KFilePreview::prevItem( const KFileItem *item ) const
+{
+ return left->prevItem( item );
+}
+
+KActionCollection * KFilePreview::actionCollection() const
+{
+ if ( left )
+ return left->actionCollection();
+ else {
+ kdWarning() << "KFilePreview::actionCollection(): called before setFileView()." << endl; //ellis
+ return KFileView::actionCollection();
+ }
+}
+
+void KFilePreview::readConfig( KConfig *config, const QString& group )
+{
+ left->readConfig( config, group );
+}
+
+void KFilePreview::writeConfig( KConfig *config, const QString& group )
+{
+ left->writeConfig( config, group );
+}
+
+void KFilePreview::virtual_hook( int id, void* data )
+{ KFileView::virtual_hook( id, data ); }
+
diff --git a/kio/kfile/kfilepreview.h b/kio/kfile/kfilepreview.h
new file mode 100644
index 000000000..d6ee487f7
--- /dev/null
+++ b/kio/kfile/kfilepreview.h
@@ -0,0 +1,122 @@
+/* -*- c++ -*-
+ This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 2000 Werner Trobin <wtrobin@carinthia.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KFILEPREVIEW_H
+#define _KFILEPREVIEW_H
+
+#include <qsplitter.h>
+#include <qwidget.h>
+#include <qstring.h>
+
+#include <kurl.h>
+#include <kfileitem.h>
+#include <kfileiconview.h>
+#include <kfiledetailview.h>
+#include <kfile.h>
+
+/*!
+ * This KFileView is an empbedded preview for some file types.
+ */
+class KIO_EXPORT KFilePreview : public QSplitter, public KFileView
+{
+ Q_OBJECT
+
+public:
+ KFilePreview(QWidget *parent, const char *name);
+ KFilePreview(KFileView *view, QWidget *parent, const char *name);
+ virtual ~KFilePreview();
+
+ virtual QWidget *widget() { return this; }
+ virtual void clearView();
+
+ /**
+ * Delets the current view and sets the view to the given @p view.
+ * The view is reparented to have this as parent, if necessary.
+ */
+ void setFileView(KFileView *view);
+
+ /**
+ * @returns the current fileview
+ */
+ KFileView* fileView() const { return left; }
+
+ virtual void updateView( bool );
+ virtual void updateView(const KFileItem*);
+ virtual void removeItem(const KFileItem*);
+ virtual void listingCompleted();
+
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+
+ virtual void setSelected(const KFileItem *, bool);
+ virtual bool isSelected( const KFileItem * ) const;
+ virtual void clearSelection();
+ virtual void selectAll();
+ virtual void invertSelection();
+
+ virtual void insertItem(KFileItem *);
+ virtual void clear();
+
+ virtual void setCurrentItem( const KFileItem * );
+ virtual KFileItem * currentFileItem() const;
+ virtual KFileItem * firstFileItem() const;
+ virtual KFileItem * nextItem( const KFileItem * ) const;
+ virtual KFileItem * prevItem( const KFileItem * ) const;
+
+ virtual void setSorting( QDir::SortSpec sort );
+
+ virtual void readConfig( KConfig *, const QString& group = QString::null );
+ virtual void writeConfig( KConfig *, const QString& group = QString::null);
+
+ /**
+ * This overrides KFileView::actionCollection() by returning
+ * the actionCollection() of the KFileView (member left) it contains.
+ * This means that KFilePreview will never create a KActionCollection
+ * object of its own.
+ */
+ virtual KActionCollection * actionCollection() const;
+
+ void ensureItemVisible(const KFileItem *);
+
+ void setPreviewWidget(const QWidget *w, const KURL &u);
+
+protected slots:
+ virtual void slotHighlighted( const KFileItem * );
+
+signals:
+ void showPreview(const KURL &);
+ void clearPreview();
+
+private:
+ void init( KFileView *view );
+
+ KFileView *left;
+ QWidget *preview;
+ QString viewname;
+
+protected:
+ /** \internal */
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFilePreviewPrivate;
+ KFilePreviewPrivate *d;
+};
+#endif
diff --git a/kio/kfile/kfilesharedlg.cpp b/kio/kfile/kfilesharedlg.cpp
new file mode 100644
index 000000000..9be183728
--- /dev/null
+++ b/kio/kfile/kfilesharedlg.cpp
@@ -0,0 +1,286 @@
+/* This file is part of the KDE project
+ Copyright (c) 2001 David Faure <david@mandrakesoft.com>
+ Copyright (c) 2001 Laurent Montel <lmontel@mandrakesoft.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kfilesharedlg.h"
+#include <qvbox.h>
+#include <qlabel.h>
+#include <qdir.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+#include <qlayout.h>
+#include <kprocess.h>
+#include <kprocio.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <kio/kfileshare.h>
+#include <kseparator.h>
+#include <qpushbutton.h>
+#include <kapplication.h>
+#include <ksimpleconfig.h>
+#include <kmessagebox.h>
+
+class KFileSharePropsPlugin::Private
+{
+public:
+ QVBox *m_vBox;
+ KProcess *m_configProc;
+ bool m_bAllShared;
+ bool m_bAllUnshared;
+};
+
+KFileSharePropsPlugin::KFileSharePropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new Private;
+ d->m_vBox = _props->addVBoxPage( i18n("&Share") );
+ d->m_configProc = 0;
+ properties->setFileSharingPage(d->m_vBox);
+ m_widget = 0L;
+ init();
+}
+
+KFileSharePropsPlugin::~KFileSharePropsPlugin()
+{
+ if (d->m_configProc)
+ d->m_configProc->detach(); // Detach to prevent that we kill the process
+ delete d;
+}
+
+bool KFileSharePropsPlugin::supports( const KFileItemList& items )
+{
+ // Do not show dialog if in advanced mode,
+ // because the advanced dialog is shown already.
+ if (KFileShare::shareMode() == KFileShare::Advanced) {
+ kdDebug() << "KFileSharePropsPlugin::supports: false because sharemode is advanced" << endl;
+ return false;
+ }
+
+ KFileItemListIterator it( items );
+ for ( ; it.current(); ++it )
+ {
+ bool isLocal = ( *it )->isLocalFile();
+ // We only support local dirs
+ if ( !(*it)->isDir() || !isLocal )
+ return false;
+ // And sharing the trash doesn't make sense
+ if ( isLocal && (*it)->url().path( 1 ) == KGlobalSettings::trashPath() )
+ return false;
+ }
+ return true;
+}
+
+void KFileSharePropsPlugin::init()
+{
+ // We store the main widget, so that it's possible (later) to call init()
+ // more than once, to update the page if something changed (e.g. after
+ // the user has been authorized)
+ delete m_widget;
+ m_rbShare = 0L;
+ m_rbUnShare = 0L;
+ m_widget = new QWidget( d->m_vBox );
+ QVBoxLayout * vbox = new QVBoxLayout( m_widget );
+
+ switch ( KFileShare::authorization() ) {
+ case KFileShare::Authorized:
+ {
+ // Check if all selected dirs are in $HOME
+ QString home = QDir::homeDirPath();
+ if ( home[home.length()-1] != '/' )
+ home += '/';
+ bool ok = true;
+ KFileItemList items = properties->items();
+ // We have 3 possibilities: all shared, all unshared, or mixed.
+ d->m_bAllShared = true;
+ d->m_bAllUnshared = true;
+ KFileItemListIterator it( items );
+ for ( ; it.current() && ok; ++it ) {
+ QString path = (*it)->url().path();
+ if ( !path.startsWith( home ) )
+ ok = false;
+ if ( KFileShare::isDirectoryShared( path ) )
+ d->m_bAllUnshared = false;
+ else
+ d->m_bAllShared = false;
+ }
+ if ( !ok )
+ {
+ vbox->addWidget( new QLabel( i18n( "Only folders in your home folder can be shared."),
+ m_widget ), 0 );
+ }
+ else
+ {
+ // Everything ok, show the share/unshare GUI
+ vbox->setSpacing( KDialog::spacingHint() );
+ vbox->setMargin( KDialog::marginHint() );
+
+ QButtonGroup *rbGroup = new QButtonGroup( m_widget );
+ rbGroup->hide();
+ m_rbUnShare = new QRadioButton( i18n("Not shared"), m_widget );
+ connect( m_rbUnShare, SIGNAL( toggled(bool) ), SIGNAL( changed() ) );
+ vbox->addWidget( m_rbUnShare, 0 );
+ rbGroup->insert( m_rbUnShare );
+
+ m_rbShare = new QRadioButton( i18n("Shared"), m_widget );
+ connect( m_rbShare, SIGNAL( toggled(bool) ), SIGNAL( changed() ) );
+ vbox->addWidget( m_rbShare, 0 );
+ rbGroup->insert( m_rbShare );
+
+ // Activate depending on status
+ if ( d->m_bAllShared )
+ m_rbShare->setChecked(true);
+ if ( d->m_bAllUnshared )
+ m_rbUnShare->setChecked(true);
+
+ // Some help text
+ QLabel *label = new QLabel( i18n("Sharing this folder makes it available under Linux/UNIX (NFS) and Windows (Samba).") , m_widget );
+ label->setAlignment( Qt::AlignAuto | Qt::AlignVCenter | Qt::WordBreak );
+ vbox->addWidget( label, 0 );
+
+ KSeparator* sep=new KSeparator(m_widget);
+ vbox->addWidget( sep, 0 );
+ label = new QLabel( i18n("You can also reconfigure file sharing authorization.") , m_widget );
+ label->setAlignment( Qt::AlignAuto | Qt::AlignVCenter | Qt::WordBreak );
+ vbox->addWidget( label, 0 );
+ m_pbConfig = new QPushButton( i18n("Configure File Sharing..."), m_widget );
+ connect( m_pbConfig, SIGNAL( clicked() ), SLOT( slotConfigureFileSharing() ) );
+ vbox->addWidget( m_pbConfig, 0, Qt::AlignHCenter );
+
+ vbox->addStretch( 10 );
+ }
+ }
+ break;
+ case KFileShare::ErrorNotFound:
+ vbox->addWidget( new QLabel( i18n("Error running 'filesharelist'. Check if installed and in $PATH or /usr/sbin."),
+ m_widget ), 0 );
+ break;
+ case KFileShare::UserNotAllowed:
+ {
+ vbox->setSpacing( 10 );
+ if (KFileShare::sharingEnabled()) {
+ vbox->addWidget( new QLabel( i18n("You need to be authorized to share folders."),
+ m_widget ), 0 );
+ } else {
+ vbox->addWidget( new QLabel( i18n("File sharing is disabled."),
+ m_widget ), 0 );
+ }
+ QHBoxLayout* hBox = new QHBoxLayout( (QWidget *)0L );
+ vbox->addLayout( hBox, 0 );
+ m_pbConfig = new QPushButton( i18n("Configure File Sharing..."), m_widget );
+ connect( m_pbConfig, SIGNAL( clicked() ), SLOT( slotConfigureFileSharing() ) );
+ hBox->addWidget( m_pbConfig, 0, Qt::AlignHCenter );
+ vbox->addStretch( 10 ); // align items on top
+ break;
+ }
+ case KFileShare::NotInitialized:
+ kdWarning() << "KFileShare Authorization still NotInitialized after calling authorization() - impossible" << endl;
+ break;
+ }
+ m_widget->show(); // In case the dialog was shown already.
+}
+
+void KFileSharePropsPlugin::slotConfigureFileSharing()
+{
+ if (d->m_configProc) return;
+
+ d->m_configProc = new KProcess(this);
+ (*d->m_configProc) << KStandardDirs::findExe("kdesu") << locate("exe", "kcmshell") << "fileshare";
+ if (!d->m_configProc->start( KProcess::NotifyOnExit ))
+ {
+ delete d->m_configProc;
+ d->m_configProc = 0;
+ return;
+ }
+ connect(d->m_configProc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(slotConfigureFileSharingDone()));
+ m_pbConfig->setEnabled(false);
+}
+
+void KFileSharePropsPlugin::slotConfigureFileSharingDone()
+{
+ delete d->m_configProc;
+ d->m_configProc = 0;
+ KFileShare::readConfig();
+ KFileShare::readShareList();
+ init();
+}
+
+void KFileSharePropsPlugin::applyChanges()
+{
+ kdDebug() << "KFileSharePropsPlugin::applyChanges" << endl;
+ if ( m_rbShare && m_rbUnShare )
+ {
+ bool share = m_rbShare->isChecked();
+
+ if (share && d->m_bAllShared)
+ return; // Nothing to do
+ if (!share && d->m_bAllUnshared)
+ return; // Nothing to do
+
+ KFileItemList items = properties->items();
+ KFileItemListIterator it( items );
+ bool ok = true;
+ for ( ; it.current() && ok; ++it ) {
+ QString path = (*it)->url().path();
+ ok = setShared( path, share );
+ if (!ok) {
+ if (share)
+ KMessageBox::detailedError(properties,
+ i18n("Sharing folder '%1' failed.").arg(path),
+ i18n("An error occurred while trying to share folder '%1'. "
+ "Make sure that the Perl script 'fileshareset' is set suid root.")
+ .arg(path));
+ else
+ KMessageBox::error(properties,
+ i18n("Unsharing folder '%1' failed.").arg(path),
+ i18n("An error occurred while trying to unshare folder '%1'. "
+ "Make sure that the Perl script 'fileshareset' is set suid root.")
+ .arg(path));
+
+ properties->abortApplying();
+ break;
+ }
+ }
+
+ // Get the change back into our cached info
+ KFileShare::readShareList();
+ }
+}
+
+bool KFileSharePropsPlugin::setShared( const QString& path, bool shared )
+{
+ kdDebug() << "KFileSharePropsPlugin::setShared " << path << "," << shared << endl;
+ return KFileShare::setShared( path, shared );
+}
+
+QWidget* KFileSharePropsPlugin::page() const
+{
+ return d->m_vBox;
+}
+
+#include "kfilesharedlg.moc"
+
+//TODO: do we need to monitor /etc/security/fileshare.conf ?
+// if the user is added to the 'fileshare' group, we wouldn't be notified
+// Of course the config module can notify us.
+// TODO: listen to such notifications ;)
diff --git a/kio/kfile/kfilesharedlg.h b/kio/kfile/kfilesharedlg.h
new file mode 100644
index 000000000..c95de779b
--- /dev/null
+++ b/kio/kfile/kfilesharedlg.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE project
+ Copyright (c) 2001 David Faure <david@mandrakesoft.com>
+ Copyright (c) 2001 Laurent Montel <lmontel@mandrakesoft.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef kfilesharedlg_h
+#define kfilesharedlg_h
+
+#include <kpropertiesdialog.h>
+class QVBoxLayout;
+class QRadioButton;
+class QPushButton;
+
+/**
+ * This plugin provides a page to KPropsDlg, showing the "file sharing" options
+ * @author David Faure <david@mandrakesoft.com>
+ * @since 3.1
+ */
+class KIO_EXPORT KFileSharePropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ KFileSharePropsPlugin( KPropertiesDialog *_props );
+ virtual ~KFileSharePropsPlugin();
+
+ /**
+ * Apply all changes to the file.
+ * This function is called when the user presses 'Ok'. The last plugin inserted
+ * is called first.
+ */
+ virtual void applyChanges();
+
+ static bool supports( const KFileItemList& items );
+
+ QWidget* page() const;
+
+protected slots:
+ void slotConfigureFileSharing();
+ void slotConfigureFileSharingDone();
+
+private:
+ void init();
+ bool setShared( const QString&path, bool shared );
+
+ QWidget *m_widget;
+ QRadioButton *m_rbShare;
+ QRadioButton *m_rbUnShare;
+ QPushButton *m_pbConfig;
+ class Private;
+ Private *d;
+};
+
+#endif
diff --git a/kio/kfile/kfilespeedbar.cpp b/kio/kfile/kfilespeedbar.cpp
new file mode 100644
index 000000000..86ee85f52
--- /dev/null
+++ b/kio/kfile/kfilespeedbar.cpp
@@ -0,0 +1,99 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kfilespeedbar.h"
+#include "config-kfile.h"
+
+#include <qdir.h>
+
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+
+KFileSpeedBar::KFileSpeedBar( QWidget *parent, const char *name )
+ : KURLBar( true, parent, name )
+{
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs( config, ConfigGroup );
+ m_initializeSpeedbar = config->readBoolEntry( "Set speedbar defaults",
+ true );
+ setIconSize(KIcon::SizeSmallMedium);
+ readConfig( KGlobal::config(), "KFileDialog Speedbar" );
+
+ if ( m_initializeSpeedbar )
+ {
+ KURL u;
+ u.setPath( KGlobalSettings::desktopPath() );
+ insertItem( u, i18n("Desktop"), false );
+
+//TODO: win32
+ if ((KGlobalSettings::documentPath() != (QDir::homeDirPath()+"/")) &&
+ QDir(KGlobalSettings::documentPath()).exists())
+ {
+ u.setPath( KGlobalSettings::documentPath() );
+ insertItem( u, i18n("Documents"), false, "document" );
+ }
+
+ u.setPath( QDir::homeDirPath() );
+ insertItem( u, i18n("Home Folder"), false,
+ "folder_home" );
+
+ u = "media:/";
+ if ( KProtocolInfo::isKnownProtocol( u ) )
+ insertItem( u, i18n("Storage Media"), false,
+ KProtocolInfo::icon( "media" ) );
+
+ u = "remote:/";
+ if ( KProtocolInfo::isKnownProtocol( u ) )
+ insertItem( u, i18n("Network Folders"), false,
+ KProtocolInfo::icon( "remote" ) );
+ }
+}
+
+KFileSpeedBar::~KFileSpeedBar()
+{
+}
+
+void KFileSpeedBar::save( KConfig *config )
+{
+ if ( m_initializeSpeedbar && isModified() )
+ {
+ KConfigGroup conf( config, ConfigGroup );
+ // write to kdeglobals
+ conf.writeEntry( "Set speedbar defaults", false, true, true );
+ }
+
+ writeConfig( config, "KFileDialog Speedbar" );
+}
+
+QSize KFileSpeedBar::sizeHint() const
+{
+ QSize sizeHint = KURLBar::sizeHint();
+ int ems = fontMetrics().width("mmmmmmmmmmmm");
+ if (sizeHint.width() < ems)
+ {
+ sizeHint.setWidth(ems);
+ }
+ return sizeHint;
+}
+
+#include "kfilespeedbar.moc"
diff --git a/kio/kfile/kfilespeedbar.h b/kio/kfile/kfilespeedbar.h
new file mode 100644
index 000000000..c941a2398
--- /dev/null
+++ b/kio/kfile/kfilespeedbar.h
@@ -0,0 +1,41 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFILESPEEDBAR_H
+#define KFILESPEEDBAR_H
+
+#include <kurlbar.h>
+
+class KConfig;
+
+class KIO_EXPORT KFileSpeedBar : public KURLBar
+{
+ Q_OBJECT
+public:
+ KFileSpeedBar( QWidget *parent = 0, const char *name = 0 );
+ ~KFileSpeedBar();
+
+ virtual void save( KConfig *config );
+ virtual QSize sizeHint() const;
+
+private:
+ bool m_initializeSpeedbar : 1;
+
+};
+
+#endif // KFILESPEEDBAR_H
diff --git a/kio/kfile/kfiletreebranch.cpp b/kio/kfile/kfiletreebranch.cpp
new file mode 100644
index 000000000..b37662f89
--- /dev/null
+++ b/kio/kfile/kfiletreebranch.cpp
@@ -0,0 +1,528 @@
+/* This file is part of the KDEproject
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2002 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qfile.h>
+
+#include <kfileitem.h>
+#include <kdebug.h>
+#include <kde_file.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "kfiletreeviewitem.h"
+#include "kfiletreebranch.h"
+
+
+/* --- KFileTreeViewToplevelItem --- */
+KFileTreeBranch::KFileTreeBranch( KFileTreeView *parent, const KURL& url,
+ const QString& name,
+ const QPixmap& pix, bool showHidden,
+ KFileTreeViewItem *branchRoot )
+
+ : KDirLister( false ),
+ m_root( branchRoot ),
+ m_startURL( url ),
+ m_name ( name ),
+ m_rootIcon( pix ),
+ m_openRootIcon( pix ),
+ m_recurseChildren(true),
+ m_showExtensions(true)
+{
+ kdDebug( 250) << "Creating branch for url " << url.prettyURL() << endl;
+
+ /* if non exists, create one */
+ if( ! branchRoot )
+ {
+ m_root = new KFileTreeViewItem( parent,
+ new KFileItem( url, "inode/directory",
+ S_IFDIR ),
+ this );
+ }
+
+ m_root->setExpandable( true );
+ m_root->setPixmap( 0, pix );
+ m_root->setText( 0, name );
+
+ setShowingDotFiles( showHidden );
+
+ connect( this, SIGNAL( refreshItems(const KFileItemList&)),
+ this, SLOT ( slotRefreshItems( const KFileItemList& )));
+
+ connect( this, SIGNAL( newItems(const KFileItemList&)),
+ this, SLOT ( addItems( const KFileItemList& )));
+
+ connect( this, SIGNAL( completed(const KURL& )),
+ this, SLOT(slCompleted(const KURL&)));
+
+ connect( this, SIGNAL( started( const KURL& )),
+ this, SLOT( slotListerStarted( const KURL& )));
+
+ connect( this, SIGNAL( deleteItem( KFileItem* )),
+ this, SLOT( slotDeleteItem( KFileItem* )));
+
+ connect( this, SIGNAL( canceled(const KURL&) ),
+ this, SLOT( slotCanceled(const KURL&) ));
+
+ connect( this, SIGNAL( clear()),
+ this, SLOT( slotDirlisterClear()));
+
+ connect( this, SIGNAL( clear(const KURL&)),
+ this, SLOT( slotDirlisterClearURL(const KURL&)));
+
+ connect( this, SIGNAL( redirection( const KURL& , const KURL& ) ),
+ this, SLOT( slotRedirect( const KURL&, const KURL& )));
+
+ m_openChildrenURLs.append( url );
+}
+
+void KFileTreeBranch::setOpenPixmap( const QPixmap& pix )
+{
+ m_openRootIcon = pix;
+
+ if( root()->isOpen())
+ {
+ root()->setPixmap( 0, pix );
+ }
+}
+
+void KFileTreeBranch::slotListerStarted( const KURL &url )
+{
+ /* set the parent correct if it is zero. */
+ kdDebug( 250) << "Starting to list " << url.prettyURL() << endl;
+}
+
+
+KFileTreeViewItem *KFileTreeBranch::parentKFTVItem( KFileItem *item )
+{
+ KFileTreeViewItem *parent = 0;
+
+ if( ! item ) return 0;
+
+ /* If it is a directory, check, if it exists in the dict. If not, go one up
+ * and check again.
+ */
+ KURL url = item->url();
+ // kdDebug(250) << "Item's url is " << url.prettyURL() << endl;
+ KURL dirUrl( url );
+ dirUrl.setFileName( QString::null );
+ // kdDebug(250) << "Directory url is " << dirUrl.prettyURL() << endl;
+
+ parent = findTVIByURL( dirUrl );
+ // kdDebug(250) << "Returning as parent item <" << parent << ">" << endl;
+ return( parent );
+}
+
+
+void KFileTreeBranch::slotRefreshItems( const KFileItemList& list )
+{
+ KFileItemListIterator it( list );
+ kdDebug(250) << "Refreshing " << list.count() << " items !" << endl;
+ KFileItem *currItem;
+ KFileTreeViewItem *item = 0;
+
+ while ( (currItem = it.current()) != 0 )
+ {
+ item = findTVIByURL(currItem->url());
+ if (item) {
+ item->setPixmap(0, item->fileItem()->pixmap( KIcon::SizeSmall ));
+ item->setText( 0, item->fileItem()->text());
+ }
+ ++it;
+ }
+}
+
+void KFileTreeBranch::addItems( const KFileItemList& list )
+{
+ KFileItemListIterator it( list );
+ kdDebug(250) << "Adding " << list.count() << " items !" << endl;
+ KFileItem *currItem;
+ KFileTreeViewItemList treeViewItList;
+ KFileTreeViewItem *parentItem = 0;
+
+ while ( (currItem = it.current()) != 0 )
+ {
+ parentItem = parentKFTVItem( currItem );
+
+
+ /* Only create a new KFileTreeViewItem if it does not yet exist */
+ KFileTreeViewItem *newKFTVI =
+ static_cast<KFileTreeViewItem *>(currItem->extraData( this ));
+
+ if( ! newKFTVI )
+ {
+ newKFTVI = createTreeViewItem( parentItem, currItem );
+ if (!newKFTVI)
+ {
+ // TODO: Don't fail if parentItem == 0
+ ++it;
+ continue;
+ }
+ currItem->setExtraData( this, newKFTVI );
+
+ /* Cut off the file extension in case it is not a directory */
+ if( !m_showExtensions && !currItem->isDir() ) /* Need to cut the extension */
+ {
+ QString name = currItem->text();
+ int mPoint = name.findRev( '.' );
+ if( mPoint > 0 )
+ name = name.left( mPoint );
+ newKFTVI->setText( 0, name );
+ }
+ }
+
+ /* Now try to find out if there are children for dirs in the treeview */
+ /* This stats a directory on the local file system and checks the */
+ /* hardlink entry in the stat-buf. This works only for local directories. */
+ if( dirOnlyMode() && !m_recurseChildren && currItem->isLocalFile( ) && currItem->isDir() )
+ {
+ KURL url = currItem->url();
+ QString filename = url.directory( false, true ) + url.fileName();
+ /* do the stat trick of Carsten. The problem is, that the hardlink
+ * count only contains directory links. Thus, this method only seem
+ * to work in dir-only mode */
+ kdDebug(250) << "Doing stat on " << filename << endl;
+ KDE_struct_stat statBuf;
+ if( KDE_stat( QFile::encodeName( filename ), &statBuf ) == 0 )
+ {
+ int hardLinks = statBuf.st_nlink; /* Count of dirs */
+ kdDebug(250) << "stat succeeded, hardlinks: " << hardLinks << endl;
+ // If the link count is > 2, the directory likely has subdirs. If it's < 2
+ // it's something weird like a mounted SMB share. In that case we don't know
+ // if there are subdirs, thus show it as expandable.
+
+ if( hardLinks != 2 )
+ {
+ newKFTVI->setExpandable(true);
+ }
+ else
+ {
+ newKFTVI->setExpandable(false);
+ }
+ if( hardLinks >= 2 ) // "Normal" directory with subdirs
+ {
+ kdDebug(250) << "Emitting for " << url.prettyURL() << endl;
+ emit( directoryChildCount( newKFTVI, hardLinks-2)); // parentItem, hardLinks-1 ));
+ }
+ }
+ else
+ {
+ kdDebug(250) << "stat of " << filename << " failed !" << endl;
+ }
+ }
+ ++it;
+
+ treeViewItList.append( newKFTVI );
+ }
+
+ emit newTreeViewItems( this, treeViewItList );
+}
+
+KFileTreeViewItem* KFileTreeBranch::createTreeViewItem( KFileTreeViewItem *parent,
+ KFileItem *fileItem )
+{
+ KFileTreeViewItem *tvi = 0;
+ if( parent && fileItem )
+ {
+ tvi = new KFileTreeViewItem( parent,
+ fileItem,
+ this );
+ }
+ else
+ {
+ kdDebug(250) << "createTreeViewItem: Have no parent" << endl;
+ }
+ return( tvi );
+}
+
+void KFileTreeBranch::setChildRecurse( bool t )
+{
+ m_recurseChildren = t;
+ if( t == false )
+ m_openChildrenURLs.clear();
+}
+
+
+void KFileTreeBranch::setShowExtensions( bool visible )
+{
+ m_showExtensions = visible;
+}
+
+bool KFileTreeBranch::showExtensions( ) const
+{
+ return( m_showExtensions );
+}
+
+/*
+ * The signal that tells that a directory was deleted may arrive before the signal
+ * for its children arrive. Thus, we must walk through the children of a dir and
+ * remove them before removing the dir itself.
+ */
+void KFileTreeBranch::slotDeleteItem( KFileItem *it )
+{
+ if( !it ) return;
+ kdDebug(250) << "Slot Delete Item hitted for " << it->url().prettyURL() << endl;
+
+ KFileTreeViewItem *kfti = static_cast<KFileTreeViewItem*>(it->extraData(this));
+
+ if( kfti )
+ {
+ kdDebug( 250 ) << "Child count: " << kfti->childCount() << endl;
+ if( kfti->childCount() > 0 )
+ {
+ KFileTreeViewItem *child = static_cast<KFileTreeViewItem*>(kfti->firstChild());
+
+ while( child )
+ {
+ kdDebug(250) << "Calling child to be deleted !" << endl;
+ KFileTreeViewItem *nextChild = static_cast<KFileTreeViewItem*>(child->nextSibling());
+ slotDeleteItem( child->fileItem());
+ child = nextChild;
+ }
+ }
+
+ kdDebug(250) << "Found corresponding KFileTreeViewItem" << endl;
+ if( m_lastFoundURL.equals(it->url(), true ))
+ {
+ m_lastFoundURL = KURL();
+ m_lastFoundItem = 0L;
+ }
+ delete( kfti );
+ }
+ else
+ {
+ kdDebug(250) << "Error: kfiletreeviewitem: "<< kfti << endl;
+ }
+}
+
+
+void KFileTreeBranch::slotCanceled( const KURL& url )
+{
+ // ### anything else to do?
+ // remove the url from the childrento-recurse-list
+ m_openChildrenURLs.remove( url);
+
+ // stop animations etc.
+ KFileTreeViewItem *item = findTVIByURL(url);
+ if (!item) return; // Uh oh...
+ emit populateFinished(item);
+}
+
+void KFileTreeBranch::slotDirlisterClear()
+{
+ kdDebug(250)<< "*** Clear all !" << endl;
+ /* this slots needs to clear all listed items, but NOT the root item */
+ if( m_root )
+ deleteChildrenOf( m_root );
+}
+
+void KFileTreeBranch::slotDirlisterClearURL( const KURL& url )
+{
+ kdDebug(250)<< "*** Clear for URL !" << url.prettyURL() << endl;
+ KFileItem *item = findByURL( url );
+ if( item )
+ {
+ KFileTreeViewItem *ftvi =
+ static_cast<KFileTreeViewItem *>(item->extraData( this ));
+ deleteChildrenOf( ftvi );
+ }
+}
+
+void KFileTreeBranch::deleteChildrenOf( QListViewItem *parent )
+{
+ // for some strange reason, slotDirlisterClearURL() sometimes calls us
+ // with a 0L parent.
+ if ( !parent )
+ return;
+
+ while ( parent->firstChild() )
+ delete parent->firstChild();
+}
+
+void KFileTreeBranch::slotRedirect( const KURL& oldUrl, const KURL&newUrl )
+{
+ if( oldUrl.equals( m_startURL, true ))
+ {
+ m_startURL = newUrl;
+ }
+}
+
+KFileTreeViewItem* KFileTreeBranch::findTVIByURL( const KURL& url )
+{
+ KFileTreeViewItem *resultItem = 0;
+
+ if( m_startURL.equals(url, true) )
+ {
+ kdDebug(250) << "findByURL: Returning root as a parent !" << endl;
+ resultItem = m_root;
+ }
+ else if( m_lastFoundURL.equals( url, true ))
+ {
+ kdDebug(250) << "findByURL: Returning from lastFoundURL!" << endl;
+ resultItem = m_lastFoundItem;
+ }
+ else
+ {
+ kdDebug(250) << "findByURL: searching by dirlister: " << url.url() << endl;
+
+ KFileItem *it = findByURL( url );
+
+ if( it )
+ {
+ resultItem = static_cast<KFileTreeViewItem*>(it->extraData(this));
+ m_lastFoundItem = resultItem;
+ m_lastFoundURL = url;
+ }
+ }
+
+ return( resultItem );
+}
+
+
+void KFileTreeBranch::slCompleted( const KURL& url )
+{
+ kdDebug(250) << "SlotCompleted hit for " << url.prettyURL() << endl;
+ KFileTreeViewItem *currParent = findTVIByURL( url );
+ if( ! currParent ) return;
+
+ kdDebug(250) << "current parent " << currParent << " is already listed: "
+ << currParent->alreadyListed() << endl;
+
+ emit( populateFinished(currParent));
+ emit( directoryChildCount(currParent, currParent->childCount()));
+
+ /* This is a walk through the children of the last populated directory.
+ * Here we start the dirlister on every child of the dir and wait for its
+ * finish. When it has finished, we go to the next child.
+ * This must be done for non local file systems in dirOnly- and Full-Mode
+ * and for local file systems only in full mode, because the stat trick
+ * (see addItem-Method) does only work for dirs, not for files in the directory.
+ */
+ /* Set bit that the parent dir was listed completely */
+ currParent->setListed(true);
+
+ kdDebug(250) << "recurseChildren: " << m_recurseChildren << endl;
+ kdDebug(250) << "isLocalFile: " << m_startURL.isLocalFile() << endl;
+ kdDebug(250) << "dirOnlyMode: " << dirOnlyMode() << endl;
+
+
+ if( m_recurseChildren && (!m_startURL.isLocalFile() || ! dirOnlyMode()) )
+ {
+ bool wantRecurseUrl = false;
+ /* look if the url is in the list for url to recurse */
+ for ( KURL::List::Iterator it = m_openChildrenURLs.begin();
+ it != m_openChildrenURLs.end(); ++it )
+ {
+ /* it is only interesting that the url _is_in_ the list. */
+ if( (*it).equals( url, true ) )
+ wantRecurseUrl = true;
+ }
+
+ KFileTreeViewItem *nextChild = 0;
+ kdDebug(250) << "Recursing " << url.prettyURL() << "? " << wantRecurseUrl << endl;
+
+ if( wantRecurseUrl && currParent )
+ {
+
+ /* now walk again through the tree and populate the children to get +-signs */
+ /* This is the starting point. The visible folder has finished,
+ processing the children has not yet started */
+ nextChild = static_cast<KFileTreeViewItem*>
+ (static_cast<QListViewItem*>(currParent)->firstChild());
+
+ if( ! nextChild )
+ {
+ /* This happens if there is no child at all */
+ kdDebug( 250 ) << "No children to recuse" << endl;
+ }
+
+ /* Since we have listed the children to recurse, we can remove the entry
+ * in the list of the URLs to see the children.
+ */
+ m_openChildrenURLs.remove(url);
+ }
+
+ if( nextChild ) /* This implies that idx > -1 */
+ {
+ /* Next child is defined. We start a dirlister job on every child item
+ * which is a directory to find out how much children are in the child
+ * of the last opened dir
+ */
+
+ /* Skip non directory entries */
+ while( nextChild )
+ {
+ if( nextChild->isDir() && ! nextChild->alreadyListed())
+ {
+ KFileItem *kfi = nextChild->fileItem();
+ if( kfi && kfi->isReadable())
+ {
+ KURL recurseUrl = kfi->url();
+ kdDebug(250) << "Starting to recurse NOW " << recurseUrl.prettyURL() << endl;
+ openURL( recurseUrl, true );
+ }
+ }
+ nextChild = static_cast<KFileTreeViewItem*>(static_cast<QListViewItem*>(nextChild->nextSibling()));
+ // kdDebug(250) << "Next child " << m_nextChild << endl;
+ }
+ }
+ }
+ else
+ {
+ kdDebug(250) << "skipping to recurse in complete-slot" << endl;
+ }
+}
+
+/* This slot is called when a treeviewitem is expanded in the gui */
+bool KFileTreeBranch::populate( const KURL& url, KFileTreeViewItem *currItem )
+{
+ bool ret = false;
+ if( ! currItem )
+ return ret;
+
+ kdDebug(250) << "Populating <" << url.prettyURL() << ">" << endl;
+
+ /* Add this url to the list of urls to recurse for children */
+ if( m_recurseChildren )
+ {
+ m_openChildrenURLs.append( url );
+ kdDebug(250) << "Appending to list " << url.prettyURL() << endl;
+ }
+
+ if( ! currItem->alreadyListed() )
+ {
+ /* start the lister */
+ ret = openURL( url, true );
+ }
+ else
+ {
+ kdDebug(250) << "Children already existing in treeview!" << endl;
+ slCompleted( url );
+ ret = true;
+ }
+ return ret;
+}
+
+void KFileTreeBranch::virtual_hook( int id, void* data )
+{ KDirLister::virtual_hook( id, data ); }
+
+#include "kfiletreebranch.moc"
+
diff --git a/kio/kfile/kfiletreebranch.h b/kio/kfile/kfiletreebranch.h
new file mode 100644
index 000000000..97d41d9c3
--- /dev/null
+++ b/kio/kfile/kfiletreebranch.h
@@ -0,0 +1,242 @@
+
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2001 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef kfile_tree_branch_h
+#define kfile_tree_branch_h
+
+#include <qdict.h>
+#include <qlistview.h>
+
+#include <kfileitem.h>
+#include <kio/global.h>
+#include <kdirlister.h>
+#include <kio/job.h>
+#include <kfiletreeviewitem.h>
+
+class KURL;
+class KFileTreeView;
+
+
+/**
+ * This is the branch class of the KFileTreeView, which represents one
+ * branch in the treeview. Every branch has a root which is an url. The branch
+ * lists the files under the root. Every branch uses its own dirlister and can
+ * have its own filter etc.
+ *
+ * @short Branch object for KFileTreeView object.
+ *
+ */
+
+class KIO_EXPORT KFileTreeBranch : public KDirLister
+{
+ Q_OBJECT
+public:
+ /**
+ * constructs a branch for KFileTreeView. Does not yet start to list it.
+ * @param url start url of the branch.
+ * @param name the name of the branch, which is displayed in the first column of the treeview.
+ * @param pix is a pixmap to display as an icon of the branch.
+ * @param showHidden flag to make hidden files visible or not.
+ * @param branchRoot is the KFileTreeViewItem to use as the root of the
+ * branch, with the default 0 meaning to let KFileTreeBranch create
+ * it for you.
+ */
+ KFileTreeBranch( KFileTreeView*, const KURL& url, const QString& name,
+ const QPixmap& pix, bool showHidden = false,
+ KFileTreeViewItem *branchRoot = 0 );
+
+ /**
+ * @returns the root url of the branch.
+ */
+ KURL rootUrl() const { return( m_startURL ); }
+
+ /**
+ * sets a KFileTreeViewItem as root widget for the branch.
+ * That must be created outside of the branch. All KFileTreeViewItems
+ * the branch is allocating will become children of that object.
+ * @param r the KFileTreeViewItem to become the root item.
+ */
+ virtual void setRoot( KFileTreeViewItem *r ){ m_root = r; };
+
+ /**
+ * @returns the root item.
+ */
+ KFileTreeViewItem *root( ) { return( m_root );}
+
+ /**
+ * @returns the name of the branch.
+ */
+ QString name() const { return( m_name ); }
+
+ /**
+ * sets the name of the branch.
+ */
+ virtual void setName( const QString n ) { m_name = n; };
+
+ /*
+ * returns the current root item pixmap set in the constructor. The root
+ * item pixmap defaults to the icon for directories.
+ * @see openPixmap()
+ */
+ const QPixmap& pixmap(){ return(m_rootIcon); }
+
+ /*
+ * returns the current root item pixmap set by setOpenPixmap()
+ * which is displayed if the branch is expanded.
+ * The root item pixmap defaults to the icon for directories.
+ * @see pixmap()
+ * Note that it depends on KFileTreeView::showFolderOpenPximap weather
+ * open pixmap are displayed or not.
+ */
+ const QPixmap& openPixmap() { return(m_openRootIcon); }
+
+ /**
+ * @returns whether the items in the branch show their file extensions in the
+ * tree or not. See setShowExtensions for more information.
+ */
+ bool showExtensions( ) const;
+
+ /**
+ * sets the root of the branch open or closed.
+ */
+ void setOpen( bool setopen = true )
+ { if( root() ) root()->setOpen( setopen ); }
+
+ /**
+ * sets if children recursion is wanted or not. If this is switched off, the
+ * child directories of a just opened directory are not listed internally.
+ * That means that it can not be determined if the sub directories are
+ * expandable or not. If this is switched off there will be no call to
+ * setExpandable.
+ * @param t set to true to switch on child recursion
+ */
+ void setChildRecurse( bool t=true );
+
+ /**
+ * @returns if child recursion is on or off.
+ * @see setChildRecurse
+ */
+ bool childRecurse()
+ { return m_recurseChildren; }
+
+public slots:
+ /**
+ * populates a branch. This method must be called after a branch was added
+ * to a KFileTreeView using method addBranch.
+ * @param url is the url of the root item where the branch starts.
+ * @param currItem is the current parent.
+ */
+ virtual bool populate( const KURL &url, KFileTreeViewItem* currItem );
+
+ /**
+ * sets printing of the file extensions on or off. If you pass false to this
+ * slot, all items of this branch will not show their file extensions in the
+ * tree.
+ * @param visible flags if the extensions should be visible or not.
+ */
+ virtual void setShowExtensions( bool visible = true );
+
+ void setOpenPixmap( const QPixmap& pix );
+
+protected:
+ /**
+ * allocates a KFileTreeViewItem for the branch
+ * for new items.
+ */
+ virtual KFileTreeViewItem *createTreeViewItem( KFileTreeViewItem *parent,
+ KFileItem *fileItem );
+
+public:
+ /**
+ * find the according KFileTreeViewItem by an url
+ */
+ virtual KFileTreeViewItem *findTVIByURL( const KURL& );
+
+signals:
+ /**
+ * emitted with the item of a directory which was finished to populate
+ */
+ void populateFinished( KFileTreeViewItem * );
+
+ /**
+ * emitted with a list of new or updated KFileTreeViewItem which were
+ * found in a branch. Note that this signal is emitted very often and may slow
+ * down the performance of the treeview !
+ */
+ void newTreeViewItems( KFileTreeBranch*, const KFileTreeViewItemList& );
+
+ /**
+ * emitted with the exact count of children for a directory.
+ */
+ void directoryChildCount( KFileTreeViewItem* item, int count );
+
+private slots:
+ void slotRefreshItems( const KFileItemList& );
+ void addItems( const KFileItemList& );
+ void slCompleted( const KURL& );
+ void slotCanceled( const KURL& );
+ void slotListerStarted( const KURL& );
+ void slotDeleteItem( KFileItem* );
+ void slotDirlisterClear();
+ void slotDirlisterClearURL( const KURL& url );
+ void slotRedirect( const KURL& oldUrl, const KURL&newUrl );
+
+private:
+ KFileTreeViewItem *parentKFTVItem( KFileItem *item );
+ static void deleteChildrenOf( QListViewItem *parent );
+
+ KFileTreeViewItem *m_root;
+ KURL m_startURL;
+ QString m_name;
+ QPixmap m_rootIcon;
+ QPixmap m_openRootIcon;
+
+ /* this list holds the url's which children are opened. */
+ KURL::List m_openChildrenURLs;
+
+
+ /* The next two members are used for caching purposes in findTVIByURL. */
+ KURL m_lastFoundURL;
+ KFileTreeViewItem *m_lastFoundItem;
+
+ bool m_recurseChildren :1;
+ bool m_showExtensions :1;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileTreeBranchPrivate;
+ KFileTreeBranchPrivate *d;
+};
+
+
+/**
+ * List of KFileTreeBranches
+ */
+typedef QPtrList<KFileTreeBranch> KFileTreeBranchList;
+
+/**
+ * Iterator for KFileTreeBranchLists
+ */
+typedef QPtrListIterator<KFileTreeBranch> KFileTreeBranchIterator;
+
+#endif
+
diff --git a/kio/kfile/kfiletreeview.cpp b/kio/kfile/kfiletreeview.cpp
new file mode 100644
index 000000000..542e80d5b
--- /dev/null
+++ b/kio/kfile/kfiletreeview.cpp
@@ -0,0 +1,677 @@
+/* This file is part of the KDEproject
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qapplication.h>
+#include <qheader.h>
+#include <qtimer.h>
+#include <kdebug.h>
+#include <kdirnotify_stub.h>
+#include <kglobalsettings.h>
+#include <kfileitem.h>
+#include <kfileview.h>
+#include <kmimetype.h>
+#include <kstandarddirs.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <kio/job.h>
+#include <kio/global.h>
+#include <kurldrag.h>
+#include <kiconloader.h>
+
+
+#include "kfiletreeview.h"
+#include "kfiletreebranch.h"
+#include "kfiletreeviewitem.h"
+
+KFileTreeView::KFileTreeView( QWidget *parent, const char *name )
+ : KListView( parent, name ),
+ m_wantOpenFolderPixmaps( true ),
+ m_toolTip( this )
+{
+ setDragEnabled(true);
+ setSelectionModeExt( KListView::Single );
+
+ m_animationTimer = new QTimer( this );
+ connect( m_animationTimer, SIGNAL( timeout() ),
+ this, SLOT( slotAnimation() ) );
+
+ m_currentBeforeDropItem = 0;
+ m_dropItem = 0;
+
+ m_autoOpenTimer = new QTimer( this );
+ connect( m_autoOpenTimer, SIGNAL( timeout() ),
+ this, SLOT( slotAutoOpenFolder() ) );
+
+ /* The executed-Slot only opens a path, while the expanded-Slot populates it */
+ connect( this, SIGNAL( executed( QListViewItem * ) ),
+ this, SLOT( slotExecuted( QListViewItem * ) ) );
+ connect( this, SIGNAL( expanded ( QListViewItem *) ),
+ this, SLOT( slotExpanded( QListViewItem *) ));
+ connect( this, SIGNAL( collapsed( QListViewItem *) ),
+ this, SLOT( slotCollapsed( QListViewItem* )));
+
+
+ /* connections from the konqtree widget */
+ connect( this, SIGNAL( selectionChanged() ),
+ this, SLOT( slotSelectionChanged() ) );
+ connect( this, SIGNAL( onItem( QListViewItem * )),
+ this, SLOT( slotOnItem( QListViewItem * ) ) );
+ connect( this, SIGNAL(itemRenamed(QListViewItem*, const QString &, int)),
+ this, SLOT(slotItemRenamed(QListViewItem*, const QString &, int)));
+
+
+ m_bDrag = false;
+ m_branches.setAutoDelete( true );
+
+ m_openFolderPixmap = DesktopIcon( "folder_open",KIcon::SizeSmall,KIcon::ActiveState );
+}
+
+KFileTreeView::~KFileTreeView()
+{
+ // we must make sure that the KFileTreeViewItems are deleted _before_ the
+ // branches are deleted. Otherwise, the KFileItems would be destroyed
+ // and the KFileTreeViewItems had dangling pointers to them.
+ hide();
+ clear();
+ m_branches.clear(); // finally delete the branches and KFileItems
+}
+
+
+bool KFileTreeView::isValidItem( QListViewItem *item)
+{
+ if (!item)
+ return false;
+ QPtrList<QListViewItem> lst;
+ QListViewItemIterator it( this );
+ while ( it.current() )
+ {
+ if ( it.current() == item )
+ return true;
+ ++it;
+ }
+ return false;
+}
+
+void KFileTreeView::contentsDragEnterEvent( QDragEnterEvent *ev )
+{
+ if ( ! acceptDrag( ev ) )
+ {
+ ev->ignore();
+ return;
+ }
+ ev->acceptAction();
+ m_currentBeforeDropItem = selectedItem();
+
+ QListViewItem *item = itemAt( contentsToViewport( ev->pos() ) );
+ if( item )
+ {
+ m_dropItem = item;
+ m_autoOpenTimer->start( KFileView::autoOpenDelay() );
+ }
+ else
+ {
+ m_dropItem = 0;
+}
+}
+
+void KFileTreeView::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ if( ! acceptDrag( e ) )
+ {
+ e->ignore();
+ return;
+ }
+ e->acceptAction();
+
+
+ QListViewItem *afterme;
+ QListViewItem *parent;
+
+ findDrop( e->pos(), parent, afterme );
+
+ // "afterme" is 0 when aiming at a directory itself
+ QListViewItem *item = afterme ? afterme : parent;
+
+ if( item && item->isSelectable() )
+ {
+ setSelected( item, true );
+ if( item != m_dropItem ) {
+ m_autoOpenTimer->stop();
+ m_dropItem = item;
+ m_autoOpenTimer->start( KFileView::autoOpenDelay() );
+ }
+ }
+ else
+ {
+ m_autoOpenTimer->stop();
+ m_dropItem = 0;
+ }
+}
+
+void KFileTreeView::contentsDragLeaveEvent( QDragLeaveEvent * )
+{
+ // Restore the current item to what it was before the dragging (#17070)
+ if ( isValidItem(m_currentBeforeDropItem) )
+ {
+ setSelected( m_currentBeforeDropItem, true );
+ ensureItemVisible( m_currentBeforeDropItem );
+ }
+ else if ( isValidItem(m_dropItem) )
+ setSelected( m_dropItem, false ); // no item selected
+ m_currentBeforeDropItem = 0;
+ m_dropItem = 0;
+
+}
+
+void KFileTreeView::contentsDropEvent( QDropEvent *e )
+{
+
+ m_autoOpenTimer->stop();
+ m_dropItem = 0;
+
+ kdDebug(250) << "contentsDropEvent !" << endl;
+ if( ! acceptDrag( e ) ) {
+ e->ignore();
+ return;
+ }
+
+ e->acceptAction();
+ QListViewItem *afterme;
+ QListViewItem *parent;
+ findDrop(e->pos(), parent, afterme);
+
+ //kdDebug(250) << " parent=" << (parent?parent->text(0):QString::null)
+ // << " afterme=" << (afterme?afterme->text(0):QString::null) << endl;
+
+ if (e->source() == viewport() && itemsMovable())
+ movableDropEvent(parent, afterme);
+ else
+ {
+ emit dropped(e, afterme);
+ emit dropped(this, e, afterme);
+ emit dropped(e, parent, afterme);
+ emit dropped(this, e, parent, afterme);
+
+ KURL::List urls;
+ KURLDrag::decode( e, urls );
+ emit dropped( this, e, urls );
+
+ KURL parentURL;
+ if( parent )
+ parentURL = static_cast<KFileTreeViewItem*>(parent)->url();
+ else
+ // can happen when dropping above the root item
+ // Should we choose the first branch in such a case ??
+ return;
+
+ emit dropped( urls, parentURL );
+ emit dropped( this , e, urls, parentURL );
+ }
+}
+
+bool KFileTreeView::acceptDrag(QDropEvent* e ) const
+{
+
+ bool ancestOK= acceptDrops();
+ // kdDebug(250) << "Do accept drops: " << ancestOK << endl;
+ ancestOK = ancestOK && itemsMovable();
+ // kdDebug(250) << "acceptDrag: " << ancestOK << endl;
+ // kdDebug(250) << "canDecode: " << KURLDrag::canDecode(e) << endl;
+ // kdDebug(250) << "action: " << e->action() << endl;
+
+ /* KListView::acceptDrag(e); */
+ /* this is what KListView does:
+ * acceptDrops() && itemsMovable() && (e->source()==viewport());
+ * ask acceptDrops and itemsMovable, but not the third
+ */
+ return ancestOK && KURLDrag::canDecode( e ) &&
+ // Why this test? All DnDs are one of those AFAIK (DF)
+ ( e->action() == QDropEvent::Copy
+ || e->action() == QDropEvent::Move
+ || e->action() == QDropEvent::Link );
+}
+
+
+
+QDragObject * KFileTreeView::dragObject()
+{
+
+ KURL::List urls;
+ const QPtrList<QListViewItem> fileList = selectedItems();
+ QPtrListIterator<QListViewItem> it( fileList );
+ for ( ; it.current(); ++it )
+ {
+ urls.append( static_cast<KFileTreeViewItem*>(it.current())->url() );
+ }
+ QPoint hotspot;
+ QPixmap pixmap;
+ if( urls.count() > 1 ){
+ pixmap = DesktopIcon( "kmultiple", 16 );
+ }
+ if( pixmap.isNull() )
+ pixmap = currentKFileTreeViewItem()->fileItem()->pixmap( 16 );
+ hotspot.setX( pixmap.width() / 2 );
+ hotspot.setY( pixmap.height() / 2 );
+ QDragObject* dragObject = new KURLDrag( urls, this );
+ if( dragObject )
+ dragObject->setPixmap( pixmap, hotspot );
+ return dragObject;
+}
+
+
+
+void KFileTreeView::slotCollapsed( QListViewItem *item )
+{
+ KFileTreeViewItem *kftvi = static_cast<KFileTreeViewItem*>(item);
+ kdDebug(250) << "hit slotCollapsed" << endl;
+ if( kftvi && kftvi->isDir())
+ {
+ item->setPixmap( 0, itemIcon(kftvi));
+ }
+}
+
+void KFileTreeView::slotExpanded( QListViewItem *item )
+{
+ kdDebug(250) << "slotExpanded here !" << endl;
+
+ if( ! item ) return;
+
+ KFileTreeViewItem *it = static_cast<KFileTreeViewItem*>(item);
+ KFileTreeBranch *branch = it->branch();
+
+ /* Start the animation for the branch object */
+ if( it->isDir() && branch && item->childCount() == 0 )
+ {
+ /* check here if the branch really needs to be populated again */
+ kdDebug(250 ) << "starting to open " << it->url().prettyURL() << endl;
+ startAnimation( it );
+ bool branchAnswer = branch->populate( it->url(), it );
+ kdDebug(250) << "Branches answer: " << branchAnswer << endl;
+ if( ! branchAnswer )
+ {
+ kdDebug(250) << "ERR: Could not populate!" << endl;
+ stopAnimation( it );
+ }
+ }
+
+ /* set a pixmap 'open folder' */
+ if( it->isDir() && isOpen( item ) )
+ {
+ kdDebug(250)<< "Setting open Pixmap" << endl;
+ item->setPixmap( 0, itemIcon( it )); // 0, m_openFolderPixmap );
+ }
+}
+
+
+
+void KFileTreeView::slotExecuted( QListViewItem *item )
+{
+ if ( !item )
+ return;
+ /* This opens the dir and causes the Expanded-slot to be called,
+ * which strolls through the children.
+ */
+ if( static_cast<KFileTreeViewItem*>(item)->isDir())
+ {
+ item->setOpen( !item->isOpen() );
+ }
+}
+
+
+void KFileTreeView::slotAutoOpenFolder()
+{
+ m_autoOpenTimer->stop();
+
+ if ( !isValidItem(m_dropItem) || m_dropItem->isOpen() )
+ return;
+
+ m_dropItem->setOpen( true );
+ m_dropItem->repaint();
+}
+
+
+void KFileTreeView::slotSelectionChanged()
+{
+ if ( !m_dropItem ) // don't do this while the dragmove thing
+ {
+ }
+}
+
+
+KFileTreeBranch* KFileTreeView::addBranch( const KURL &path, const QString& name,
+ bool showHidden )
+{
+ const QPixmap& folderPix = KMimeType::mimeType("inode/directory")->pixmap( KIcon::Desktop,KIcon::SizeSmall );
+
+ return addBranch( path, name, folderPix, showHidden);
+}
+
+KFileTreeBranch* KFileTreeView::addBranch( const KURL &path, const QString& name,
+ const QPixmap& pix, bool showHidden )
+{
+ kdDebug(250) << "adding another root " << path.prettyURL() << endl;
+
+ /* Open a new branch */
+ KFileTreeBranch *newBranch = new KFileTreeBranch( this, path, name, pix,
+ showHidden );
+ return addBranch(newBranch);
+}
+
+KFileTreeBranch *KFileTreeView::addBranch(KFileTreeBranch *newBranch)
+{
+ connect( newBranch, SIGNAL(populateFinished( KFileTreeViewItem* )),
+ this, SLOT( slotPopulateFinished( KFileTreeViewItem* )));
+
+ connect( newBranch, SIGNAL( newTreeViewItems( KFileTreeBranch*,
+ const KFileTreeViewItemList& )),
+ this, SLOT( slotNewTreeViewItems( KFileTreeBranch*,
+ const KFileTreeViewItemList& )));
+
+ m_branches.append( newBranch );
+ return( newBranch );
+}
+
+KFileTreeBranch *KFileTreeView::branch( const QString& searchName )
+{
+ KFileTreeBranch *branch = 0;
+ QPtrListIterator<KFileTreeBranch> it( m_branches );
+
+ while ( (branch = it.current()) != 0 ) {
+ ++it;
+ QString bname = branch->name();
+ kdDebug(250) << "This is the branches name: " << bname << endl;
+ if( bname == searchName )
+ {
+ kdDebug(250) << "Found branch " << bname << " and return ptr" << endl;
+ return( branch );
+ }
+ }
+ return ( 0L );
+}
+
+KFileTreeBranchList& KFileTreeView::branches()
+{
+ return( m_branches );
+}
+
+
+bool KFileTreeView::removeBranch( KFileTreeBranch *branch )
+{
+ if(m_branches.contains(branch))
+ {
+ delete (branch->root());
+ m_branches.remove( branch );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void KFileTreeView::setDirOnlyMode( KFileTreeBranch* branch, bool bom )
+{
+ if( branch )
+ {
+ branch->setDirOnlyMode( bom );
+ }
+}
+
+
+void KFileTreeView::slotPopulateFinished( KFileTreeViewItem *it )
+{
+ if( it && it->isDir())
+ stopAnimation( it );
+}
+
+void KFileTreeView::slotNewTreeViewItems( KFileTreeBranch* branch, const KFileTreeViewItemList& itemList )
+{
+ if( ! branch ) return;
+ kdDebug(250) << "hitting slotNewTreeViewItems" << endl;
+
+ /* Sometimes it happens that new items should become selected, i.e. if the user
+ * creates a new dir, he probably wants it to be selected. This can not be done
+ * right after creating the directory or file, because it takes some time until
+ * the item appears here in the treeview. Thus, the creation code sets the member
+ * m_neUrlToSelect to the required url. If this url appears here, the item becomes
+ * selected and the member nextUrlToSelect will be cleared.
+ */
+ if( ! m_nextUrlToSelect.isEmpty() )
+ {
+ KFileTreeViewItemListIterator it( itemList );
+
+ bool end = false;
+ for( ; !end && it.current(); ++it )
+ {
+ KURL url = (*it)->url();
+
+ if( m_nextUrlToSelect.equals(url, true )) // ignore trailing / on dirs
+ {
+ setCurrentItem( static_cast<QListViewItem*>(*it) );
+ m_nextUrlToSelect = KURL();
+ end = true;
+ }
+ }
+ }
+}
+
+QPixmap KFileTreeView::itemIcon( KFileTreeViewItem *item, int gap ) const
+{
+ QPixmap pix;
+ kdDebug(250) << "Setting icon for column " << gap << endl;
+
+ if( item )
+ {
+ /* Check if it is a branch root */
+ KFileTreeBranch *brnch = item->branch();
+ if( item == brnch->root() )
+ {
+ pix = brnch->pixmap();
+ if( m_wantOpenFolderPixmaps && brnch->root()->isOpen() )
+ {
+ pix = brnch->openPixmap();
+ }
+ }
+ else
+ {
+ // TODO: different modes, user Pixmaps ?
+ pix = item->fileItem()->pixmap( KIcon::SizeSmall ); // , KIcon::DefaultState);
+
+ /* Only if it is a dir and the user wants open dir pixmap and it is open,
+ * change the fileitem's pixmap to the open folder pixmap. */
+ if( item->isDir() && m_wantOpenFolderPixmaps )
+ {
+ if( isOpen( static_cast<QListViewItem*>(item)))
+ pix = m_openFolderPixmap;
+ }
+ }
+ }
+
+ return pix;
+}
+
+
+void KFileTreeView::slotAnimation()
+{
+ MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.begin();
+ MapCurrentOpeningFolders::Iterator end = m_mapCurrentOpeningFolders.end();
+ for (; it != end;)
+ {
+ KFileTreeViewItem *item = it.key();
+ if (!isValidItem(item))
+ {
+ ++it;
+ m_mapCurrentOpeningFolders.remove(item);
+ continue;
+ }
+
+ uint & iconNumber = it.data().iconNumber;
+ QString icon = QString::fromLatin1( it.data().iconBaseName ).append( QString::number( iconNumber ) );
+ // kdDebug(250) << "Loading icon " << icon << endl;
+ item->setPixmap( 0, DesktopIcon( icon,KIcon::SizeSmall,KIcon::ActiveState )); // KFileTreeViewFactory::instance() ) );
+
+ iconNumber++;
+ if ( iconNumber > it.data().iconCount )
+ iconNumber = 1;
+
+ ++it;
+ }
+}
+
+
+void KFileTreeView::startAnimation( KFileTreeViewItem * item, const char * iconBaseName, uint iconCount )
+{
+ /* TODO: allow specific icons */
+ if( ! item )
+ {
+ kdDebug(250) << " startAnimation Got called without valid item !" << endl;
+ return;
+ }
+
+ m_mapCurrentOpeningFolders.insert( item,
+ AnimationInfo( iconBaseName,
+ iconCount,
+ itemIcon(item, 0) ) );
+ if ( !m_animationTimer->isActive() )
+ m_animationTimer->start( 50 );
+}
+
+void KFileTreeView::stopAnimation( KFileTreeViewItem * item )
+{
+ if( ! item ) return;
+
+ kdDebug(250) << "Stoping Animation !" << endl;
+
+ MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.find(item);
+ if ( it != m_mapCurrentOpeningFolders.end() )
+ {
+ if( item->isDir() && isOpen( item) )
+ {
+ kdDebug(250) << "Setting folder open pixmap !" << endl;
+ item->setPixmap( 0, itemIcon( item ));
+ }
+ else
+ {
+ item->setPixmap( 0, it.data().originalPixmap );
+ }
+ m_mapCurrentOpeningFolders.remove( item );
+ }
+ else
+ {
+ if( item )
+ kdDebug(250)<< "StopAnimation - could not find item " << item->url().prettyURL()<< endl;
+ else
+ kdDebug(250)<< "StopAnimation - item is zero !" << endl;
+ }
+ if (m_mapCurrentOpeningFolders.isEmpty())
+ m_animationTimer->stop();
+}
+
+KFileTreeViewItem * KFileTreeView::currentKFileTreeViewItem() const
+{
+ return static_cast<KFileTreeViewItem *>( selectedItem() );
+}
+
+KURL KFileTreeView::currentURL() const
+{
+ KFileTreeViewItem *item = currentKFileTreeViewItem();
+ if ( item )
+ return currentKFileTreeViewItem()->url();
+ else
+ return KURL();
+}
+
+void KFileTreeView::slotOnItem( QListViewItem *item )
+{
+ KFileTreeViewItem *i = static_cast<KFileTreeViewItem *>( item );
+ if( i )
+ {
+ const KURL url = i->url();
+ if ( url.isLocalFile() )
+ emit onItem( url.path() );
+ else
+ emit onItem( url.prettyURL() );
+ }
+}
+
+void KFileTreeView::slotItemRenamed(QListViewItem* item, const QString &name, int col)
+{
+ (void) item;
+ kdDebug(250) << "Do not bother: " << name << col << endl;
+}
+
+KFileTreeViewItem *KFileTreeView::findItem( const QString& branchName, const QString& relUrl )
+{
+ KFileTreeBranch *br = branch( branchName );
+ return( findItem( br, relUrl ));
+}
+
+KFileTreeViewItem *KFileTreeView::findItem( KFileTreeBranch* brnch, const QString& relUrl )
+{
+ KFileTreeViewItem *ret = 0;
+ if( brnch )
+ {
+ KURL url = brnch->rootUrl();
+
+ if( ! relUrl.isEmpty() && QDir::isRelativePath(relUrl) )
+ {
+ QString partUrl( relUrl );
+
+ if( partUrl.endsWith("/"))
+ partUrl.truncate( relUrl.length()-1 );
+
+ url.addPath( partUrl );
+
+ kdDebug(250) << "assembled complete dir string " << url.prettyURL() << endl;
+
+ KFileItem *fi = brnch->findByURL( url );
+ if( fi )
+ {
+ ret = static_cast<KFileTreeViewItem*>( fi->extraData( brnch ));
+ kdDebug(250) << "Found item !" <<ret << endl;
+ }
+ }
+ else
+ {
+ ret = brnch->root();
+ }
+ }
+ return( ret );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+void KFileTreeViewToolTip::maybeTip( const QPoint & )
+{
+#if 0
+ QListViewItem *item = m_view->itemAt( point );
+ if ( item ) {
+ QString text = static_cast<KFileViewItem*>( item )->toolTipText();
+ if ( !text.isEmpty() )
+ tip ( m_view->itemRect( item ), text );
+ }
+#endif
+}
+
+void KFileTreeView::virtual_hook( int id, void* data )
+{ KListView::virtual_hook( id, data ); }
+
+#include "kfiletreeview.moc"
diff --git a/kio/kfile/kfiletreeview.h b/kio/kfile/kfiletreeview.h
new file mode 100644
index 000000000..93af623a6
--- /dev/null
+++ b/kio/kfile/kfiletreeview.h
@@ -0,0 +1,273 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2002 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef kfile_tree_view_h
+#define kfile_tree_view_h
+
+#include <qmap.h>
+#include <qpoint.h>
+#include <qpixmap.h>
+#include <qstrlist.h>
+#include <qtooltip.h>
+
+#include <klistview.h>
+#include <kdirnotify.h>
+#include <kio/job.h>
+#include <kfiletreeviewitem.h>
+#include <kfiletreebranch.h>
+
+class QTimer;
+
+
+
+class KIO_EXPORT KFileTreeViewToolTip : public QToolTip
+{
+public:
+ KFileTreeViewToolTip( QListView *view ) : QToolTip( view ), m_view( view ) {}
+
+protected:
+ virtual void maybeTip( const QPoint & );
+
+private:
+ QListView *m_view;
+};
+
+
+/**
+ * The filetreeview offers a treeview on the file system which behaves like
+ * a QTreeView showing files and/or directories in the file system.
+ *
+ * KFileTreeView is able to handle more than one URL, represented by
+ * KFileTreeBranch.
+ *
+ * Typical usage:
+ * 1. create a KFileTreeView fitting in your layout and add columns to it
+ * 2. call addBranch to create one or more branches
+ * 3. retrieve the root item with KFileTreeBranch::root() and set it open
+ * if desired. That starts the listing.
+ */
+class KIO_EXPORT KFileTreeView : public KListView
+{
+ Q_OBJECT
+public:
+ KFileTreeView( QWidget *parent, const char *name = 0 );
+ virtual ~KFileTreeView();
+
+ /**
+ * @return the current (i.e. selected) item
+ */
+ KFileTreeViewItem * currentKFileTreeViewItem() const;
+
+ /**
+ * @return the URL of the current selected item.
+ */
+ KURL currentURL() const;
+
+ /**
+ * Adds a branch to the treeview item.
+ *
+ * This high-level function creates the branch, adds it to the treeview and
+ * connects some signals. Note that directory listing does not start until
+ * a branch is expanded either by opening the root item by user or by setOpen
+ * on the root item.
+ *
+ * @returns a pointer to the new branch or zero
+ * @param path is the base url of the branch
+ * @param name is the name of the branch, which will be the text for column 0
+ * @param showHidden says if hidden files and directories should be visible
+ */
+ KFileTreeBranch* addBranch( const KURL &path, const QString& name, bool showHidden = false );
+
+ /**
+ * same as the function above but with a pixmap to set for the branch.
+ */
+ virtual KFileTreeBranch* addBranch( const KURL &path, const QString& name ,
+ const QPixmap& pix, bool showHidden = false );
+
+ /**
+ * same as the function above but letting the user create the branch.
+ */
+ virtual KFileTreeBranch* addBranch( KFileTreeBranch * );
+
+ /**
+ * removes the branch from the treeview.
+ * @param branch is a pointer to the branch
+ * @returns true on success.
+ */
+ virtual bool removeBranch( KFileTreeBranch *branch );
+
+ /**
+ * @returns a pointer to the KFileTreeBranch in the KFileTreeView or zero on failure.
+ * @param searchName is the name of a branch
+ */
+ KFileTreeBranch *branch( const QString& searchName );
+
+
+ /**
+ * @returns a list of pointers to all existing branches in the treeview.
+ **/
+ KFileTreeBranchList& branches();
+
+ /**
+ * set the directory mode for branches. If true is passed, only directories will be loaded.
+ * @param branch is a pointer to a KFileTreeBranch
+ */
+ virtual void setDirOnlyMode( KFileTreeBranch *branch, bool );
+
+ /**
+ * searches a branch for a KFileTreeViewItem identified by the relative url given as
+ * second parameter. The method adds the branches base url to the relative path and finds
+ * the item.
+ * @returns a pointer to the item or zero if the item does not exist.
+ * @param brnch is a pointer to the branch to search in
+ * @param relUrl is the branch relativ url
+ */
+ KFileTreeViewItem *findItem( KFileTreeBranch* brnch, const QString& relUrl );
+
+ /**
+ * see method above, differs only in the first parameter. Finds the branch by its name.
+ */
+ KFileTreeViewItem *findItem( const QString& branchName, const QString& relUrl );
+
+ /**
+ * @returns a flag indicating if extended folder pixmaps are displayed or not.
+ */
+ bool showFolderOpenPixmap() const { return m_wantOpenFolderPixmaps; };
+
+public slots:
+
+ /**
+ * set the flag to show 'extended' folder icons on or off. If switched on, folders will
+ * have an open folder pixmap displayed if their children are visible, and the standard
+ * closed folder pixmap (from mimetype folder) if they are closed.
+ * If switched off, the plain mime pixmap is displayed.
+ * @param showIt = false displays mime type pixmap only
+ */
+ virtual void setShowFolderOpenPixmap( bool showIt = true )
+ { m_wantOpenFolderPixmaps = showIt; }
+
+protected:
+ /**
+ * @returns true if we can decode the drag and support the action
+ */
+
+ virtual bool acceptDrag(QDropEvent* event) const;
+ virtual QDragObject * dragObject();
+
+ virtual void startAnimation( KFileTreeViewItem* item, const char * iconBaseName = "kde", uint iconCount = 6 );
+ virtual void stopAnimation( KFileTreeViewItem* item );
+ virtual void contentsDragEnterEvent( QDragEnterEvent *e );
+ virtual void contentsDragMoveEvent( QDragMoveEvent *e );
+ virtual void contentsDragLeaveEvent( QDragLeaveEvent *e );
+ virtual void contentsDropEvent( QDropEvent *ev );
+
+protected slots:
+ virtual void slotNewTreeViewItems( KFileTreeBranch*,
+ const KFileTreeViewItemList& );
+
+ virtual void slotSetNextUrlToSelect( const KURL &url )
+ { m_nextUrlToSelect = url; }
+
+ virtual QPixmap itemIcon( KFileTreeViewItem*, int gap = 0 ) const;
+
+private slots:
+ void slotExecuted( QListViewItem * );
+ void slotExpanded( QListViewItem * );
+ void slotCollapsed( QListViewItem *item );
+
+ void slotSelectionChanged();
+
+ void slotAnimation();
+
+ void slotAutoOpenFolder();
+
+ void slotOnItem( QListViewItem * );
+ void slotItemRenamed(QListViewItem*, const QString &, int);
+
+ void slotPopulateFinished( KFileTreeViewItem* );
+
+
+signals:
+
+ void onItem( const QString& );
+ /* New signals if you like it ? */
+ void dropped( QWidget*, QDropEvent* );
+ void dropped( QWidget*, QDropEvent*, KURL::List& );
+ void dropped( KURL::List&, KURL& );
+ // The drop event allows to differentiate between move and copy
+ void dropped( QWidget*, QDropEvent*, KURL::List&, KURL& );
+
+ void dropped( QDropEvent *e, QListViewItem * after);
+ void dropped(KFileTreeView *, QDropEvent *, QListViewItem *);
+ void dropped(QDropEvent *e, QListViewItem * parent, QListViewItem * after);
+ void dropped(KFileTreeView *, QDropEvent *, QListViewItem *, QListViewItem *);
+
+protected:
+ KURL m_nextUrlToSelect;
+
+
+private:
+ // Returns whether item is still a valid item in the tree
+ bool isValidItem( QListViewItem *item);
+ void clearTree();
+
+
+ /* List that holds the branches */
+ KFileTreeBranchList m_branches;
+
+
+ struct AnimationInfo
+ {
+ AnimationInfo( const char * _iconBaseName, uint _iconCount, const QPixmap & _originalPixmap )
+ : iconBaseName(_iconBaseName), iconCount(_iconCount), iconNumber(1), originalPixmap(_originalPixmap) {}
+ AnimationInfo() : iconCount(0) {}
+ QCString iconBaseName;
+ uint iconCount;
+ uint iconNumber;
+ QPixmap originalPixmap;
+ };
+ typedef QMap<KFileTreeViewItem *, AnimationInfo> MapCurrentOpeningFolders;
+ MapCurrentOpeningFolders m_mapCurrentOpeningFolders;
+
+
+ QTimer *m_animationTimer;
+
+ QPoint m_dragPos;
+ bool m_bDrag;
+
+ bool m_wantOpenFolderPixmaps; // Flag weather the folder should have open-folder pixmaps
+
+ QListViewItem *m_currentBeforeDropItem; // The item that was current before the drag-enter event happened
+ QListViewItem *m_dropItem; // The item we are moving the mouse over (during a drag)
+ QStrList m_lstDropFormats;
+ QPixmap m_openFolderPixmap;
+ QTimer *m_autoOpenTimer;
+
+ KFileTreeViewToolTip m_toolTip;
+
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileTreeViewPrivate;
+ KFileTreeViewPrivate *d;
+};
+
+#endif
diff --git a/kio/kfile/kfiletreeviewitem.cpp b/kio/kfile/kfiletreeviewitem.cpp
new file mode 100644
index 000000000..96c100521
--- /dev/null
+++ b/kio/kfile/kfiletreeviewitem.cpp
@@ -0,0 +1,83 @@
+/* This file is part of the KDEproject
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <kfileitem.h>
+#include <kicontheme.h>
+
+#include "kfiletreeviewitem.h"
+
+/* --- KFileTreeViewItem --- */
+/*
+ */
+KFileTreeViewItem::KFileTreeViewItem( KFileTreeViewItem *parent,
+ KFileItem* item,
+ KFileTreeBranch *brnch )
+ : KListViewItem( parent ),
+ m_kfileitem( item ),
+ m_branch( brnch ),
+ m_wasListed(false)
+{
+ setPixmap(0, item->pixmap( KIcon::SizeSmall ));
+ setText( 0, item->text());
+
+}
+
+KFileTreeViewItem::KFileTreeViewItem( KFileTreeView* parent,
+ KFileItem* item,
+ KFileTreeBranch *brnch )
+ :KListViewItem( (QListView*)parent ),
+ m_kfileitem(item ),
+ m_branch( brnch ),
+ m_wasListed(false)
+{
+ setPixmap(0, item->pixmap( KIcon::SizeSmall ));
+ setText( 0, item->text());
+}
+
+KFileTreeViewItem::~KFileTreeViewItem()
+{
+ if ( m_kfileitem )
+ m_kfileitem->removeExtraData( m_branch );
+}
+
+bool KFileTreeViewItem::alreadyListed() const
+{
+ return m_wasListed;
+}
+
+void KFileTreeViewItem::setListed( bool wasListed )
+{
+ m_wasListed = wasListed;
+}
+
+KURL KFileTreeViewItem::url() const
+{
+ return m_kfileitem ? m_kfileitem->url() : KURL();
+}
+
+QString KFileTreeViewItem::path() const
+{
+ return m_kfileitem ? m_kfileitem->url().path() : QString::null;
+}
+
+bool KFileTreeViewItem::isDir() const
+{
+ return m_kfileitem ? m_kfileitem->isDir() : false;
+}
diff --git a/kio/kfile/kfiletreeviewitem.h b/kio/kfile/kfiletreeviewitem.h
new file mode 100644
index 000000000..69e4a2d90
--- /dev/null
+++ b/kio/kfile/kfiletreeviewitem.h
@@ -0,0 +1,106 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef kfile_tree_view_item_h
+#define kfile_tree_view_item_h
+
+#include <qptrlist.h>
+#include <klistview.h>
+
+#include <kfileitem.h>
+#include <kio/global.h>
+#include <kdirlister.h>
+#include <kio/job.h>
+
+class KURL;
+class KFileTreeView;
+class KFileTreeBranch;
+class KFileTreeItem;
+
+
+/**
+ * An item for a KFileTreeView that knows about its own KFileItem.
+ */
+class KIO_EXPORT KFileTreeViewItem : public KListViewItem
+{
+public:
+ KFileTreeViewItem( KFileTreeViewItem*, KFileItem*, KFileTreeBranch * );
+ KFileTreeViewItem( KFileTreeView*, KFileItem*, KFileTreeBranch * );
+ ~KFileTreeViewItem();
+
+ /**
+ * @return the KFileTreeBranch the item is sorted in.
+ */
+ KFileTreeBranch* branch() const { return m_branch; }
+
+ /**
+ * @return the KFileItem the viewitem is representing.
+ */
+ KFileItem *fileItem() const { return m_kfileitem; }
+
+ /**
+ * @return the path of the item.
+ */
+ QString path() const;
+
+ /**
+ * @return the items KURL
+ */
+ KURL url() const;
+
+ /**
+ * @return if the item represents a directory
+ */
+ bool isDir() const;
+
+ /**
+ * @return if this directory was already seen by a KDirLister.
+ */
+ bool alreadyListed() const;
+
+ /**
+ * set the flag if the directory was already listed.
+ */
+ void setListed( bool wasListed );
+
+protected:
+
+private:
+
+ KFileItem *m_kfileitem;
+ KFileTreeBranch *m_branch;
+ bool m_wasListed;
+ class KFileTreeViewItemPrivate;
+ KFileTreeViewItemPrivate *d;
+};
+
+
+/**
+ * List of KFileTreeViewItems
+ */
+typedef QPtrList<KFileTreeViewItem> KFileTreeViewItemList;
+
+/**
+ * Iterator for KFileTreeViewItemList
+ */
+typedef QPtrListIterator<KFileTreeViewItem> KFileTreeViewItemListIterator;
+
+
+#endif
+
diff --git a/kio/kfile/kfileview.cpp b/kio/kfile/kfileview.cpp
new file mode 100644
index 000000000..976d3b815
--- /dev/null
+++ b/kio/kfile/kfileview.cpp
@@ -0,0 +1,429 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "config-kfile.h"
+#include "kfileview.h"
+
+#ifdef Unsorted // the "I hate X.h" modus
+#undef Unsorted
+#endif
+
+QDir::SortSpec KFileView::defaultSortSpec = static_cast<QDir::SortSpec>(QDir::Name | QDir::IgnoreCase | QDir::DirsFirst);
+
+class KFileView::KFileViewPrivate
+{
+public:
+ KFileViewPrivate()
+ {
+ actions = 0;
+ dropOptions = 0;
+ }
+
+ ~KFileViewPrivate()
+ {
+ if( actions ) {
+ actions->clear(); // so that the removed() signal is emitted!
+ delete actions;
+ }
+ }
+
+ QGuardedPtr<KActionCollection> actions;
+ int dropOptions;
+};
+
+
+KFileView::KFileView()
+{
+ d = new KFileViewPrivate();
+ m_sorting = KFileView::defaultSortSpec;
+
+ sig = new KFileViewSignaler();
+ sig->setName("view-signaller");
+
+ m_selectedList = 0L;
+ filesNumber = 0;
+ dirsNumber = 0;
+
+ view_mode = All;
+ selection_mode = KFile::Single;
+ m_viewName = i18n("Unknown View");
+
+ myOnlyDoubleClickSelectsFiles = false;
+ m_itemList.setAutoDelete( false ); // just references
+}
+
+KFileView::~KFileView()
+{
+ delete d;
+ delete sig;
+ delete m_selectedList;
+}
+
+void KFileView::setParentView(KFileView *parent)
+{
+ if ( parent ) { // pass all signals right to our parent
+ QObject::connect(sig, SIGNAL( activatedMenu(const KFileItem *,
+ const QPoint& ) ),
+ parent->sig, SIGNAL( activatedMenu(const KFileItem *,
+ const QPoint& )));
+ QObject::connect(sig, SIGNAL( dirActivated(const KFileItem *)),
+ parent->sig, SIGNAL( dirActivated(const KFileItem*)));
+ QObject::connect(sig, SIGNAL( fileSelected(const KFileItem *)),
+ parent->sig, SIGNAL( fileSelected(const KFileItem*)));
+ QObject::connect(sig, SIGNAL( fileHighlighted(const KFileItem *) ),
+ parent->sig,SIGNAL(fileHighlighted(const KFileItem*)));
+ QObject::connect(sig, SIGNAL( sortingChanged( QDir::SortSpec ) ),
+ parent->sig, SIGNAL(sortingChanged( QDir::SortSpec)));
+ QObject::connect(sig, SIGNAL( dropped(const KFileItem *, QDropEvent*, const KURL::List&) ),
+ parent->sig, SIGNAL(dropped(const KFileItem *, QDropEvent*, const KURL::List&)));
+ }
+}
+
+bool KFileView::updateNumbers(const KFileItem *i)
+{
+ if (!( viewMode() & Files ) && i->isFile())
+ return false;
+
+ if (!( viewMode() & Directories ) && i->isDir())
+ return false;
+
+ if (i->isDir())
+ dirsNumber++;
+ else
+ filesNumber++;
+
+ return true;
+}
+
+void qt_qstring_stats();
+
+// filter out files if we're in directory mode and count files/directories
+// and insert into the view
+void KFileView::addItemList(const KFileItemList& list)
+{
+ KFileItem *tmp;
+
+ for (KFileItemListIterator it(list); (tmp = it.current()); ++it)
+ {
+ if (!updateNumbers(tmp))
+ continue;
+
+ insertItem( tmp );
+ }
+
+#ifdef Q2HELPER
+ qt_qstring_stats();
+#endif
+}
+
+void KFileView::insertItem( KFileItem * )
+{
+}
+
+void KFileView::setSorting(QDir::SortSpec new_sort)
+{
+ m_sorting = new_sort;
+}
+
+void KFileView::clear()
+{
+ m_itemList.clear();
+ filesNumber = 0;
+ dirsNumber = 0;
+ clearView();
+}
+
+void KFileView::sortReversed()
+{
+ int spec = sorting();
+
+ setSorting( static_cast<QDir::SortSpec>( spec ^ QDir::Reversed ) );
+}
+
+#if 0
+int KFileView::compareItems(const KFileItem *fi1, const KFileItem *fi2) const
+{
+ static const QString &dirup = KGlobal::staticQString("..");
+ bool bigger = true;
+ bool keepFirst = false;
+ bool dirsFirst = ((m_sorting & QDir::DirsFirst) == QDir::DirsFirst);
+
+ if (fi1 == fi2)
+ return 0;
+
+ // .. is always bigger, independent of the sort criteria
+ if ( fi1->name() == dirup ) {
+ bigger = false;
+ keepFirst = dirsFirst;
+ }
+ else if ( fi2->name() == dirup ) {
+ bigger = true;
+ keepFirst = dirsFirst;
+ }
+
+ else {
+ if ( fi1->isDir() != fi2->isDir() && dirsFirst ) {
+ bigger = fi2->isDir();
+ keepFirst = true;
+ }
+ else {
+
+ QDir::SortSpec sort = static_cast<QDir::SortSpec>(m_sorting & QDir::SortByMask);
+
+ //if (fi1->isDir() || fi2->isDir())
+ // sort = static_cast<QDir::SortSpec>(KFileView::defaultSortSpec & QDir::SortByMask);
+
+ switch (sort) {
+ case QDir::Name:
+ default:
+sort_by_name:
+ if ( (m_sorting & QDir::IgnoreCase) == QDir::IgnoreCase )
+ bigger = (fi1->name( true ) > fi2->name( true ));
+ else
+ bigger = (fi1->name() > fi2->name());
+ break;
+ case QDir::Time:
+ {
+ time_t t1 = fi1->time( KIO::UDS_MODIFICATION_TIME );
+ time_t t2 = fi2->time( KIO::UDS_MODIFICATION_TIME );
+ if ( t1 != t2 ) {
+ bigger = (t1 > t2);
+ break;
+ }
+
+ // Sort by name if both items have the same timestamp.
+ // Don't honor the reverse flag tho.
+ else {
+ keepFirst = true;
+ goto sort_by_name;
+ }
+ }
+ case QDir::Size:
+ {
+ KIO::filesize_t s1 = fi1->size();
+ KIO::filesize_t s2 = fi2->size();
+ if ( s1 != s2 ) {
+ bigger = (s1 > s2);
+ break;
+ }
+
+ // Sort by name if both items have the same size.
+ // Don't honor the reverse flag tho.
+ else {
+ keepFirst = true;
+ goto sort_by_name;
+ }
+ }
+ case QDir::Unsorted:
+ bigger = true; // nothing
+ break;
+ }
+ }
+ }
+
+ if (reversed && !keepFirst ) // don't reverse dirs to the end!
+ bigger = !bigger;
+
+ return (bigger ? 1 : -1);
+}
+#endif
+
+void KFileView::updateView(bool f)
+{
+ widget()->repaint(f);
+}
+
+void KFileView::updateView(const KFileItem *)
+{
+}
+
+void KFileView::setCurrentItem(const QString &filename )
+{
+ if (!filename.isNull()) {
+ KFileItem *item;
+ for ( (item = firstFileItem()); item; item = nextItem( item ) ) {
+ if (item->name() == filename) {
+ setCurrentItem( item );
+ return;
+ }
+ }
+ }
+
+ kdDebug(kfile_area) << "setCurrentItem: no match found: " << filename << endl;
+}
+
+const KFileItemList * KFileView::items() const
+{
+ KFileItem *item = 0L;
+
+ // only ever use m_itemList in this method!
+ m_itemList.clear();
+ for ( (item = firstFileItem()); item; item = nextItem( item ) )
+ m_itemList.append( item );
+
+ return &m_itemList;
+}
+
+
+const KFileItemList * KFileView::selectedItems() const
+{
+ if ( !m_selectedList )
+ m_selectedList = new KFileItemList;
+
+ m_selectedList->clear();
+
+ KFileItem *item;
+ for ( (item = firstFileItem()); item; item = nextItem( item ) ) {
+ if ( isSelected( item ) )
+ m_selectedList->append( item );
+ }
+
+ return m_selectedList;
+}
+
+void KFileView::selectAll()
+{
+ if (selection_mode == KFile::NoSelection || selection_mode== KFile::Single)
+ return;
+
+ KFileItem *item = 0L;
+ for ( (item = firstFileItem()); item; item = nextItem( item ) )
+ setSelected( item, true );
+}
+
+
+void KFileView::invertSelection()
+{
+ KFileItem *item = 0L;
+ for ( (item = firstFileItem()); item; item = nextItem( item ) )
+ setSelected( item, !isSelected( item ) );
+}
+
+
+void KFileView::setSelectionMode( KFile::SelectionMode sm )
+{
+ selection_mode = sm;
+}
+
+KFile::SelectionMode KFileView::selectionMode() const
+{
+ return selection_mode;
+}
+
+void KFileView::setViewMode( ViewMode vm )
+{
+ view_mode = vm;
+}
+
+void KFileView::removeItem( const KFileItem *item )
+{
+ if ( !item )
+ return;
+
+ if ( item->isDir() )
+ dirsNumber--;
+ else
+ filesNumber--;
+
+ if ( m_selectedList )
+ m_selectedList->removeRef( item );
+}
+
+void KFileView::listingCompleted()
+{
+ // empty default impl.
+}
+
+KActionCollection * KFileView::actionCollection() const
+{
+ if ( !d->actions )
+ d->actions = new KActionCollection( widget(), "KFileView::d->actions" );
+ return d->actions;
+}
+
+void KFileView::readConfig( KConfig *, const QString& )
+{
+}
+
+void KFileView::writeConfig( KConfig *, const QString& )
+{
+}
+
+QString KFileView::sortingKey( const QString& value, bool isDir, int sortSpec )
+{
+ bool reverse = sortSpec & QDir::Reversed;
+ bool dirsFirst = sortSpec & QDir::DirsFirst;
+ char start = (isDir && dirsFirst) ? (reverse ? '2' : '0') : '1';
+ QString result = (sortSpec & QDir::IgnoreCase) ? value.lower() : value;
+ return result.prepend( start );
+}
+
+QString KFileView::sortingKey( KIO::filesize_t value, bool isDir, int sortSpec)
+{
+ bool reverse = sortSpec & QDir::Reversed;
+ bool dirsFirst = sortSpec & QDir::DirsFirst;
+ char start = (isDir && dirsFirst) ? (reverse ? '2' : '0') : '1';
+ return KIO::number( value ).rightJustify( 24, '0' ).prepend( start );
+}
+
+void KFileView::setDropOptions(int options)
+{
+ virtual_hook(VIRTUAL_SET_DROP_OPTIONS, &options); // Virtual call
+}
+
+void KFileView::setDropOptions_impl(int options)
+{
+ d->dropOptions = options;
+}
+
+int KFileView::dropOptions()
+{
+ return d->dropOptions;
+}
+
+int KFileView::autoOpenDelay()
+{
+ return (QApplication::startDragTime() * 3) / 2;
+}
+
+void KFileView::virtual_hook( int id, void* data)
+{
+ switch(id) {
+ case VIRTUAL_SET_DROP_OPTIONS:
+ setDropOptions_impl(*(int *)data);
+ break;
+ default:
+ /*BASE::virtual_hook( id, data );*/
+ break;
+ }
+}
+
+#include "kfileview.moc"
diff --git a/kio/kfile/kfileview.h b/kio/kfile/kfileview.h
new file mode 100644
index 000000000..0b2002e3b
--- /dev/null
+++ b/kio/kfile/kfileview.h
@@ -0,0 +1,444 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFILEVIEW_H
+#define KFILEVIEW_H
+
+class QPoint;
+class KActionCollection;
+
+#include <qwidget.h>
+
+#include "kfileitem.h"
+#include "kfile.h"
+
+/**
+ * internal class to make easier to use signals possible
+ * @internal
+ **/
+class KIO_EXPORT KFileViewSignaler : public QObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Call this method when an item is selected (depends on single click /
+ * double click configuration). Emits the appropriate signal.
+ **/
+ void activate( const KFileItem *item ) {
+ if ( item->isDir() )
+ emit dirActivated( item );
+ else
+ emit fileSelected( item );
+ }
+ /**
+ * emits the highlighted signal for item. Call this in your view class
+ * whenever the selection changes.
+ */
+ void highlightFile(const KFileItem *i) { emit fileHighlighted(i); }
+
+ void activateMenu( const KFileItem *i, const QPoint& pos ) {
+ emit activatedMenu( i, pos );
+ }
+
+ void changeSorting( QDir::SortSpec sorting ) {
+ emit sortingChanged( sorting );
+ }
+
+ void dropURLs(const KFileItem *i, QDropEvent*e, const KURL::List&urls) {
+ emit dropped(i, e, urls);
+ }
+
+signals:
+ void dirActivated(const KFileItem*);
+
+ void sortingChanged( QDir::SortSpec );
+
+ /**
+ * the item maybe be 0L, indicating that we're in multiselection mode and
+ * the selection has changed.
+ */
+ void fileHighlighted(const KFileItem*);
+ void fileSelected(const KFileItem*);
+ void activatedMenu( const KFileItem *i, const QPoint& );
+ void dropped(const KFileItem *, QDropEvent*, const KURL::List&);
+};
+
+/**
+ * This class defines an interface to all file views. Its intent is
+ * to allow to switch the view of the files in the selector very easily.
+ * It defines some pure virtual functions, that must be implemented to
+ * make a file view working.
+ *
+ * Since this class is not a widget, but it's meant to be added to other
+ * widgets, its most important function is widget. This should return
+ * a pointer to the implemented widget.
+ *
+ * @short A base class for views of the KDE file selector
+ * @author Stephan Kulow <coolo@kde.org>
+ **/
+class KIO_EXPORT KFileView {
+
+public:
+ KFileView();
+
+ /**
+ * Destructor
+ */
+ virtual ~KFileView();
+
+ /**
+ * inserts a list of items.
+ **/
+ void addItemList(const KFileItemList &list);
+
+ /**
+ * a pure virtual function to get a QWidget, that can be added to
+ * other widgets. This function is needed to make it possible for
+ * derived classes to derive from other widgets.
+ **/
+ virtual QWidget *widget() = 0;
+
+ /**
+ * ### As const-method, to be fixed in 3.0
+ */
+ QWidget *widget() const { return const_cast<KFileView*>(this)->widget(); }
+
+ /**
+ * Sets @p filename the current item in the view, if available.
+ */
+ void setCurrentItem( const QString &filename );
+
+ /**
+ * Reimplement this to set @p item the current item in the view, e.g.
+ * the item having focus.
+ */
+ virtual void setCurrentItem( const KFileItem *item ) = 0;
+
+ /**
+ * @returns the "current" KFileItem, e.g. where the cursor is.
+ * Returns 0L when there is no current item (e.g. in an empty view).
+ * Subclasses have to implement this.
+ */
+ virtual KFileItem *currentFileItem() const = 0;
+
+ /**
+ * Clears the view and all item lists.
+ */
+ virtual void clear();
+
+ /**
+ * does a repaint of the view.
+ *
+ * The default implementation calls
+ * \code
+ * widget()->repaint(f)
+ * \endcode
+ **/
+ virtual void updateView(bool f = true);
+
+ virtual void updateView(const KFileItem*);
+
+ /**
+ * Removes an item from the list; has to be implemented by the view.
+ * Call KFileView::removeItem( item ) after removing it.
+ */
+ virtual void removeItem(const KFileItem *item);
+
+ /**
+ * This hook is called when all items of the currently listed directory
+ * are listed and inserted into the view, i.e. there won't come any new
+ * items anymore.
+ */
+ virtual void listingCompleted();
+
+ /**
+ * Returns the sorting order of the internal list. Newly added files
+ * are added through this sorting.
+ */
+ QDir::SortSpec sorting() const { return m_sorting; }
+
+ /**
+ * Sets the sorting order of the view.
+ *
+ * Default is QDir::Name | QDir::IgnoreCase | QDir::DirsFirst
+ * Override this in your subclass and sort accordingly (usually by
+ * setting the sorting-key for every item and telling QIconView
+ * or QListView to sort.
+ *
+ * A view may choose to use a different sorting than QDir::Name, Time
+ * or Size. E.g. to sort by mimetype or any possible string. Set the
+ * sorting to QDir::Unsorted for that and do the rest internally.
+ *
+ * @see sortingKey
+ */
+ virtual void setSorting(QDir::SortSpec sort);
+
+ /**
+ * Tells whether the current items are in reversed order (shortcut to
+ * sorting() & QDir::Reversed).
+ */
+ bool isReversed() const { return (m_sorting & QDir::Reversed); }
+
+ void sortReversed();
+
+ /**
+ * @returns the number of dirs and files
+ **/
+ uint count() const { return filesNumber + dirsNumber; }
+
+ /**
+ * @returns the number of files.
+ **/
+ uint numFiles() const { return filesNumber; }
+
+ /**
+ * @returns the number of directories
+ **/
+ uint numDirs() const { return dirsNumber; }
+
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+ virtual KFile::SelectionMode selectionMode() const;
+
+ enum ViewMode {
+ Files = 1,
+ Directories = 2,
+ All = Files | Directories
+ };
+ virtual void setViewMode( ViewMode vm );
+ virtual ViewMode viewMode() const { return view_mode; }
+
+ /**
+ * @returns the localized name of the view, which could be displayed
+ * somewhere, e.g. in a menu, where the user can choose between views.
+ * @see setViewName
+ */
+ QString viewName() const { return m_viewName; }
+
+ /**
+ * Sets the name of the view, which could be displayed somewhere.
+ * E.g. "Image Preview".
+ */
+ void setViewName( const QString& name ) { m_viewName = name; }
+
+ virtual void setParentView(KFileView *parent);
+
+ /**
+ * The derived view must implement this function to add
+ * the file in the widget.
+ *
+ * Make sure to call this implementation, i.e.
+ * KFileView::insertItem( i );
+ *
+ */
+ virtual void insertItem( KFileItem *i);
+
+ /**
+ * pure virtual function, that should be implemented to clear
+ * the view. At this moment the list is already empty
+ **/
+ virtual void clearView() = 0;
+
+ /**
+ * pure virtual function, that should be implemented to make item i
+ * visible, i.e. by scrolling the view appropriately.
+ */
+ virtual void ensureItemVisible( const KFileItem *i ) = 0;
+
+ /**
+ * Clears any selection, unhighlights everything. Must be implemented by
+ * the view.
+ */
+ virtual void clearSelection() = 0;
+
+ /**
+ * Selects all items. You may want to override this, if you can implement
+ * it more efficiently than calling setSelected() with every item.
+ * This works only in Multiselection mode of course.
+ */
+ virtual void selectAll();
+
+ /**
+ * Inverts the current selection, i.e. selects all items, that were up to
+ * now not selected and deselects the other.
+ */
+ virtual void invertSelection();
+
+ /**
+ * Tells the view that it should highlight the item.
+ * This function must be implemented by the view.
+ **/
+ virtual void setSelected(const KFileItem *, bool enable) = 0;
+
+ /**
+ * @returns whether the given item is currently selected.
+ * Must be implemented by the view.
+ */
+ virtual bool isSelected( const KFileItem * ) const = 0;
+
+ /**
+ * @returns all currently highlighted items.
+ */
+ const KFileItemList * selectedItems() const;
+
+ /**
+ * @returns all items currently available in the current sort-order
+ */
+ const KFileItemList * items() const;
+
+ virtual KFileItem * firstFileItem() const = 0;
+ virtual KFileItem * nextItem( const KFileItem * ) const = 0;
+ virtual KFileItem * prevItem( const KFileItem * ) const = 0;
+
+ /**
+ * This is a KFileDialog specific hack: we want to select directories with
+ * single click, but not files. But as a generic class, we have to be able
+ * to select files on single click as well.
+ *
+ * This gives us the opportunity to do both.
+ *
+ * Every view has to decide when to call select( item ) when a file was
+ * single-clicked, based on onlyDoubleClickSelectsFiles().
+ */
+ void setOnlyDoubleClickSelectsFiles( bool enable ) {
+ myOnlyDoubleClickSelectsFiles = enable;
+ }
+
+ /**
+ * @returns whether files (not directories) should only be select()ed by
+ * double-clicks.
+ * @see setOnlyDoubleClickSelectsFiles
+ */
+ bool onlyDoubleClickSelectsFiles() const {
+ return myOnlyDoubleClickSelectsFiles;
+ }
+
+ /**
+ * increases the number of dirs and files.
+ * @returns true if the item fits the view mode
+ */
+ bool updateNumbers(const KFileItem *i);
+
+ /**
+ * @returns the view-specific action-collection. Every view should
+ * add its actions here (if it has any) to make them available to
+ * e.g. the KDirOperator's popup-menu.
+ */
+ virtual KActionCollection * actionCollection() const;
+
+ KFileViewSignaler * signaler() const { return sig; }
+
+ virtual void readConfig( KConfig *, const QString& group = QString::null );
+ virtual void writeConfig( KConfig *, const QString& group = QString::null);
+
+ /**
+ * Various options for drag and drop support.
+ * These values can be or'd together.
+ * @li @p AutoOpenDirs Automatically open directory after hovering above it
+ * for a short while while dragging.
+ * @since 3.2
+ */
+ enum DropOptions {
+ AutoOpenDirs = 1
+ };
+ /**
+ * Specify DND options. See DropOptions for details.
+ * All options are disabled by default.
+ * @since 3.2
+ */
+ // KDE 4: Make virtual
+ void setDropOptions(int options);
+
+ /**
+ * Returns the DND options in effect.
+ * See DropOptions for details.
+ * @since 3.2
+ */
+ int dropOptions();
+
+ /**
+ * This method calculates a QString from the given parameters, that is
+ * suitable for sorting with e.g. QIconView or QListView. Their
+ * Item-classes usually have a setKey( const QString& ) method or a virtual
+ * method QString key() that is used for sorting.
+ *
+ * @param value Any string that should be used as sort criterion
+ * @param isDir Tells whether the key is computed for an item representing
+ * a directory (directories are usually sorted before files)
+ * @param sortSpec An ORed combination of QDir::SortSpec flags.
+ * Currently, the values IgnoreCase, Reversed and
+ * DirsFirst are taken into account.
+ */
+ static QString sortingKey( const QString& value, bool isDir, int sortSpec);
+
+ /**
+ * An overloaded method that takes not a QString, but a number as sort
+ * criterion. You can use this for file-sizes or dates/times for example.
+ * If you use a time_t, you need to cast that to KIO::filesize_t because
+ * of ambiguity problems.
+ */
+ static QString sortingKey( KIO::filesize_t value, bool isDir,int sortSpec);
+
+ /**
+ * @internal
+ * delay before auto opening a directory
+ */
+ static int autoOpenDelay();
+
+protected:
+ /**
+ * @internal
+ * class to distribute the signals
+ **/
+ KFileViewSignaler *sig;
+
+private:
+ static QDir::SortSpec defaultSortSpec;
+ QDir::SortSpec m_sorting;
+ QString m_viewName;
+
+ /**
+ * counters
+ **/
+ uint filesNumber;
+ uint dirsNumber;
+
+ ViewMode view_mode;
+ KFile::SelectionMode selection_mode;
+
+ // never use! It's only guaranteed to contain valid items in the items()
+ // method!
+ mutable KFileItemList m_itemList;
+
+ mutable KFileItemList *m_selectedList;
+ bool myOnlyDoubleClickSelectsFiles;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+ /* @internal for virtual_hook */
+ enum { VIRTUAL_SET_DROP_OPTIONS = 1 };
+ void setDropOptions_impl(int options);
+private:
+ class KFileViewPrivate;
+ KFileViewPrivate *d;
+};
+
+#endif // KFILEINFOLISTWIDGET_H
diff --git a/kio/kfile/kicondialog.cpp b/kio/kfile/kicondialog.cpp
new file mode 100644
index 000000000..21a6ff6cd
--- /dev/null
+++ b/kio/kfile/kicondialog.cpp
@@ -0,0 +1,772 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kfile.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * (C) 2000 Kurt Granroth <granroth@kde.org>
+ * (C) 1997 Christoph Neerfeld <chris@kde.org>
+ * (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ */
+
+#include "kicondialog.h"
+
+#include <config.h>
+
+#include <assert.h>
+
+#include <kiconviewsearchline.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+#include <kprogress.h>
+#include <kiconview.h>
+#include <kfiledialog.h>
+#include <kimagefilepreview.h>
+
+#include <qlayout.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qsortedlist.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qtimer.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qfileinfo.h>
+#include <qtoolbutton.h>
+#include <qwhatsthis.h>
+
+#ifdef HAVE_LIBART
+#include <svgicons/ksvgiconengine.h>
+#include <svgicons/ksvgiconpainter.h>
+#endif
+
+class KIconCanvas::KIconCanvasPrivate
+{
+ public:
+ KIconCanvasPrivate() { m_bLoading = false; }
+ ~KIconCanvasPrivate() {}
+ bool m_bLoading;
+};
+
+/**
+ * Helper class for sorting icon paths by icon name
+ */
+class IconPath : public QString
+{
+protected:
+ QString m_iconName;
+
+public:
+ IconPath(const QString &ip) : QString (ip)
+ {
+ int n = findRev('/');
+ m_iconName = (n==-1) ? static_cast<QString>(*this) : mid(n+1);
+ }
+
+
+ IconPath() : QString ()
+ { }
+
+ bool operator== (const IconPath &ip) const
+ { return m_iconName == ip.m_iconName; }
+
+ bool operator< (const IconPath &ip) const
+ { return m_iconName < ip.m_iconName; }
+
+};
+
+/*
+ * KIconCanvas: Iconview for the iconloader dialog.
+ */
+
+KIconCanvas::KIconCanvas(QWidget *parent, const char *name)
+ : KIconView(parent, name)
+{
+ d = new KIconCanvasPrivate;
+ mpTimer = new QTimer(this);
+ connect(mpTimer, SIGNAL(timeout()), SLOT(slotLoadFiles()));
+ connect(this, SIGNAL(currentChanged(QIconViewItem *)),
+ SLOT(slotCurrentChanged(QIconViewItem *)));
+ setGridX(80);
+ setWordWrapIconText(false);
+ setShowToolTips(true);
+}
+
+KIconCanvas::~KIconCanvas()
+{
+ delete mpTimer;
+ delete d;
+}
+
+void KIconCanvas::loadFiles(const QStringList& files)
+{
+ clear();
+ mFiles = files;
+ emit startLoading(mFiles.count());
+ mpTimer->start(10, true); // #86680
+ d->m_bLoading = false;
+}
+
+void KIconCanvas::slotLoadFiles()
+{
+ setResizeMode(Fixed);
+ QApplication::setOverrideCursor(waitCursor);
+
+ // disable updates to not trigger paint events when adding child items
+ setUpdatesEnabled( false );
+
+#ifdef HAVE_LIBART
+ KSVGIconEngine *svgEngine = new KSVGIconEngine();
+#endif
+
+ d->m_bLoading = true;
+ int i;
+ QStringList::ConstIterator it;
+ uint emitProgress = 10; // so we will emit it once in the beginning
+ QStringList::ConstIterator end(mFiles.end());
+ for (it=mFiles.begin(), i=0; it!=end; ++it, i++)
+ {
+ // Calling kapp->processEvents() makes the iconview flicker like hell
+ // (it's being repainted once for every new item), so we don't do this.
+ // Instead, we directly repaint the progress bar without going through
+ // the event-loop. We do that just once for every 10th item so that
+ // the progress bar doesn't flicker in turn. (pfeiffer)
+ if ( emitProgress >= 10 ) {
+ emit progress(i);
+ emitProgress = 0;
+ }
+
+ emitProgress++;
+// kapp->processEvents();
+ if ( !d->m_bLoading ) // user clicked on a button that will load another set of icons
+ break;
+ QImage img;
+
+ // Use the extension as the format. Works for XPM and PNG, but not for SVG
+ QString path= *it;
+ QString ext = path.right(3).upper();
+
+ if (ext != "SVG" && ext != "VGZ")
+ img.load(*it);
+#ifdef HAVE_LIBART
+ else
+ if (svgEngine->load(60, 60, *it))
+ img = *svgEngine->painter()->image();
+#endif
+
+ if (img.isNull())
+ continue;
+ if (img.width() > 60 || img.height() > 60)
+ {
+ if (img.width() > img.height())
+ {
+ int height = (int) ((60.0 / img.width()) * img.height());
+ img = img.smoothScale(60, height);
+ } else
+ {
+ int width = (int) ((60.0 / img.height()) * img.width());
+ img = img.smoothScale(width, 60);
+ }
+ }
+ QPixmap pm;
+ pm.convertFromImage(img);
+ QFileInfo fi(*it);
+ QIconViewItem *item = new QIconViewItem(this, fi.baseName(), pm);
+ item->setKey(*it);
+ item->setDragEnabled(false);
+ item->setDropEnabled(false);
+ }
+
+#ifdef HAVE_LIBART
+ delete svgEngine;
+#endif
+
+ // enable updates since we have to draw the whole view now
+ setUpdatesEnabled( true );
+
+ QApplication::restoreOverrideCursor();
+ d->m_bLoading = false;
+ emit finished();
+ setResizeMode(Adjust);
+}
+
+QString KIconCanvas::getCurrent() const
+{
+ if (!currentItem())
+ return QString::null;
+ return currentItem()->key();
+}
+
+void KIconCanvas::stopLoading()
+{
+ d->m_bLoading = false;
+}
+
+void KIconCanvas::slotCurrentChanged(QIconViewItem *item)
+{
+ emit nameChanged((item != 0L) ? item->text() : QString::null);
+}
+
+class KIconDialog::KIconDialogPrivate
+{
+ public:
+ KIconDialogPrivate() {
+ m_bStrictIconSize = true;
+ m_bLockUser = false;
+ m_bLockCustomDir = false;
+ searchLine = 0;
+ }
+ ~KIconDialogPrivate() {}
+ bool m_bStrictIconSize, m_bLockUser, m_bLockCustomDir;
+ QString custom;
+ QString customLocation;
+ KIconViewSearchLine *searchLine;
+};
+
+/*
+ * KIconDialog: Dialog for selecting icons. Both system and user
+ * specified icons can be chosen.
+ */
+
+KIconDialog::KIconDialog(QWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, i18n("Select Icon"), Ok|Cancel, Ok)
+{
+ d = new KIconDialogPrivate;
+ mpLoader = KGlobal::iconLoader();
+ init();
+}
+
+KIconDialog::KIconDialog(KIconLoader *loader, QWidget *parent,
+ const char *name)
+ : KDialogBase(parent, name, true, i18n("Select Icon"), Ok|Cancel, Ok)
+{
+ d = new KIconDialogPrivate;
+ mpLoader = loader;
+ init();
+}
+
+void KIconDialog::init()
+{
+ mGroupOrSize = KIcon::Desktop;
+ mContext = KIcon::Any;
+ mType = 0;
+ mFileList = KGlobal::dirs()->findAllResources("appicon", QString::fromLatin1("*.png"));
+
+ QWidget *main = new QWidget( this );
+ setMainWidget(main);
+
+ QVBoxLayout *top = new QVBoxLayout(main);
+ top->setSpacing( spacingHint() );
+
+ QButtonGroup *bgroup = new QButtonGroup(0, Qt::Vertical, i18n("Icon Source"), main);
+ bgroup->layout()->setSpacing(KDialog::spacingHint());
+ bgroup->layout()->setMargin(KDialog::marginHint());
+ top->addWidget(bgroup);
+ connect(bgroup, SIGNAL(clicked(int)), SLOT(slotButtonClicked(int)));
+ QGridLayout *grid = new QGridLayout(bgroup->layout(), 3, 2);
+ mpRb1 = new QRadioButton(i18n("S&ystem icons:"), bgroup);
+ grid->addWidget(mpRb1, 1, 0);
+ mpCombo = new QComboBox(bgroup);
+ connect(mpCombo, SIGNAL(activated(int)), SLOT(slotContext(int)));
+ grid->addWidget(mpCombo, 1, 1);
+ mpRb2 = new QRadioButton(i18n("O&ther icons:"), bgroup);
+ grid->addWidget(mpRb2, 2, 0);
+ mpBrowseBut = new QPushButton(i18n("&Browse..."), bgroup);
+ grid->addWidget(mpBrowseBut, 2, 1);
+
+ //
+ // ADD SEARCHLINE
+ //
+ QHBoxLayout *searchLayout = new QHBoxLayout(0, 0, KDialog::spacingHint());
+ top->addLayout(searchLayout);
+
+ QToolButton *clearSearch = new QToolButton(main);
+ clearSearch->setTextLabel(i18n("Clear Search"), true);
+ clearSearch->setIconSet(SmallIconSet(QApplication::reverseLayout() ? "clear_left" :"locationbar_erase"));
+ searchLayout->addWidget(clearSearch);
+
+ QLabel *searchLabel = new QLabel(i18n("&Search:"), main);
+ searchLayout->addWidget(searchLabel);
+
+ d->searchLine = new KIconViewSearchLine(main, "searchLine");
+ searchLayout->addWidget(d->searchLine);
+ searchLabel->setBuddy(d->searchLine);
+
+
+ // signals and slots connections
+ connect(clearSearch, SIGNAL(clicked()), d->searchLine, SLOT(clear()));
+
+ QString wtstr = i18n("Search interactively for icon names (e.g. folder).");
+ QWhatsThis::add(searchLabel, wtstr);
+ QWhatsThis::add(d->searchLine, wtstr);
+
+
+ mpCanvas = new KIconCanvas(main);
+ connect(mpCanvas, SIGNAL(executed(QIconViewItem *)), SLOT(slotAcceptIcons()));
+ connect(mpCanvas, SIGNAL(returnPressed(QIconViewItem *)), SLOT(slotAcceptIcons()));
+ mpCanvas->setMinimumSize(400, 125);
+ top->addWidget(mpCanvas);
+ d->searchLine->setIconView(mpCanvas);
+
+ mpProgress = new KProgress(main);
+ top->addWidget(mpProgress);
+ connect(mpCanvas, SIGNAL(startLoading(int)), SLOT(slotStartLoading(int)));
+ connect(mpCanvas, SIGNAL(progress(int)), SLOT(slotProgress(int)));
+ connect(mpCanvas, SIGNAL(finished()), SLOT(slotFinished()));
+
+ // When pressing Ok or Cancel, stop loading icons
+ connect(this, SIGNAL(hidden()), mpCanvas, SLOT(stopLoading()));
+
+ static const char* const context_text[] = {
+ I18N_NOOP( "Actions" ),
+ I18N_NOOP( "Animations" ),
+ I18N_NOOP( "Applications" ),
+ I18N_NOOP( "Categories" ),
+ I18N_NOOP( "Devices" ),
+ I18N_NOOP( "Emblems" ),
+ I18N_NOOP( "Emotes" ),
+ I18N_NOOP( "Filesystems" ),
+ I18N_NOOP( "International" ),
+ I18N_NOOP( "Mimetypes" ),
+ I18N_NOOP( "Places" ),
+ I18N_NOOP( "Status" ) };
+ static const KIcon::Context context_id[] = {
+ KIcon::Action,
+ KIcon::Animation,
+ KIcon::Application,
+ KIcon::Category,
+ KIcon::Device,
+ KIcon::Emblem,
+ KIcon::Emote,
+ KIcon::FileSystem,
+ KIcon::International,
+ KIcon::MimeType,
+ KIcon::Place,
+ KIcon::StatusIcon };
+ mNumContext = 0;
+ int cnt = sizeof( context_text ) / sizeof( context_text[ 0 ] );
+ // check all 3 arrays have same sizes
+ assert( cnt == sizeof( context_id ) / sizeof( context_id[ 0 ] )
+ && cnt == sizeof( mContextMap ) / sizeof( mContextMap[ 0 ] ));
+ for( int i = 0;
+ i < cnt;
+ ++i )
+ {
+ if( mpLoader->hasContext( context_id[ i ] ))
+ {
+ mpCombo->insertItem(i18n( context_text[ i ] ));
+ mContextMap[ mNumContext++ ] = context_id[ i ];
+ }
+ }
+ mpCombo->setFixedSize(mpCombo->sizeHint());
+
+ mpBrowseBut->setFixedWidth(mpCombo->width());
+
+ // Make the dialog a little taller
+ incInitialSize(QSize(0,100));
+}
+
+
+KIconDialog::~KIconDialog()
+{
+ delete d;
+}
+
+void KIconDialog::slotAcceptIcons()
+{
+ d->custom=QString::null;
+ slotOk();
+}
+
+void KIconDialog::showIcons()
+{
+ mpCanvas->clear();
+ QStringList filelist;
+ if (mType == 0)
+ if (d->m_bStrictIconSize)
+ filelist=mpLoader->queryIcons(mGroupOrSize, mContext);
+ else
+ filelist=mpLoader->queryIconsByContext(mGroupOrSize, mContext);
+ else if ( !d->customLocation.isNull() )
+ filelist=mpLoader->queryIconsByDir( d->customLocation );
+ else
+ filelist=mFileList;
+
+ QSortedList <IconPath>iconlist;
+ iconlist.setAutoDelete(true);
+ QStringList::Iterator it;
+ for( it = filelist.begin(); it != filelist.end(); ++it )
+ iconlist.append(new IconPath(*it));
+
+ iconlist.sort();
+ filelist.clear();
+
+ for ( IconPath *ip=iconlist.first(); ip != 0; ip=iconlist.next() )
+ filelist.append(*ip);
+
+ d->searchLine->clear();
+ mpCanvas->loadFiles(filelist);
+}
+
+void KIconDialog::setStrictIconSize(bool b)
+{
+ d->m_bStrictIconSize=b;
+}
+
+bool KIconDialog::strictIconSize() const
+{
+ return d->m_bStrictIconSize;
+}
+
+void KIconDialog::setIconSize( int size )
+{
+ // see KIconLoader, if you think this is weird
+ if ( size == 0 )
+ mGroupOrSize = KIcon::Desktop; // default Group
+ else
+ mGroupOrSize = -size; // yes, KIconLoader::queryIconsByContext is weird
+}
+
+int KIconDialog::iconSize() const
+{
+ // 0 or any other value ==> mGroupOrSize is a group, so we return 0
+ return (mGroupOrSize < 0) ? -mGroupOrSize : 0;
+}
+
+#ifndef KDE_NO_COMPAT
+QString KIconDialog::selectIcon(KIcon::Group group, KIcon::Context context, bool user)
+{
+ setup( group, context, false, 0, user );
+ return openDialog();
+}
+#endif
+
+void KIconDialog::setup(KIcon::Group group, KIcon::Context context,
+ bool strictIconSize, int iconSize, bool user )
+{
+ d->m_bStrictIconSize = strictIconSize;
+ mGroupOrSize = (iconSize == 0) ? group : -iconSize;
+ mType = user ? 1 : 0;
+ mpRb1->setChecked(!user);
+ mpRb2->setChecked(user);
+ mpCombo->setEnabled(!user);
+ mpBrowseBut->setEnabled(user);
+ setContext( context );
+}
+
+void KIconDialog::setup(KIcon::Group group, KIcon::Context context,
+ bool strictIconSize, int iconSize, bool user,
+ bool lockUser, bool lockCustomDir )
+{
+ d->m_bStrictIconSize = strictIconSize;
+ d->m_bLockUser = lockUser;
+ d->m_bLockCustomDir = lockCustomDir;
+ mGroupOrSize = (iconSize == 0) ? group : -iconSize;
+ mType = user ? 1 : 0;
+ mpRb1->setChecked(!user);
+ mpRb1->setEnabled( !lockUser || !user );
+ mpRb2->setChecked(user);
+ mpRb2->setEnabled( !lockUser || user );
+ mpCombo->setEnabled(!user);
+ mpBrowseBut->setEnabled( user && !lockCustomDir );
+ setContext( context );
+}
+
+void KIconDialog::setContext( KIcon::Context context )
+{
+ mContext = context;
+ for( int i = 0;
+ i < mNumContext;
+ ++i )
+ if( mContextMap[ i ] == context )
+ {
+ mpCombo->setCurrentItem( i );
+ return;
+ }
+}
+
+void KIconDialog::setCustomLocation( const QString& location )
+{
+ d->customLocation = location;
+}
+
+QString KIconDialog::openDialog()
+{
+ showIcons();
+
+ if ( exec() == Accepted )
+ {
+ if (!d->custom.isNull())
+ return d->custom;
+ QString name = mpCanvas->getCurrent();
+ if (name.isEmpty() || (mType == 1))
+ return name;
+ QFileInfo fi(name);
+ return fi.baseName();
+ }
+ return QString::null;
+}
+
+void KIconDialog::showDialog()
+{
+ setModal(false);
+ showIcons();
+ show();
+}
+
+void KIconDialog::slotOk()
+{
+ QString name;
+ if (!d->custom.isNull())
+ {
+ name = d->custom;
+ }
+ else
+ {
+ name = mpCanvas->getCurrent();
+ if (!name.isEmpty() && (mType != 1))
+ {
+ QFileInfo fi(name);
+ name = fi.baseName();
+ }
+ }
+
+ emit newIconName(name);
+ KDialogBase::slotOk();
+}
+
+QString KIconDialog::getIcon(KIcon::Group group, KIcon::Context context,
+ bool strictIconSize, int iconSize, bool user,
+ QWidget *parent, const QString &caption)
+{
+ KIconDialog dlg(parent, "icon dialog");
+ dlg.setup( group, context, strictIconSize, iconSize, user );
+ if (!caption.isNull())
+ dlg.setCaption(caption);
+
+ return dlg.openDialog();
+}
+
+void KIconDialog::slotButtonClicked(int id)
+{
+ QString file;
+
+ switch (id)
+ {
+ case 0:
+ if(mType!=0)
+ {
+ mType = 0;
+ mpBrowseBut->setEnabled(false);
+ mpCombo->setEnabled(true);
+ showIcons();
+ }
+ break;
+
+ case 1:
+ if(mType!=1)
+ {
+ mType = 1;
+ mpBrowseBut->setEnabled( !d->m_bLockCustomDir );
+ mpCombo->setEnabled(false);
+ showIcons();
+ }
+ break;
+ case 2:
+ {
+ // Create a file dialog to select a PNG, XPM or SVG file,
+ // with the image previewer shown.
+ // KFileDialog::getImageOpenURL doesn't allow svg.
+ KFileDialog dlg(QString::null, i18n("*.png *.xpm *.svg *.svgz|Icon Files (*.png *.xpm *.svg *.svgz)"),
+ this, "filedialog", true);
+ dlg.setOperationMode( KFileDialog::Opening );
+ dlg.setCaption( i18n("Open") );
+ dlg.setMode( KFile::File );
+
+ KImageFilePreview *ip = new KImageFilePreview( &dlg );
+ dlg.setPreviewWidget( ip );
+ dlg.exec();
+
+ file = dlg.selectedFile();
+ if (!file.isEmpty())
+ {
+ d->custom = file;
+ if ( mType == 1 )
+ d->customLocation = QFileInfo( file ).dirPath( true );
+ slotOk();
+ }
+ }
+ break;
+ }
+}
+
+void KIconDialog::slotContext(int id)
+{
+ mContext = static_cast<KIcon::Context>( mContextMap[ id ] );
+ showIcons();
+}
+
+void KIconDialog::slotStartLoading(int steps)
+{
+ if (steps < 10)
+ mpProgress->hide();
+ else
+ {
+ mpProgress->setTotalSteps(steps);
+ mpProgress->setProgress(0);
+ mpProgress->show();
+ }
+}
+
+void KIconDialog::slotProgress(int p)
+{
+ mpProgress->setProgress(p);
+ // commented out the following since setProgress already paints ther
+ // progress bar. ->repaint() only makes it flicker
+ //mpProgress->repaint();
+}
+
+void KIconDialog::slotFinished()
+{
+ mpProgress->hide();
+}
+
+class KIconButton::KIconButtonPrivate
+{
+ public:
+ KIconButtonPrivate() {
+ m_bStrictIconSize = false;
+ iconSize = 0; // let KIconLoader choose the default
+ }
+ ~KIconButtonPrivate() {}
+ bool m_bStrictIconSize;
+ int iconSize;
+};
+
+
+/*
+ * KIconButton: A "choose icon" pushbutton.
+ */
+
+KIconButton::KIconButton(QWidget *parent, const char *name)
+ : QPushButton(parent, name)
+{
+ init( KGlobal::iconLoader() );
+}
+
+KIconButton::KIconButton(KIconLoader *loader,
+ QWidget *parent, const char *name)
+ : QPushButton(parent, name)
+{
+ init( loader );
+}
+
+void KIconButton::init( KIconLoader *loader )
+{
+ d = new KIconButtonPrivate;
+ mGroup = KIcon::Desktop;
+ mContext = KIcon::Application;
+ mbUser = false;
+
+ mpLoader = loader;
+ mpDialog = 0L;
+ connect(this, SIGNAL(clicked()), SLOT(slotChangeIcon()));
+}
+
+KIconButton::~KIconButton()
+{
+ delete mpDialog;
+ delete d;
+}
+
+void KIconButton::setStrictIconSize(bool b)
+{
+ d->m_bStrictIconSize=b;
+}
+
+bool KIconButton::strictIconSize() const
+{
+ return d->m_bStrictIconSize;
+}
+
+void KIconButton::setIconSize( int size )
+{
+ d->iconSize = size;
+}
+
+int KIconButton::iconSize() const
+{
+ return d->iconSize;
+}
+
+void KIconButton::setIconType(KIcon::Group group, KIcon::Context context, bool user)
+{
+ mGroup = group;
+ mContext = context;
+ mbUser = user;
+}
+
+void KIconButton::setIcon(const QString& icon)
+{
+ mIcon = icon;
+ setIconSet(mpLoader->loadIconSet(mIcon, mGroup, d->iconSize));
+
+ if (!mpDialog)
+ {
+ mpDialog = new KIconDialog(mpLoader, this);
+ connect(mpDialog, SIGNAL(newIconName(const QString&)), SLOT(newIconName(const QString&)));
+ }
+
+ if ( mbUser )
+ mpDialog->setCustomLocation( QFileInfo( mpLoader->iconPath(mIcon, mGroup, true) ).dirPath( true ) );
+}
+
+void KIconButton::resetIcon()
+{
+ mIcon = QString::null;
+ setIconSet(QIconSet());
+}
+
+void KIconButton::slotChangeIcon()
+{
+ if (!mpDialog)
+ {
+ mpDialog = new KIconDialog(mpLoader, this);
+ connect(mpDialog, SIGNAL(newIconName(const QString&)), SLOT(newIconName(const QString&)));
+ }
+
+ mpDialog->setup( mGroup, mContext, d->m_bStrictIconSize, d->iconSize, mbUser );
+ mpDialog->showDialog();
+}
+
+void KIconButton::newIconName(const QString& name)
+{
+ if (name.isEmpty())
+ return;
+
+ QIconSet iconset = mpLoader->loadIconSet(name, mGroup, d->iconSize);
+ setIconSet(iconset);
+ mIcon = name;
+
+ if ( mbUser )
+ mpDialog->setCustomLocation( QFileInfo( mpLoader->iconPath(mIcon, mGroup, true) ).dirPath( true ) );
+
+ emit iconChanged(name);
+}
+
+void KIconCanvas::virtual_hook( int id, void* data )
+{ KIconView::virtual_hook( id, data ); }
+
+void KIconDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+#include "kicondialog.moc"
diff --git a/kio/kfile/kicondialog.h b/kio/kfile/kicondialog.h
new file mode 100644
index 000000000..e6cf4e2fe
--- /dev/null
+++ b/kio/kfile/kicondialog.h
@@ -0,0 +1,350 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kfile.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * (C) 2000 Kurt Granroth <granroth@kde.org>
+ * (C) 1997 Christoph Neerfeld <chris@kde.org>
+ * (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ */
+
+#ifndef __KIconDialog_h__
+#define __KIconDialog_h__
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qpushbutton.h>
+
+#include <kicontheme.h>
+#include <kdialogbase.h>
+#include <kiconview.h>
+
+class QComboBox;
+class QTimer;
+class QKeyEvent;
+class QRadioButton;
+class KProgress;
+class KIconLoader;
+
+/**
+ * Icon canvas for KIconDialog.
+ */
+class KIO_EXPORT KIconCanvas: public KIconView
+{
+ Q_OBJECT
+
+public:
+ KIconCanvas(QWidget *parent=0L, const char *name=0L);
+ ~KIconCanvas();
+
+ /**
+ * Load icons into the canvas.
+ */
+ void loadFiles(const QStringList& files);
+
+ /**
+ * Returns the current icon.
+ */
+ QString getCurrent() const;
+
+public slots:
+ void stopLoading();
+
+signals:
+ /**
+ * Emitted when the current icon has changed.
+ */
+ void nameChanged(QString);
+ /* KDE 4: Make it const QString & */
+
+ void startLoading(int);
+ void progress(int);
+ void finished();
+
+private slots:
+ void slotLoadFiles();
+ void slotCurrentChanged(QIconViewItem *item);
+
+private:
+ QStringList mFiles;
+ QTimer *mpTimer;
+ KIconLoader *mpLoader; // unused
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+
+private:
+ class KIconCanvasPrivate;
+ KIconCanvasPrivate *d;
+};
+
+
+/**
+ * Dialog for interactive selection of icons. Use the function
+ * getIcon() let the user select an icon.
+ *
+ * @short An icon selection dialog.
+ */
+class KIO_EXPORT KIconDialog: public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs an icon selection dialog using the global iconloader.
+ */
+ KIconDialog(QWidget *parent=0L, const char *name=0L);
+ /**
+ * Constructs an icon selection dialog using a specific iconloader.
+ */
+ KIconDialog(KIconLoader *loader, QWidget *parent=0,
+ const char *name=0);
+ /**
+ * Destructs the dialog.
+ */
+ ~KIconDialog();
+
+ /**
+ * Sets a strict icon size policy for allowed icons. When true,
+ * only icons of the specified group's size in getIcon() are shown.
+ * When false, icons not available at the desired group's size will
+ * also be selectable.
+ */
+ void setStrictIconSize(bool b);
+ /**
+ * Returns true if a strict icon size policy is set.
+ */
+ bool strictIconSize() const;
+ /**
+ * sets a custom icon directory
+ * @since 3.1
+ */
+ void setCustomLocation( const QString& location );
+
+ /**
+ * Sets the size of the icons to be shown / selected.
+ * @see KIcon::StdSizes
+ * @see iconSize
+ */
+ void setIconSize(int size);
+
+ /**
+ * Returns the iconsize set via setIconSize() or 0, if the default
+ * iconsize will be used.
+ */
+ int iconSize() const;
+
+#ifndef KDE_NO_COMPAT
+ /**
+ * @deprecated in KDE 3.0, use the static method getIcon instead.
+ */
+ QString selectIcon(KIcon::Group group=KIcon::Desktop, KIcon::Context
+ context=KIcon::Application, bool user=false);
+#endif
+
+ /**
+ * Allows you to set the same parameters as in the class method
+ * getIcon().
+ */
+ void setup( KIcon::Group group,
+ KIcon::Context context = KIcon::Application,
+ bool strictIconSize = false, int iconSize = 0,
+ bool user = false );
+
+ /**
+ * Allows you to set the same parameters as in the class method
+ * getIcon(), as well as two additional parameters to lock
+ * the choice between system and user dirs and to lock the custom user
+ * dir itself.
+ *
+ * @since 3.3
+ */
+
+ void setup( KIcon::Group group, KIcon::Context context,
+ bool strictIconSize, int iconSize, bool user, bool lockUser,
+ bool lockCustomDir );
+
+ /**
+ * exec()utes this modal dialog and returns the name of the selected icon,
+ * or QString::null if the dialog was aborted.
+ * @returns the name of the icon, suitable for loading with KIconLoader.
+ * @see getIcon
+ */
+ QString openDialog();
+
+ /**
+ * show()es this dialog and emits a newIcon(const QString&) signal when
+ * successful. QString::null will be emitted if the dialog was aborted.
+ */
+ void showDialog();
+
+ /**
+ * Pops up the dialog an lets the user select an icon.
+ *
+ * @param group The icon group this icon is intended for. Providing the
+ * group shows the icons in the dialog with the same appearance as when
+ * used outside the dialog.
+ * @param context The initial icon context. Initially, the icons having
+ * this context are shown in the dialog. The user can change this.
+ * @param strictIconSize When true, only icons of the specified group's size
+ * are shown, otherwise icon not available in the desired group's size
+ * will also be selectable.
+ * @param iconSize the size of the icons -- the default of the icongroup
+ * if set to 0
+ * @param user Begin with the "user icons" instead of "system icons".
+ * @param parent The parent widget of the dialog.
+ * @param caption The caption to use for the dialog.
+ * @return The name of the icon, suitable for loading with KIconLoader.
+ * @version New in 3.0
+ */
+ static QString getIcon(KIcon::Group group=KIcon::Desktop,
+ KIcon::Context context=KIcon::Application,
+ bool strictIconSize=false, int iconSize = 0,
+ bool user=false, QWidget *parent=0,
+ const QString &caption=QString::null);
+
+signals:
+ void newIconName(const QString&);
+
+protected slots:
+ void slotOk();
+
+private slots:
+ void slotButtonClicked(int);
+ void slotContext(int);
+ void slotStartLoading(int);
+ void slotProgress(int);
+ void slotFinished();
+ void slotAcceptIcons();
+private:
+ void init();
+ void showIcons();
+ void setContext( KIcon::Context context );
+
+ int mGroupOrSize;
+ KIcon::Context mContext;
+ int mType;
+
+ QStringList mFileList;
+ QComboBox *mpCombo;
+ QPushButton *mpBrowseBut;
+ QRadioButton *mpRb1, *mpRb2;
+ KProgress *mpProgress;
+ KIconLoader *mpLoader;
+ KIconCanvas *mpCanvas;
+ int mNumContext;
+ KIcon::Context mContextMap[ 12 ]; // must match KIcon::Context size, code has assert
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KIconDialogPrivate;
+ KIconDialogPrivate *d;
+};
+
+
+/**
+ * A pushbutton for choosing an icon. Pressing on the button will open a
+ * KIconDialog for the user to select an icon. The current icon will be
+ * displayed on the button.
+ *
+ * @see KIconDialog
+ * @short A push button that allows selection of an icon.
+ */
+class KIO_EXPORT KIconButton: public QPushButton
+{
+ Q_OBJECT
+ Q_PROPERTY( QString icon READ icon WRITE setIcon RESET resetIcon )
+ Q_PROPERTY( int iconSize READ iconSize WRITE setIconSize)
+ Q_PROPERTY( bool strictIconSize READ strictIconSize WRITE setStrictIconSize )
+
+public:
+ /**
+ * Constructs a KIconButton using the global iconloader.
+ */
+ KIconButton(QWidget *parent=0L, const char *name=0L);
+
+ /**
+ * Constructs a KIconButton using a specific KIconLoader.
+ */
+ KIconButton(KIconLoader *loader, QWidget *parent, const char *name=0L);
+ /**
+ * Destructs the button.
+ */
+ ~KIconButton();
+
+ /**
+ * Sets a strict icon size policy for allowed icons. When true,
+ * only icons of the specified group's size in setIconType are allowed,
+ * and only icons of that size will be shown in the icon dialog.
+ */
+ void setStrictIconSize(bool b);
+ /**
+ * Returns true if a strict icon size policy is set.
+ */
+ bool strictIconSize() const;
+
+ /**
+ * Sets the icon group and context. Use KIcon::NoGroup if you want to
+ * allow icons for any group in the given context.
+ */
+ void setIconType(KIcon::Group group, KIcon::Context context, bool user=false);
+
+ /**
+ * Sets the button's initial icon.
+ */
+ void setIcon(const QString& icon);
+
+ /**
+ * Resets the icon (reverts to an empty button).
+ */
+ void resetIcon();
+
+ /**
+ * Returns the name of the selected icon.
+ */
+ QString icon() const { return mIcon; }
+
+ /**
+ * Sets the size of the icon to be shown / selected.
+ * @see KIcon::StdSizes
+ * @see iconSize
+ */
+ void setIconSize( int size );
+
+ /**
+ * Returns the iconsize set via setIconSize() or 0, if the default
+ * iconsize will be used.
+ */
+ int iconSize() const;
+
+signals:
+ /**
+ * Emitted when the icon has changed.
+ */
+ void iconChanged(QString icon);
+ /* KDE 4: Make it const QString & */
+
+private slots:
+ void slotChangeIcon();
+ void newIconName(const QString& name);
+
+private:
+ void init( KIconLoader *loader );
+
+ bool mbUser;
+ KIcon::Group mGroup;
+ KIcon::Context mContext;
+
+ QString mIcon;
+ KIconDialog *mpDialog;
+ KIconLoader *mpLoader;
+ class KIconButtonPrivate;
+ KIconButtonPrivate *d;
+};
+
+
+#endif // __KIconDialog_h__
diff --git a/kio/kfile/kimagefilepreview.cpp b/kio/kfile/kimagefilepreview.cpp
new file mode 100644
index 000000000..d973c6e1b
--- /dev/null
+++ b/kio/kfile/kimagefilepreview.cpp
@@ -0,0 +1,187 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2001 Martin R. Jones <mjones@kde.org>
+ * 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qwhatsthis.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kfileitem.h>
+#include <kio/previewjob.h>
+
+#include "kimagefilepreview.h"
+#include "config-kfile.h"
+
+/**** KImageFilePreview ****/
+
+KImageFilePreview::KImageFilePreview( QWidget *parent )
+ : KPreviewWidgetBase( parent ),
+ m_job( 0L )
+{
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs( config, ConfigGroup );
+ autoMode = config->readBoolEntry( "Automatic Preview", true );
+
+ QVBoxLayout *vb = new QVBoxLayout( this, 0, KDialog::spacingHint() );
+
+ imageLabel = new QLabel( this );
+ imageLabel->setFrameStyle( QFrame::NoFrame );
+ imageLabel->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
+ imageLabel->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding) );
+ vb->addWidget( imageLabel );
+
+ QHBoxLayout *hb = new QHBoxLayout( 0 );
+ vb->addLayout( hb );
+
+ autoPreview = new QCheckBox( i18n("&Automatic preview"), this );
+ autoPreview->setChecked( autoMode );
+ hb->addWidget( autoPreview );
+ connect( autoPreview, SIGNAL(toggled(bool)), SLOT(toggleAuto(bool)) );
+
+ previewButton = new KPushButton( SmallIconSet("thumbnail"), i18n("&Preview"), this );
+ hb->addWidget( previewButton );
+ connect( previewButton, SIGNAL(clicked()), SLOT(showPreview()) );
+
+ timer = new QTimer( this );
+ connect( timer, SIGNAL(timeout()), SLOT(showPreview()) );
+
+ setSupportedMimeTypes( KIO::PreviewJob::supportedMimeTypes() );
+}
+
+KImageFilePreview::~KImageFilePreview()
+{
+ if ( m_job )
+ m_job->kill();
+
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs( config, ConfigGroup );
+ config->writeEntry( "Automatic Preview", autoPreview->isChecked() );
+}
+
+void KImageFilePreview::showPreview()
+{
+ // Pass a copy since clearPreview() will clear currentURL
+ KURL url = currentURL;
+ showPreview( url, true );
+}
+
+// called via KPreviewWidgetBase interface
+void KImageFilePreview::showPreview( const KURL& url )
+{
+ showPreview( url, false );
+}
+
+void KImageFilePreview::showPreview( const KURL &url, bool force )
+{
+ if ( !url.isValid() ) {
+ clearPreview();
+ return;
+ }
+
+ if ( url != currentURL || force )
+ {
+ clearPreview();
+ currentURL = url;
+
+ if ( autoMode || force )
+ {
+ int w = imageLabel->contentsRect().width() - 4;
+ int h = imageLabel->contentsRect().height() - 4;
+
+ m_job = createJob( url, w, h );
+ if ( force ) // explicitly requested previews shall always be generated!
+ m_job->setIgnoreMaximumSize( true );
+
+ connect( m_job, SIGNAL( result( KIO::Job * )),
+ this, SLOT( slotResult( KIO::Job * )));
+ connect( m_job, SIGNAL( gotPreview( const KFileItem*,
+ const QPixmap& )),
+ SLOT( gotPreview( const KFileItem*, const QPixmap& ) ));
+
+ connect( m_job, SIGNAL( failed( const KFileItem* )),
+ this, SLOT( slotFailed( const KFileItem* ) ));
+ }
+ }
+}
+
+void KImageFilePreview::toggleAuto( bool a )
+{
+ autoMode = a;
+ if ( autoMode )
+ {
+ // Pass a copy since clearPreview() will clear currentURL
+ KURL url = currentURL;
+ showPreview( url, true );
+ }
+}
+
+void KImageFilePreview::resizeEvent( QResizeEvent * )
+{
+ timer->start( 100, true ); // forces a new preview
+}
+
+QSize KImageFilePreview::sizeHint() const
+{
+ return QSize( 20, 200 ); // otherwise it ends up huge???
+}
+
+KIO::PreviewJob * KImageFilePreview::createJob( const KURL& url, int w, int h )
+{
+ KURL::List urls;
+ urls.append( url );
+ return KIO::filePreview( urls, w, h, 0, 0, true, false );
+}
+
+void KImageFilePreview::gotPreview( const KFileItem* item, const QPixmap& pm )
+{
+ if ( item->url() == currentURL ) // should always be the case
+ imageLabel->setPixmap( pm );
+}
+
+void KImageFilePreview::slotFailed( const KFileItem* item )
+{
+ if ( item->isDir() )
+ imageLabel->clear();
+ else if ( item->url() == currentURL ) // should always be the case
+ imageLabel->setPixmap( SmallIcon( "file_broken", KIcon::SizeLarge,
+ KIcon::DisabledState ));
+}
+
+void KImageFilePreview::slotResult( KIO::Job *job )
+{
+ if ( job == m_job )
+ m_job = 0L;
+}
+
+void KImageFilePreview::clearPreview()
+{
+ if ( m_job ) {
+ m_job->kill();
+ m_job = 0L;
+ }
+
+ imageLabel->clear();
+ currentURL = KURL();
+}
+
+void KImageFilePreview::virtual_hook( int id, void* data )
+{ KPreviewWidgetBase::virtual_hook( id, data ); }
+
+#include "kimagefilepreview.moc"
diff --git a/kio/kfile/kimagefilepreview.h b/kio/kfile/kimagefilepreview.h
new file mode 100644
index 000000000..cb034265a
--- /dev/null
+++ b/kio/kfile/kimagefilepreview.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * This file is part of the KDE project.
+ * Copyright (C) 2001 Martin R. Jones <mjones@kde.org>
+ * 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef KIMAGEFILEPREVIEW_H
+#define KIMAGEFILEPREVIEW_H
+
+#include <qpixmap.h>
+
+#include <kurl.h>
+#include <kpreviewwidgetbase.h>
+
+class QCheckBox;
+class QPushButton;
+class QLabel;
+class QTimer;
+
+class KFileDialog;
+class KFileItem;
+namespace KIO { class Job; class PreviewJob; }
+
+/**
+ * Image preview widget for the file dialog.
+ */
+class KIO_EXPORT KImageFilePreview : public KPreviewWidgetBase
+{
+ Q_OBJECT
+
+ public:
+ KImageFilePreview(QWidget *parent);
+ ~KImageFilePreview();
+
+ virtual QSize sizeHint() const;
+
+ public slots:
+ virtual void showPreview(const KURL &url);
+ virtual void clearPreview();
+
+ protected slots:
+ void showPreview();
+ void showPreview( const KURL& url, bool force );
+
+ void toggleAuto(bool);
+ virtual void gotPreview( const KFileItem*, const QPixmap& );
+
+ protected:
+ virtual void resizeEvent(QResizeEvent *e);
+ virtual KIO::PreviewJob * createJob( const KURL& url,
+ int w, int h );
+
+ private slots:
+ void slotResult( KIO::Job * );
+ virtual void slotFailed( const KFileItem* );
+
+ private:
+ bool autoMode;
+ KURL currentURL;
+ QTimer *timer;
+ QLabel *imageLabel;
+ QLabel *infoLabel;
+ QCheckBox *autoPreview;
+ QPushButton *previewButton;
+ KIO::PreviewJob *m_job;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class KImageFilePreviewPrivate;
+ KImageFilePreviewPrivate *d;
+};
+
+#endif // KIMAGEFILEPREVIEW_H
diff --git a/kio/kfile/kmetaprops.cpp b/kio/kfile/kmetaprops.cpp
new file mode 100644
index 000000000..b3ff504fc
--- /dev/null
+++ b/kio/kfile/kmetaprops.cpp
@@ -0,0 +1,268 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Rolf Magnus <ramagnus@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ $Id$
+ */
+
+#include "kmetaprops.h"
+
+#include <kdebug.h>
+#include <kfilemetainfowidget.h>
+#include <kfilemetainfo.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+
+#include <qvalidator.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qdatetime.h>
+#include <qstylesheet.h>
+#include <qvgroupbox.h>
+
+#undef Bool
+
+class MetaPropsScrollView : public QScrollView
+{
+public:
+ MetaPropsScrollView(QWidget* parent = 0, const char* name = 0)
+ : QScrollView(parent, name)
+ {
+ setFrameStyle(QFrame::NoFrame);
+ m_frame = new QFrame(viewport(), "MetaPropsScrollView::m_frame");
+ m_frame->setFrameStyle(QFrame::NoFrame);
+ addChild(m_frame, 0, 0);
+ };
+
+ QFrame* frame() {return m_frame;};
+
+protected:
+ virtual void viewportResizeEvent(QResizeEvent* ev)
+ {
+ QScrollView::viewportResizeEvent(ev);
+ m_frame->resize( kMax(m_frame->sizeHint().width(), ev->size().width()),
+ kMax(m_frame->sizeHint().height(), ev->size().height()));
+ };
+
+private:
+ QFrame* m_frame;
+};
+
+class KFileMetaPropsPlugin::KFileMetaPropsPluginPrivate
+{
+public:
+ KFileMetaPropsPluginPrivate() {}
+ ~KFileMetaPropsPluginPrivate() {}
+
+ QFrame* m_frame;
+ QGridLayout* m_framelayout;
+ KFileMetaInfo m_info;
+// QPushButton* m_add;
+ QPtrList<KFileMetaInfoWidget> m_editWidgets;
+};
+
+KFileMetaPropsPlugin::KFileMetaPropsPlugin(KPropertiesDialog* props)
+ : KPropsDlgPlugin(props)
+{
+ d = new KFileMetaPropsPluginPrivate;
+
+ KFileItem * fileitem = properties->item();
+ kdDebug(250) << "KFileMetaPropsPlugin constructor" << endl;
+
+ d->m_info = fileitem->metaInfo();
+ if (!d->m_info.isValid())
+ {
+ d->m_info = KFileMetaInfo(properties->kurl().path(-1));
+ fileitem->setMetaInfo(d->m_info);
+ }
+
+ if ( properties->items().count() > 1 )
+ {
+ // not yet supported
+ // we should allow setting values for a list of files. Itt makes sense
+ // in some cases, like the album of a list of mp3s
+ return;
+ }
+
+ createLayout();
+
+ setDirty(true);
+}
+
+void KFileMetaPropsPlugin::createLayout()
+{
+ QFileInfo file_info(properties->item()->url().path());
+
+ kdDebug(250) << "KFileMetaPropsPlugin::createLayout" << endl;
+
+ // is there any valid and non-empty info at all?
+ if ( !d->m_info.isValid() || (d->m_info.preferredKeys()).isEmpty() )
+ return;
+
+ // now get a list of groups
+ KFileMetaInfoProvider* prov = KFileMetaInfoProvider::self();
+ QStringList groupList = d->m_info.preferredGroups();
+
+ const KFileMimeTypeInfo* mtinfo = prov->mimeTypeInfo(d->m_info.mimeType());
+ if (!mtinfo)
+ {
+ kdDebug(7034) << "no mimetype info there\n";
+ return;
+ }
+
+ // let the dialog create the page frame
+ QFrame* topframe = properties->addPage(i18n("&Meta Info"));
+ topframe->setFrameStyle(QFrame::NoFrame);
+ QVBoxLayout* tmp = new QVBoxLayout(topframe);
+
+ // create a scroll view in the page
+ MetaPropsScrollView* view = new MetaPropsScrollView(topframe);
+
+ tmp->addWidget(view);
+
+ d->m_frame = view->frame();
+
+ QVBoxLayout *toplayout = new QVBoxLayout(d->m_frame);
+ toplayout->setSpacing(KDialog::spacingHint());
+
+ for (QStringList::Iterator git=groupList.begin();
+ git!=groupList.end(); ++git)
+ {
+ kdDebug(7033) << *git << endl;
+
+ QStringList itemList = d->m_info.group(*git).preferredKeys();
+ if (itemList.isEmpty())
+ continue;
+
+ QGroupBox *groupBox = new QGroupBox(2, Qt::Horizontal,
+ QStyleSheet::escape(mtinfo->groupInfo(*git)->translatedName()),
+ d->m_frame);
+
+ toplayout->addWidget(groupBox);
+
+ QValueList<KFileMetaInfoItem> readItems;
+ QValueList<KFileMetaInfoItem> editItems;
+
+ for (QStringList::Iterator iit = itemList.begin();
+ iit!=itemList.end(); ++iit)
+ {
+ KFileMetaInfoItem item = d->m_info[*git][*iit];
+ if ( !item.isValid() ) continue;
+
+ bool editable = file_info.isWritable() && item.isEditable();
+
+ if (editable)
+ editItems.append( item );
+ else
+ readItems.append( item );
+ }
+
+ KFileMetaInfoWidget* w = 0L;
+ // then first add the editable items to the layout
+ for (QValueList<KFileMetaInfoItem>::Iterator iit= editItems.begin();
+ iit!=editItems.end(); ++iit)
+ {
+ QLabel* l = new QLabel((*iit).translatedKey() + ":", groupBox);
+ l->setAlignment( AlignAuto | AlignTop | ExpandTabs );
+ QValidator* val = mtinfo->createValidator(*git, (*iit).key());
+ if (!val) kdDebug(7033) << "didn't get a validator for " << *git << "/" << (*iit).key() << endl;
+ w = new KFileMetaInfoWidget(*iit, val, groupBox);
+ d->m_editWidgets.append( w );
+ connect(w, SIGNAL(valueChanged(const QVariant&)), this, SIGNAL(changed()));
+ }
+
+ // and then the read only items
+ for (QValueList<KFileMetaInfoItem>::Iterator iit= readItems.begin();
+ iit!=readItems.end(); ++iit)
+ {
+ QLabel* l = new QLabel((*iit).translatedKey() + ":", groupBox);
+ l->setAlignment( AlignAuto | AlignTop | ExpandTabs );
+ (new KFileMetaInfoWidget(*iit, KFileMetaInfoWidget::ReadOnly, 0L, groupBox));
+ }
+ }
+
+ toplayout->addStretch(1);
+
+ // the add key (disabled until fully implemented)
+/* d->m_add = new QPushButton(i18n("&Add"), topframe);
+ d->m_add->setSizePolicy(QSizePolicy(QSizePolicy::Fixed,
+ QSizePolicy::Fixed));
+ connect(d->m_add, SIGNAL(clicked()), this, SLOT(slotAdd()));
+ tmp->addWidget(d->m_add);
+
+ // if nothing can be added, deactivate it
+ if ( !d->m_info.supportsVariableKeys() )
+ {
+ // if supportedKeys() does contain anything not in preferredKeys,
+ // we have something addable
+
+ QStringList sk = d->m_info.supportedKeys();
+ d->m_add->setEnabled(false);
+ for (QStringList::Iterator it = sk.begin(); it!=sk.end(); ++it)
+ {
+ if ( l.find(*it)==l.end() )
+ {
+ d->m_add->setEnabled(true);
+ kdDebug(250) << "**first addable key is " << (*it).latin1() << "**" <<endl;
+ break;
+ }
+ kdDebug(250) << "**already existing key is " << (*it).latin1() << "**" <<endl;
+ }
+ } */
+}
+
+/*void KFileMetaPropsPlugin::slotAdd()
+{
+ // add a lineedit for the name
+
+
+
+ // insert the item in the list
+
+}*/
+
+KFileMetaPropsPlugin::~KFileMetaPropsPlugin()
+{
+ delete d;
+}
+
+bool KFileMetaPropsPlugin::supports( KFileItemList _items )
+{
+#ifdef _GNUC
+#warning TODO: Add support for more than one item
+#endif
+ if (KExecPropsPlugin::supports(_items) || KURLPropsPlugin::supports(_items))
+ return false; // Having both is redundant.
+
+ bool metaDataEnabled = KGlobalSettings::showFilePreview(_items.first()->url());
+ return _items.count() == 1 && metaDataEnabled;
+}
+
+void KFileMetaPropsPlugin::applyChanges()
+{
+ kdDebug(250) << "applying changes" << endl;
+ // insert the fields that changed into the info object
+
+ QPtrListIterator<KFileMetaInfoWidget> it( d->m_editWidgets );
+ KFileMetaInfoWidget* w;
+ for (; (w = it.current()); ++it) w->apply();
+ d->m_info.applyChanges(properties->kurl().path());
+}
+
+#include "kmetaprops.moc"
diff --git a/kio/kfile/kmetaprops.h b/kio/kfile/kmetaprops.h
new file mode 100644
index 000000000..dfa9b6e33
--- /dev/null
+++ b/kio/kfile/kmetaprops.h
@@ -0,0 +1,69 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Rolf Magnus <ramagnus@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ */
+
+#ifndef __KMETAPROPS_H__
+#define __KMETAPROPS_H__
+#include <kpropertiesdialog.h>
+
+
+class KFileMetaInfoItem;
+
+/*!
+ * 'MetaProps plugin
+ * In this plugin you can modify meta information like id3 tags of mp3 files
+ */
+class KIO_EXPORT KFileMetaPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KFileMetaPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KFileMetaPropsPlugin();
+
+ virtual void applyChanges();
+
+ /**
+ * Tests whether the file specified by _items has a 'MetaInfo' plugin.
+ */
+ static bool supports( KFileItemList _items );
+
+private:
+ void createLayout();
+
+ QWidget* makeBoolWidget(const KFileMetaInfoItem& item, QWidget* parent);
+ QWidget* makeIntWidget(const KFileMetaInfoItem& item, QWidget* parent,
+ QString& valClass);
+ QWidget* makeStringWidget(const KFileMetaInfoItem& item, QWidget* parent,
+ QString& valClass);
+ QWidget* makeDateTimeWidget(const KFileMetaInfoItem& item, QWidget* parent,
+ QString& valClass);
+
+private slots:
+ // Code disabled until the "Add" button is implemented
+// void slotAdd();
+
+private:
+
+ class KFileMetaPropsPluginPrivate;
+ KFileMetaPropsPluginPrivate *d;
+};
+
+#endif
diff --git a/kio/kfile/knotifydialog.cpp b/kio/kfile/knotifydialog.cpp
new file mode 100644
index 000000000..6543344e2
--- /dev/null
+++ b/kio/kfile/knotifydialog.cpp
@@ -0,0 +1,1191 @@
+/*
+ Copyright (C) 2000,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ Copyright (C) 2002 Neil Stevens <neil@qualityassistant.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation;
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library, If not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <dcopclient.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kaudioplayer.h>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kcursor.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <kicontheme.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knotifyclient.h>
+#include <knotifydialog.h>
+#include <kstandarddirs.h>
+#include <kurlrequester.h>
+#include <kio/netaccess.h>
+
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qheader.h>
+#include <qlabel.h>
+#include <qlistview.h>
+#include <qlayout.h>
+#include <qptrlist.h>
+#include <qpushbutton.h>
+#include <qstring.h>
+#include <qtooltip.h>
+#include <qtimer.h>
+#include <qvbox.h>
+#include <qwhatsthis.h>
+
+using namespace KNotify;
+
+enum
+{
+ COL_EXECUTE = 0,
+ COL_STDERR = 1,
+ COL_MESSAGE = 2,
+ COL_LOGFILE = 3,
+ COL_SOUND = 4,
+ COL_TASKBAR = 5,
+ COL_EVENT = 6
+};
+
+//
+// I don't feel like subclassing KComboBox and find ways to insert that into
+// the .ui file...
+//
+namespace KNotify
+{
+ class SelectionCombo
+ {
+ public:
+ //
+ // Mind the order in fill() and type()
+ //
+ static void fill( KComboBox *combo )
+ {
+ combo->insertItem( i18n("Sounds") );
+ combo->insertItem( i18n("Logging") );
+ combo->insertItem( i18n("Program Execution") );
+ combo->insertItem( i18n("Message Windows") );
+ combo->insertItem( i18n("Passive Windows") );
+ combo->insertItem( i18n("Standard Error Output") );
+ combo->insertItem( i18n("Taskbar") );
+ }
+
+ static int type( KComboBox *combo )
+ {
+ switch( combo->currentItem() )
+ {
+ case 0:
+ return KNotifyClient::Sound;
+ case 1:
+ return KNotifyClient::Logfile;
+ case 2:
+ return KNotifyClient::Execute;
+ case 3:
+ return KNotifyClient::Messagebox;
+ case 4:
+ return KNotifyClient::PassivePopup;
+ case 5:
+ return KNotifyClient::Stderr;
+ case 6:
+ return KNotifyClient::Taskbar;
+ }
+
+ return KNotifyClient::None;
+ }
+ };
+
+ // Needed for displaying tooltips in the listview's QHeader
+ class KNotifyToolTip : public QToolTip
+ {
+ public:
+ KNotifyToolTip( QHeader *header )
+ : QToolTip( header )
+ {
+ m_tips[COL_EXECUTE] = i18n("Execute a program");
+ m_tips[COL_STDERR] = i18n("Print to Standard error output");
+ m_tips[COL_MESSAGE] = i18n("Display a messagebox");
+ m_tips[COL_LOGFILE] = i18n("Log to a file");
+ m_tips[COL_SOUND] = i18n("Play a sound");
+ m_tips[COL_TASKBAR] = i18n("Flash the taskbar entry");
+ }
+ virtual ~KNotifyToolTip() {}
+
+ protected:
+ virtual void maybeTip ( const QPoint& p )
+ {
+ QHeader *header = static_cast<QHeader*>( parentWidget() );
+ int section = 0;
+
+ if ( header->orientation() == Horizontal )
+ section= header->sectionAt( p.x() );
+ else
+ section= header->sectionAt( p.y() );
+
+ if ( ( section < 0 ) || ( static_cast<uint>( section ) >= (sizeof(m_tips) / sizeof(QString)) ) )
+ return;
+
+ tip( header->sectionRect( section ), m_tips[section] );
+ }
+
+ private:
+ QString m_tips[6];
+ };
+
+}
+
+
+int KNotifyDialog::configure( QWidget *parent, const char *name,
+ const KAboutData *aboutData )
+{
+ KNotifyDialog dialog( parent, name, true, aboutData );
+ return dialog.exec();
+}
+
+KNotifyDialog::KNotifyDialog( QWidget *parent, const char *name, bool modal,
+ const KAboutData *aboutData )
+ : KDialogBase(parent, name, modal, i18n("Notification Settings"),
+ Ok | Apply | Cancel | Default, Ok, true )
+{
+ QVBox *box = makeVBoxMainWidget();
+
+ m_notifyWidget = new KNotifyWidget( box, "knotify widget" );
+
+ if ( aboutData )
+ addApplicationEvents( aboutData->appName() );
+
+ connect( this, SIGNAL( okClicked() ), m_notifyWidget, SLOT( save() ));
+ connect( this, SIGNAL( applyClicked() ), m_notifyWidget, SLOT( save() ));
+}
+
+KNotifyDialog::~KNotifyDialog()
+{
+}
+
+void KNotifyDialog::addApplicationEvents( const char *appName )
+{
+ addApplicationEvents( QString::fromUtf8( appName ) +
+ QString::fromLatin1( "/eventsrc" ) );
+}
+
+void KNotifyDialog::addApplicationEvents( const QString& path )
+{
+ Application *app = m_notifyWidget->addApplicationEvents( path );
+ if ( app )
+ {
+ m_notifyWidget->addVisibleApp( app );
+ m_notifyWidget->sort();
+ }
+}
+
+void KNotifyDialog::clearApplicationEvents()
+{
+ m_notifyWidget->clear();
+}
+
+void KNotifyDialog::slotDefault()
+{
+ m_notifyWidget->resetDefaults( true ); // ask user
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+
+class KNotifyWidget::Private
+{
+public:
+ QPixmap pixmaps[6];
+ KNotifyToolTip *toolTip;
+};
+
+// simple access to all knotify-handled applications
+KNotifyWidget::KNotifyWidget( QWidget *parent, const char *name,
+ bool handleAllApps )
+ : KNotifyWidgetBase( parent, name ? name : "KNotifyWidget" )
+{
+ d = new Private;
+
+ m_allApps.setAutoDelete( true );
+
+ if ( !handleAllApps )
+ {
+ m_affectAllApps->hide();
+ m_playerButton->hide();
+ }
+
+ SelectionCombo::fill( m_comboEnable );
+ SelectionCombo::fill( m_comboDisable );
+
+ m_listview->setFullWidth( true );
+ m_listview->setAllColumnsShowFocus( true );
+
+ QPixmap pexec = SmallIcon("exec");
+ QPixmap pstderr = SmallIcon("terminal");
+ QPixmap pmessage = SmallIcon("info");
+ QPixmap plogfile = SmallIcon("log");
+ QPixmap psound = SmallIcon("sound");
+ QPixmap ptaskbar = SmallIcon("kicker");
+
+ d->pixmaps[COL_EXECUTE] = pexec;
+ d->pixmaps[COL_STDERR] = pstderr;
+ d->pixmaps[COL_MESSAGE] = pmessage;
+ d->pixmaps[COL_LOGFILE] = plogfile;
+ d->pixmaps[COL_SOUND] = psound;
+ d->pixmaps[COL_TASKBAR] = ptaskbar;
+
+ int w = KIcon::SizeSmall + 6;
+
+ QHeader *header = m_listview->header();
+ header->setLabel( COL_EXECUTE, pexec, QString::null, w );
+ header->setLabel( COL_STDERR, pstderr, QString::null, w );
+ header->setLabel( COL_MESSAGE, pmessage, QString::null, w );
+ header->setLabel( COL_LOGFILE, plogfile, QString::null, w );
+ header->setLabel( COL_SOUND, psound, QString::null, w );
+ header->setLabel( COL_TASKBAR, ptaskbar, QString::null, w );
+
+ d->toolTip = new KNotifyToolTip( header );
+
+ m_playButton->setIconSet( SmallIconSet( "player_play" ) );
+ connect( m_playButton, SIGNAL( clicked() ), SLOT( playSound() ));
+
+ connect( m_listview, SIGNAL( currentChanged( QListViewItem * ) ),
+ SLOT( slotEventChanged( QListViewItem * ) ));
+ connect( m_listview, SIGNAL(clicked( QListViewItem *, const QPoint&, int)),
+ SLOT( slotItemClicked( QListViewItem *, const QPoint&, int )));
+
+ connect( m_playSound, SIGNAL( toggled( bool )),
+ SLOT( soundToggled( bool )) );
+ connect( m_logToFile, SIGNAL( toggled( bool )),
+ SLOT( loggingToggled( bool )) );
+ connect( m_execute, SIGNAL( toggled( bool )),
+ SLOT( executeToggled( bool )) );
+ connect( m_messageBox, SIGNAL( toggled( bool )),
+ SLOT( messageBoxChanged() ) );
+ connect( m_passivePopup, SIGNAL( toggled( bool )),
+ SLOT( messageBoxChanged() ) );
+ connect( m_stderr, SIGNAL( toggled( bool )),
+ SLOT( stderrToggled( bool ) ) );
+ connect( m_taskbar, SIGNAL( toggled( bool )),
+ SLOT( taskbarToggled( bool ) ) );
+
+ connect( m_soundPath, SIGNAL( textChanged( const QString& )),
+ SLOT( soundFileChanged( const QString& )));
+ connect( m_logfilePath, SIGNAL( textChanged( const QString& )),
+ SLOT( logfileChanged( const QString& ) ));
+ connect( m_executePath, SIGNAL( textChanged( const QString& )),
+ SLOT( commandlineChanged( const QString& ) ));
+
+ connect( m_soundPath, SIGNAL( openFileDialog( KURLRequester * )),
+ SLOT( openSoundDialog( KURLRequester * )));
+ connect( m_logfilePath, SIGNAL( openFileDialog( KURLRequester * )),
+ SLOT( openLogDialog( KURLRequester * )));
+ connect( m_executePath, SIGNAL( openFileDialog( KURLRequester * )),
+ SLOT( openExecDialog( KURLRequester * )));
+
+ connect( m_extension, SIGNAL( clicked() ),
+ SLOT( toggleAdvanced()) );
+
+ connect( m_buttonEnable, SIGNAL( clicked() ), SLOT( enableAll() ));
+ connect( m_buttonDisable, SIGNAL( clicked() ), SLOT( enableAll() ));
+
+ QString whatsThis = i18n("<qt>You may use the following macros<br>"
+ "in the commandline:<br>"
+ "<b>%e</b>: for the event name,<br>"
+ "<b>%a</b>: for the name of the application that sent the event,<br>"
+ "<b>%s</b>: for the notification message,<br>"
+ "<b>%w</b>: for the numeric window ID where the event originated,<br>"
+ "<b>%i</b>: for the numeric event ID.");
+ QWhatsThis::add( m_execute, whatsThis );
+ QWhatsThis::add( m_executePath, whatsThis );
+
+ showAdvanced( false );
+
+ slotEventChanged( 0L ); // disable widgets by default
+}
+
+KNotifyWidget::~KNotifyWidget()
+{
+ delete d->toolTip;
+ delete d;
+}
+
+void KNotifyWidget::toggleAdvanced()
+{
+ showAdvanced( m_logToFile->isHidden() );
+}
+
+void KNotifyWidget::showAdvanced( bool show )
+{
+ if ( show )
+ {
+ m_extension->setText( i18n("Advanced <<") );
+ QToolTip::add( m_extension, i18n("Hide advanced options") );
+
+ m_logToFile->show();
+ m_logfilePath->show();
+ m_execute->show();
+ m_executePath->show();
+ m_messageBox->show();
+ m_passivePopup->show();
+ m_stderr->show();
+ m_taskbar->show();
+
+ m_passivePopup->setEnabled( m_messageBox->isChecked() );
+ m_actionsBoxLayout->setSpacing( KDialog::spacingHint() );
+ }
+ else
+ {
+ m_extension->setText( i18n("Advanced >>") );
+ QToolTip::add( m_extension, i18n("Show advanced options") );
+
+ m_logToFile->hide();
+ m_logfilePath->hide();
+ m_execute->hide();
+ m_executePath->hide();
+ m_messageBox->hide();
+ m_passivePopup->hide();
+ m_stderr->hide();
+ m_taskbar->hide();
+
+ m_actionsBoxLayout->setSpacing( 0 );
+ }
+}
+
+Application * KNotifyWidget::addApplicationEvents( const QString& path )
+{
+ kdDebug() << "**** knotify: adding path: " << path << endl;
+ QString relativePath = path;
+
+ if ( path.at(0) == '/' && KStandardDirs::exists( path ) )
+ relativePath = makeRelative( path );
+
+ if ( !relativePath.isEmpty() )
+ {
+ Application *app = new Application( relativePath );
+ m_allApps.append( app );
+ return app;
+ }
+
+ return 0L;
+}
+
+void KNotifyWidget::clear()
+{
+ clearVisible();
+ m_allApps.clear();
+}
+
+void KNotifyWidget::clearVisible()
+{
+ m_visibleApps.clear();
+ m_listview->clear();
+ slotEventChanged( 0L ); // disable widgets
+}
+
+void KNotifyWidget::showEvent( QShowEvent *e )
+{
+ selectItem( m_listview->firstChild() );
+ KNotifyWidgetBase::showEvent( e );
+}
+
+void KNotifyWidget::slotEventChanged( QListViewItem *item )
+{
+ bool on = (item != 0L);
+
+ m_actionsBox->setEnabled( on );
+ m_controlsBox->setEnabled( on );
+
+ if ( !on )
+ return;
+
+ ListViewItem *lit = static_cast<ListViewItem*>( item );
+ updateWidgets( lit );
+}
+
+void KNotifyWidget::updateWidgets( ListViewItem *item )
+{
+ bool enable;
+ bool checked;
+
+ blockSignals( true ); // don't emit changed() signals
+
+ const Event& event = item->event();
+
+ // sound settings
+ m_playButton->setEnabled( !event.soundfile.isEmpty() );
+ m_soundPath->setURL( event.soundfile );
+ enable = (event.dontShow & KNotifyClient::Sound) == 0;
+ checked = enable && !event.soundfile.isEmpty() &&
+ (event.presentation & KNotifyClient::Sound);
+ m_playSound->setEnabled( enable );
+ m_playSound->setChecked( checked );
+ m_soundPath->setEnabled( checked );
+
+
+ // logfile settings
+ m_logfilePath->setURL( event.logfile );
+ enable = (event.dontShow & KNotifyClient::Logfile) == 0;
+ checked = enable && !event.logfile.isEmpty() &&
+ (event.presentation & KNotifyClient::Logfile);
+ m_logToFile->setEnabled( enable );
+ m_logToFile->setChecked( checked );
+ m_logfilePath->setEnabled( checked );
+
+
+ // execute program settings
+ m_executePath->setURL( event.commandline );
+ enable = (event.dontShow & KNotifyClient::Execute) == 0;
+ checked = enable && !event.commandline.isEmpty() &&
+ (event.presentation & KNotifyClient::Execute);
+ m_execute->setEnabled( enable );
+ m_execute->setChecked( checked );
+ m_executePath->setEnabled( checked );
+
+
+ // other settings
+ m_messageBox->setChecked(event.presentation & (KNotifyClient::Messagebox | KNotifyClient::PassivePopup));
+ enable = (event.dontShow & KNotifyClient::Messagebox) == 0;
+ m_messageBox->setEnabled( enable );
+
+ m_passivePopup->setChecked(event.presentation & KNotifyClient::PassivePopup);
+ enable = (event.dontShow & KNotifyClient::PassivePopup) == 0;
+ m_passivePopup->setEnabled( enable );
+
+ m_stderr->setChecked( event.presentation & KNotifyClient::Stderr );
+ enable = (event.dontShow & KNotifyClient::Stderr) == 0;
+ m_stderr->setEnabled( enable );
+
+ m_taskbar->setChecked(event.presentation & KNotifyClient::Taskbar);
+ enable = (event.dontShow & KNotifyClient::Taskbar) == 0;
+ m_taskbar->setEnabled( enable );
+
+ updatePixmaps( item );
+
+ blockSignals( false );
+}
+
+void KNotifyWidget::updatePixmaps( ListViewItem *item )
+{
+ QPixmap emptyPix;
+ Event &event = item->event();
+
+ bool doIt = (event.presentation & KNotifyClient::Execute) &&
+ !event.commandline.isEmpty();
+ item->setPixmap( COL_EXECUTE, doIt ? d->pixmaps[COL_EXECUTE] : emptyPix );
+
+ doIt = (event.presentation & KNotifyClient::Sound) &&
+ !event.soundfile.isEmpty();
+ item->setPixmap( COL_SOUND, doIt ? d->pixmaps[COL_SOUND] : emptyPix );
+
+ doIt = (event.presentation & KNotifyClient::Logfile) &&
+ !event.logfile.isEmpty();
+ item->setPixmap( COL_LOGFILE, doIt ? d->pixmaps[COL_LOGFILE] : emptyPix );
+
+ item->setPixmap( COL_MESSAGE,
+ (event.presentation &
+ (KNotifyClient::Messagebox | KNotifyClient::PassivePopup)) ?
+ d->pixmaps[COL_MESSAGE] : emptyPix );
+
+ item->setPixmap( COL_STDERR,
+ (event.presentation & KNotifyClient::Stderr) ?
+ d->pixmaps[COL_STDERR] : emptyPix );
+ item->setPixmap( COL_TASKBAR,
+ (event.presentation & KNotifyClient::Taskbar) ?
+ d->pixmaps[COL_TASKBAR] : emptyPix );
+}
+
+void KNotifyWidget::addVisibleApp( Application *app )
+{
+ if ( !app || (m_visibleApps.findRef( app ) != -1) )
+ return;
+
+ m_visibleApps.append( app );
+ addToView( app->eventList() );
+
+ QListViewItem *item = m_listview->selectedItem();
+ if ( !item )
+ item = m_listview->firstChild();
+
+ selectItem( item );
+}
+
+void KNotifyWidget::addToView( const EventList& events )
+{
+ ListViewItem *item = 0L;
+
+ EventListIterator it( events );
+
+ for ( ; it.current(); ++it )
+ {
+ Event *event = it.current();
+ item = new ListViewItem( m_listview, event );
+
+ if ( (event->presentation & KNotifyClient::Execute) &&
+ !event->commandline.isEmpty() )
+ item->setPixmap( COL_EXECUTE, d->pixmaps[COL_EXECUTE] );
+ if ( (event->presentation & KNotifyClient::Sound) &&
+ !event->soundfile.isEmpty() )
+ item->setPixmap( COL_SOUND, d->pixmaps[COL_SOUND] );
+ if ( (event->presentation & KNotifyClient::Logfile) &&
+ !event->logfile.isEmpty() )
+ item->setPixmap( COL_LOGFILE, d->pixmaps[COL_LOGFILE] );
+ if ( event->presentation & (KNotifyClient::Messagebox|KNotifyClient::PassivePopup) )
+ item->setPixmap( COL_MESSAGE, d->pixmaps[COL_MESSAGE] );
+ if ( event->presentation & KNotifyClient::Stderr )
+ item->setPixmap( COL_STDERR, d->pixmaps[COL_STDERR] );
+ if ( event->presentation & KNotifyClient::Taskbar )
+ item->setPixmap( COL_TASKBAR, d->pixmaps[COL_TASKBAR] );
+ }
+}
+
+void KNotifyWidget::widgetChanged( QListViewItem *item,
+ int what, bool on, QWidget *buddy )
+{
+ if ( signalsBlocked() )
+ return;
+
+ if ( buddy )
+ buddy->setEnabled( on );
+
+ Event &e = static_cast<ListViewItem*>( item )->event();
+ if ( on )
+ {
+ e.presentation |= what;
+ if ( buddy )
+ buddy->setFocus();
+ }
+ else
+ e.presentation &= ~what;
+
+ emit changed( true );
+}
+
+void KNotifyWidget::soundToggled( bool on )
+{
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ bool doIcon = on && !m_soundPath->url().isEmpty();
+ item->setPixmap( COL_SOUND, doIcon ? d->pixmaps[COL_SOUND] : QPixmap() );
+ widgetChanged( item, KNotifyClient::Sound, on, m_soundPath );
+}
+
+void KNotifyWidget::loggingToggled( bool on )
+{
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ bool doIcon = on && !m_logfilePath->url().isEmpty();
+ item->setPixmap(COL_LOGFILE, doIcon ? d->pixmaps[COL_LOGFILE] : QPixmap());
+ widgetChanged( item, KNotifyClient::Logfile, on, m_logfilePath );
+}
+
+void KNotifyWidget::executeToggled( bool on )
+{
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ bool doIcon = on && !m_executePath->url().isEmpty();
+ item->setPixmap(COL_EXECUTE, doIcon ? d->pixmaps[COL_EXECUTE] : QPixmap());
+ widgetChanged( item, KNotifyClient::Execute, on, m_executePath );
+}
+
+void KNotifyWidget::messageBoxChanged()
+{
+ if ( signalsBlocked() )
+ return;
+
+ m_passivePopup->setEnabled( m_messageBox->isChecked() );
+
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+
+ bool on = m_passivePopup->isEnabled();
+ item->setPixmap( COL_MESSAGE, on ? d->pixmaps[COL_MESSAGE] : QPixmap() );
+
+ Event &e = static_cast<ListViewItem*>( item )->event();
+
+ if ( m_messageBox->isChecked() ) {
+ if ( m_passivePopup->isChecked() ) {
+ e.presentation |= KNotifyClient::PassivePopup;
+ e.presentation &= ~KNotifyClient::Messagebox;
+ }
+ else {
+ e.presentation &= ~KNotifyClient::PassivePopup;
+ e.presentation |= KNotifyClient::Messagebox;
+ }
+ }
+ else {
+ e.presentation &= ~KNotifyClient::Messagebox;
+ e.presentation &= ~KNotifyClient::PassivePopup;
+ }
+
+ emit changed( true );
+}
+
+void KNotifyWidget::stderrToggled( bool on )
+{
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ item->setPixmap( COL_STDERR, on ? d->pixmaps[COL_STDERR] : QPixmap() );
+ widgetChanged( item, KNotifyClient::Stderr, on );
+}
+
+void KNotifyWidget::taskbarToggled( bool on )
+{
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ item->setPixmap( COL_TASKBAR, on ? d->pixmaps[COL_TASKBAR] : QPixmap() );
+ widgetChanged( item, KNotifyClient::Taskbar, on );
+}
+
+void KNotifyWidget::soundFileChanged( const QString& text )
+{
+ if ( signalsBlocked() )
+ return;
+
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+
+ m_playButton->setEnabled( !text.isEmpty() );
+
+ currentEvent()->soundfile = text;
+ bool ok = !text.isEmpty() && m_playSound->isChecked();
+ item->setPixmap( COL_SOUND, ok ? d->pixmaps[COL_SOUND] : QPixmap() );
+
+ emit changed( true );
+}
+
+void KNotifyWidget::logfileChanged( const QString& text )
+{
+ if ( signalsBlocked() )
+ return;
+
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+
+ currentEvent()->logfile = text;
+ bool ok = !text.isEmpty() && m_logToFile->isChecked();
+ item->setPixmap( COL_LOGFILE, ok ? d->pixmaps[COL_LOGFILE] : QPixmap() );
+
+ emit changed( true );
+}
+
+void KNotifyWidget::commandlineChanged( const QString& text )
+{
+ if ( signalsBlocked() )
+ return;
+
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+
+ currentEvent()->commandline = text;
+ bool ok = !text.isEmpty() && m_execute->isChecked();
+ item->setPixmap( COL_EXECUTE, ok ? d->pixmaps[COL_EXECUTE] : QPixmap() );
+
+ emit changed( true );
+}
+
+void KNotifyWidget::slotItemClicked( QListViewItem *item, const QPoint&,
+ int col )
+{
+ if ( !item || !item->isSelected() )
+ return;
+
+ Event *event = currentEvent();
+ if ( !event )
+ return; // very unlikely, but safety first
+
+ bool doShowAdvanced = false;
+
+ switch( col )
+ {
+ case COL_EXECUTE:
+ m_execute->toggle();
+ m_executePath->setFocus();
+ doShowAdvanced = true;
+ break;
+ case COL_STDERR:
+ m_stderr->toggle();
+ break;
+ case COL_TASKBAR:
+ m_taskbar->toggle();
+ break;
+ case COL_MESSAGE:
+ m_passivePopup->setChecked( true ); // default to passive popups
+ m_messageBox->toggle();
+ break;
+ case COL_LOGFILE:
+ m_logToFile->toggle();
+ m_logfilePath->setFocus();
+ doShowAdvanced = true;
+ break;
+ case COL_SOUND:
+ m_playSound->toggle();
+ break;
+ default: // do nothing
+ break;
+ }
+
+ if ( doShowAdvanced && !m_logToFile->isVisible() )
+ {
+ showAdvanced( true );
+ m_listview->ensureItemVisible( m_listview->currentItem() );
+ }
+}
+
+void KNotifyWidget::sort( bool ascending )
+{
+ m_listview->setSorting( COL_EVENT, ascending );
+ m_listview->sort();
+}
+
+void KNotifyWidget::selectItem( QListViewItem *item )
+{
+ if ( item )
+ {
+ m_listview->setCurrentItem( item );
+ item->setSelected( true );
+ slotEventChanged( item );
+ }
+}
+
+void KNotifyWidget::resetDefaults( bool ask )
+{
+ if ( ask )
+ {
+ if ( KMessageBox::warningContinueCancel(this,
+ i18n("This will cause the notifications "
+ "to be reset to their defaults."),
+ i18n("Are You Sure?"),
+ i18n("&Reset"))
+ != KMessageBox::Continue)
+ return;
+ }
+
+ reload( true ); // defaults
+ emit changed( true );
+}
+
+void KNotifyWidget::reload( bool revertToDefaults )
+{
+ m_listview->clear();
+ ApplicationListIterator it( m_visibleApps );
+ for ( ; it.current(); ++it )
+ {
+ it.current()->reloadEvents( revertToDefaults );
+ addToView( it.current()->eventList() );
+ }
+
+ m_listview->sort();
+ selectItem( m_listview->firstChild() );
+}
+
+void KNotifyWidget::save()
+{
+ kdDebug() << "save\n";
+
+ ApplicationListIterator it( m_allApps );
+ while ( it.current() )
+ {
+ (*it)->save();
+ ++it;
+ }
+
+ if ( kapp )
+ {
+ if ( !kapp->dcopClient()->isAttached() )
+ kapp->dcopClient()->attach();
+ kapp->dcopClient()->send("knotify", "", "reconfigure()", "");
+ }
+
+ emit changed( false );
+}
+
+// returns e.g. "kwin/eventsrc" from a given path
+// "/opt/kde3/share/apps/kwin/eventsrc"
+QString KNotifyWidget::makeRelative( const QString& fullPath )
+{
+ int slash = fullPath.findRev( '/' ) - 1;
+ slash = fullPath.findRev( '/', slash );
+
+ if ( slash < 0 )
+ return QString::null;
+
+ return fullPath.mid( slash+1 );
+}
+
+Event * KNotifyWidget::currentEvent()
+{
+ QListViewItem *current = m_listview->currentItem();
+ if ( !current )
+ return 0L;
+
+ return &static_cast<ListViewItem*>( current )->event();
+}
+
+void KNotifyWidget::openSoundDialog( KURLRequester *requester )
+{
+ // only need to init this once
+ requester->disconnect( SIGNAL( openFileDialog( KURLRequester * )),
+ this, SLOT( openSoundDialog( KURLRequester * )));
+
+ KFileDialog *fileDialog = requester->fileDialog();
+ fileDialog->setCaption( i18n("Select Sound File") );
+ QStringList filters;
+ filters << "audio/x-wav" << "audio/x-mp3" << "application/ogg"
+ << "audio/x-adpcm";
+ fileDialog->setMimeFilter( filters );
+
+ // find the first "sound"-resource that contains files
+ const Application *app = currentEvent()->application();
+ QStringList soundDirs =
+ KGlobal::dirs()->findDirs("data", app->appName() + "/sounds");
+ soundDirs += KGlobal::dirs()->resourceDirs( "sound" );
+
+ if ( !soundDirs.isEmpty() ) {
+ KURL soundURL;
+ QDir dir;
+ dir.setFilter( QDir::Files | QDir::Readable );
+ QStringList::ConstIterator it = soundDirs.begin();
+ while ( it != soundDirs.end() ) {
+ dir = *it;
+ if ( dir.isReadable() && dir.count() > 2 ) {
+ soundURL.setPath( *it );
+ fileDialog->setURL( soundURL );
+ break;
+ }
+ ++it;
+ }
+ }
+}
+
+void KNotifyWidget::openLogDialog( KURLRequester *requester )
+{
+ // only need to init this once
+ requester->disconnect( SIGNAL( openFileDialog( KURLRequester * )),
+ this, SLOT( openLogDialog( KURLRequester * )));
+
+ KFileDialog *fileDialog = requester->fileDialog();
+ fileDialog->setCaption( i18n("Select Log File") );
+ QStringList filters;
+ filters << "text/x-log" << "text/plain";
+ fileDialog->setMimeFilter( filters );
+}
+
+void KNotifyWidget::openExecDialog( KURLRequester *requester )
+{
+ // only need to init this once
+ requester->disconnect( SIGNAL( openFileDialog( KURLRequester * )),
+ this, SLOT( openExecDialog( KURLRequester * )));
+
+
+ KFileDialog *fileDialog = requester->fileDialog();
+ fileDialog->setCaption( i18n("Select File to Execute") );
+ QStringList filters;
+ filters << "application/x-executable" << "application/x-shellscript"
+ << "application/x-perl" << "application/x-python";
+ fileDialog->setMimeFilter( filters );
+}
+
+void KNotifyWidget::playSound()
+{
+ QString soundPath = m_soundPath->url();
+ if (!KIO::NetAccess::exists( m_soundPath->url(), true, 0 )) {
+ bool foundSound=false;
+
+ // find the first "sound"-resource that contains files
+ const Application *app = currentEvent()->application();
+ QStringList soundDirs = KGlobal::dirs()->findDirs("data", app->appName() + "/sounds");
+ soundDirs += KGlobal::dirs()->resourceDirs( "sound" );
+
+ if ( !soundDirs.isEmpty() ) {
+ QDir dir;
+ dir.setFilter( QDir::Files | QDir::Readable );
+ QStringList::ConstIterator it = soundDirs.begin();
+ while ( it != soundDirs.end() ) {
+ dir = *it;
+ if ( dir.isReadable() && dir.count() > 2 &&
+ KIO::NetAccess::exists( *it + m_soundPath->url(), true, 0 )) {
+ foundSound=true;
+ soundPath = *it + m_soundPath->url();
+ break;
+ }
+ ++it;
+ }
+ }
+ if ( !foundSound ) {
+ KMessageBox::sorry(this, i18n("The specified file does not exist." ));
+ return;
+ }
+ }
+ KAudioPlayer::play( soundPath );
+}
+
+void KNotifyWidget::enableAll()
+{
+ bool enable = (sender() == m_buttonEnable);
+ enableAll( SelectionCombo::type(enable ? m_comboEnable : m_comboDisable),
+ enable );
+}
+
+void KNotifyWidget::enableAll( int what, bool enable )
+{
+ if ( m_listview->childCount() == 0 )
+ return;
+
+ bool affectAll = m_affectAllApps->isChecked(); // multi-apps mode
+
+ ApplicationListIterator appIt( affectAll ? m_allApps : m_visibleApps );
+ for ( ; appIt.current(); ++appIt )
+ {
+ const EventList& events = appIt.current()->eventList();
+ EventListIterator it( events );
+ for ( ; it.current(); ++it )
+ {
+ if ( enable )
+ it.current()->presentation |= what;
+ else
+ it.current()->presentation &= ~what;
+ }
+ }
+
+ // now make the listview reflect the changes
+ QListViewItemIterator it( m_listview->firstChild() );
+ for ( ; it.current(); ++it )
+ {
+ ListViewItem *item = static_cast<ListViewItem*>( it.current() );
+ updatePixmaps( item );
+ }
+
+ QListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ item = m_listview->firstChild();
+ selectItem( item );
+
+ emit changed( true );
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+
+//
+// path must be "appname/eventsrc", i.e. a relative path
+//
+Application::Application( const QString &path )
+{
+ QString config_file = path;
+ config_file[config_file.find('/')] = '.';
+ m_events = 0L;
+ config = new KConfig(config_file, false, false);
+ kc = new KConfig(path, true, false, "data");
+ kc->setGroup( QString::fromLatin1("!Global!") );
+ m_icon = kc->readEntry(QString::fromLatin1("IconName"),
+ QString::fromLatin1("misc"));
+ m_description = kc->readEntry( QString::fromLatin1("Comment"),
+ i18n("No description available") );
+
+ int index = path.find( '/' );
+ if ( index >= 0 )
+ m_appname = path.left( index );
+ else
+ kdDebug() << "Cannot determine application name from path: " << path << endl;
+}
+
+Application::~Application()
+{
+ delete config;
+ delete kc;
+ delete m_events;
+}
+
+
+const EventList& Application::eventList()
+{
+ if ( !m_events ) {
+ m_events = new EventList;
+ m_events->setAutoDelete( true );
+ reloadEvents();
+ }
+
+ return *m_events;
+}
+
+
+void Application::save()
+{
+ if ( !m_events )
+ return;
+
+ EventListIterator it( *m_events );
+ Event *e;
+ while ( (e = it.current()) ) {
+ config->setGroup( e->configGroup );
+ config->writeEntry( "presentation", e->presentation );
+ config->writePathEntry( "soundfile", e->soundfile );
+ config->writePathEntry( "logfile", e->logfile );
+ config->writePathEntry( "commandline", e->commandline );
+
+ ++it;
+ }
+ config->sync();
+}
+
+
+void Application::reloadEvents( bool revertToDefaults )
+{
+ if ( m_events )
+ m_events->clear();
+ else
+ {
+ m_events = new EventList;
+ m_events->setAutoDelete( true );
+ }
+
+ Event *e = 0L;
+
+ QString global = QString::fromLatin1("!Global!");
+ QString default_group = QString::fromLatin1("<default>");
+ QString name = QString::fromLatin1("Name");
+ QString comment = QString::fromLatin1("Comment");
+
+ QStringList conflist = kc->groupList();
+ QStringList::ConstIterator it = conflist.begin();
+
+ while ( it != conflist.end() ) {
+ if ( (*it) != global && (*it) != default_group ) { // event group
+ kc->setGroup( *it );
+
+ e = new Event( this );
+ e->name = kc->readEntry( name );
+ e->description = kc->readEntry( comment );
+ e->dontShow = kc->readNumEntry("nopresentation", 0 );
+ e->configGroup = *it;
+ if ( e->name.isEmpty() && e->description.isEmpty() )
+ delete e;
+ else { // load the event
+ if( !e->name.isEmpty() && e->description.isEmpty() )
+ e->description = e->name;
+ // default to passive popups over plain messageboxes
+ int default_rep = kc->readNumEntry("default_presentation",
+ 0 | KNotifyClient::PassivePopup);
+ QString default_logfile = kc->readPathEntry("default_logfile");
+ QString default_soundfile = kc->readPathEntry("default_sound");
+ QString default_commandline = kc->readPathEntry("default_commandline");
+
+ config->setGroup(*it);
+
+ if ( revertToDefaults )
+ {
+ e->presentation = default_rep;
+ e->logfile = default_logfile;
+ e->soundfile = default_soundfile;
+ e->commandline = default_commandline;
+ }
+
+ else
+ {
+ e->presentation = config->readNumEntry("presentation",
+ default_rep);
+ e->logfile = config->readPathEntry("logfile",
+ default_logfile);
+ e->soundfile = config->readPathEntry("soundfile",
+ default_soundfile);
+ e->commandline = config->readPathEntry("commandline",
+ default_commandline);
+ }
+
+ m_events->append( e );
+ }
+ }
+
+ ++it;
+ }
+
+ return;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+ListViewItem::ListViewItem( QListView *view, Event *event )
+ : QListViewItem( view ),
+ m_event( event )
+{
+ setText( COL_EVENT, event->text() );
+}
+
+int ListViewItem::compare ( QListViewItem * i, int col, bool ascending ) const
+{
+ ListViewItem *item = static_cast<ListViewItem*>( i );
+ int myPres = m_event->presentation;
+ int otherPres = item->event().presentation;
+
+ int action = 0;
+
+ switch ( col )
+ {
+ case COL_EVENT: // use default sorting
+ return QListViewItem::compare( i, col, ascending );
+
+ case COL_EXECUTE:
+ action = KNotifyClient::Execute;
+ break;
+ case COL_LOGFILE:
+ action = KNotifyClient::Logfile;
+ break;
+ case COL_MESSAGE:
+ action = (KNotifyClient::Messagebox | KNotifyClient::PassivePopup);
+ break;
+ case COL_SOUND:
+ action = KNotifyClient::Sound;
+ break;
+ case COL_STDERR:
+ action = KNotifyClient::Stderr;
+ break;
+ case COL_TASKBAR:
+ action = KNotifyClient::Taskbar;
+ break;
+ }
+
+ if ( (myPres & action) == (otherPres & action) )
+ {
+ // default sorting by event
+ return QListViewItem::compare( i, COL_EVENT, true );
+ }
+
+ if ( myPres & action )
+ return -1;
+ if ( otherPres & action )
+ return 1;
+
+ return 0;
+}
+
+#include "knotifydialog.moc"
diff --git a/kio/kfile/knotifydialog.h b/kio/kfile/knotifydialog.h
new file mode 100644
index 000000000..3d4074fd0
--- /dev/null
+++ b/kio/kfile/knotifydialog.h
@@ -0,0 +1,341 @@
+/*
+ Copyright (C) 2000,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ Copyright (C) 2002 Neil Stevens <neil@qualityassistant.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation;
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library, If not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KNOTIFYDIALOG_H
+#define KNOTIFYDIALOG_H
+
+#include <klistview.h>
+#include <kdialogbase.h>
+#include <kinstance.h>
+#include <kglobal.h>
+
+#include "knotifywidgetbase.h"
+
+class QShowEvent;
+
+namespace KNotify
+{
+ class KNotifyWidget;
+}
+
+/**
+ * KNotifyDialog presents an interface for configuring an application's
+ * KNotify events.
+ *
+ * Rather than requiring the user to wade through the entire list of
+ * applications' events in KControl, your application can make the list
+ * of its own notifications available here.
+ *
+ * Typical usage is calling the static configure() method:
+ * \code
+ * (void) KNotifyDialog::configure( someParentWidget );
+ * \endcode
+ *
+ * @since 3.1
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class KIO_EXPORT KNotifyDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * If you want a non-modal dialog, you need to instantiate KNotifyDialog
+ * yourself instead of using the configure() method.
+ *
+ * KDE4.0 modal default will be false.
+ *
+ * @param parent The parent widget for the dialog
+ * @param name The widget name
+ * @param modal If true, this will be a modal dialog, otherwise non-modal.
+ * @param aboutData A pointer to a KAboutData object. KAboutData::appName()
+ * will be used to find the KNotify events (in the eventsrc file).
+ * Set this to 0L if you want to add all events yourself with
+ * addApplicationEvents().
+ */
+ KNotifyDialog( QWidget *parent = 0, const char *name = 0,
+ bool modal = true,
+ const KAboutData *aboutData =
+ KGlobal::instance()->aboutData() );
+ /**
+ * Destroys the KNotifyDialog
+ */
+ virtual ~KNotifyDialog();
+
+ /**
+ * Convenience method to create exec() a modal KNotifyDialog.
+ *
+ * @param parent The parent widget for the dialog
+ * @param name The widget name
+ * @param aboutData A pointer to a KAboutData object. KAboutData::appName()
+ * will be used to find the KNotify events (in the eventsrc file).
+ * @see exec for the return values.
+ * @return The value of QDialog::exec()
+ */
+ static int configure( QWidget *parent = 0, const char *name = 0,
+ const KAboutData *aboutData = KGlobal::instance()->aboutData() );
+
+ /**
+ * With this method, you can add the KNotify events of one eventsrc
+ * files to the view.
+ * KNotifyDialog can handle events for multiple applications (i.e. eventsrc files).
+ * Successive calls with a different @p appName will add them.
+ * @param appName The application's name, i.e. the name passed to the
+ * KApplication constructor or KAboutData.
+ * @see clearApplicationEvents()
+ */
+ virtual void addApplicationEvents( const char *appName );
+
+ /**
+ * With this method, you can add the KNotify events of one eventsrc
+ * files to the view.
+ * KNotifyDialog can handle events for multiple applications (i.e. eventsrc files).
+ * Successive calls with a different @p path will add them.
+ * @param path The absolute or relative path to the eventsrc file to be configured.
+ * A relative path would be e.g. "kwin/eventsrc".
+ * @see clearApplicationEvents()
+ */
+ virtual void addApplicationEvents( const QString& path );
+
+ /**
+ * Removes all the events added with addApplicationEvents()
+ * @see addApplicationEvents()
+ */
+ virtual void clearApplicationEvents();
+
+private slots:
+ void slotDefault();
+
+private:
+ enum
+ {
+ COL_FILENAME = 1
+ };
+
+ void updateView();
+
+ KNotify::KNotifyWidget * m_notifyWidget;
+
+ class Private;
+ Private *d;
+};
+
+
+namespace KNotify
+{
+ class Application;
+ class Event;
+ class ListViewItem;
+ typedef QPtrList<Event> EventList;
+ typedef QPtrListIterator<Application> ApplicationListIterator;
+ typedef QPtrListIterator<Event> EventListIterator;
+
+ /**
+ * @internal
+ */
+ class KIO_EXPORT Application
+ {
+ public:
+ Application( const QString &path );
+ ~Application();
+
+ QString text() const { return m_description; }
+ QString icon() const { return m_icon; }
+ const EventList& eventList();
+ void reloadEvents( bool revertToDefaults = false );
+ void save();
+
+ QString appName() const { return m_appname; }
+
+ private:
+ QString m_icon;
+ QString m_description;
+ QString m_appname;
+ EventList *m_events;
+
+ KConfig *kc; // The file that defines the events.
+ KConfig *config; // The file that contains the settings for the events
+ };
+
+
+ class KIO_EXPORT ApplicationList : public QPtrList<Application>
+ {
+ virtual int compareItems ( QPtrCollection::Item item1,
+ QPtrCollection::Item item2 )
+ {
+ return (static_cast<Application*>( item1 )->text() >=
+ static_cast<Application*>( item2 )->text()) ? 1 : -1;
+ }
+ };
+
+ /**
+ * @internal
+ */
+ class KIO_EXPORT KNotifyWidget : public KNotifyWidgetBase
+ {
+ Q_OBJECT
+
+ public:
+ KNotifyWidget( QWidget* parent = 0, const char* name = 0,
+ bool handleAllApps = false );
+ ~KNotifyWidget();
+
+ KListView * eventsView() {
+ return m_listview;
+ }
+
+ void addVisibleApp( Application *app );
+ ApplicationList& visibleApps() { return m_visibleApps; }
+ ApplicationList& allApps() { return m_allApps; }
+
+ /**
+ * Returns 0L if no application events could be found
+ * The returned pointer must be freed by the caller (easiest done
+ * by putting it into an ApplicationList with setAutoDelete( true )).
+ */
+ Application * addApplicationEvents( const QString& path );
+
+ void resetDefaults( bool ask );
+ void sort( bool ascending = true );
+
+ public slots:
+ /**
+ * Clears the view and all the Application events.
+ */
+ virtual void clear();
+ /**
+ * Clears only the view and the visible Application events.
+ * E.g. useful if you want to set new visible events with
+ * addVisibleApp()
+ */
+ virtual void clearVisible();
+ virtual void save();
+ virtual void showAdvanced( bool show );
+ void toggleAdvanced();
+
+
+ signals:
+ void changed( bool hasChanges );
+
+ protected:
+ /**
+ * May return 0L, if there is no current event selected.
+ */
+ Event * currentEvent();
+ virtual void showEvent( QShowEvent * );
+ virtual void enableAll( int what, bool enable );
+
+ void reload( bool revertToDefaults = false );
+
+ protected slots:
+ void playSound();
+
+ private slots:
+ void slotItemClicked( QListViewItem *item, const QPoint& point,
+ int col );
+ void slotEventChanged( QListViewItem * );
+ void soundToggled( bool on );
+ void loggingToggled( bool on );
+ void executeToggled( bool on );
+ void messageBoxChanged();
+ void stderrToggled( bool on );
+ void taskbarToggled( bool on );
+
+ void soundFileChanged( const QString& text );
+ void logfileChanged( const QString& text );
+ void commandlineChanged( const QString& text );
+
+ void openSoundDialog( KURLRequester * );
+ void openLogDialog( KURLRequester * );
+ void openExecDialog( KURLRequester * );
+
+ void enableAll();
+
+ private:
+ void updateWidgets( ListViewItem *item );
+ void updatePixmaps( ListViewItem *item );
+
+ static QString makeRelative( const QString& );
+ void addToView( const EventList& events );
+ void widgetChanged( QListViewItem *item,
+ int what, bool on, QWidget *buddy = 0L );
+ void selectItem( QListViewItem *item );
+
+ ApplicationList m_visibleApps;
+ ApplicationList m_allApps;
+
+ class Private;
+ Private *d;
+
+ };
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+ /**
+ * @internal
+ */
+ class Event
+ {
+ friend class Application;
+
+ public:
+ QString text() const { return description; }
+
+ int presentation;
+ int dontShow;
+ QString logfile;
+ QString soundfile;
+ QString commandline;
+
+ const Application *application() const { return m_app; }
+
+ private:
+ Event( const Application *app ) {
+ presentation = 0;
+ dontShow = 0;
+ m_app = app;
+ }
+ QString name;
+ QString description;
+ QString configGroup;
+
+ const Application *m_app;
+ };
+
+ /**
+ * @internal
+ */
+ class ListViewItem : public QListViewItem
+ {
+ public:
+ ListViewItem( QListView *view, Event *event );
+
+ Event& event() { return *m_event; }
+ virtual int compare (QListViewItem * i, int col, bool ascending) const;
+
+ private:
+ Event * m_event;
+ };
+
+}
+
+
+#endif
diff --git a/kio/kfile/knotifywidgetbase.ui b/kio/kfile/knotifywidgetbase.ui
new file mode 100644
index 000000000..99fd07582
--- /dev/null
+++ b/kio/kfile/knotifywidgetbase.ui
@@ -0,0 +1,469 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KNotifyWidgetBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KNotifyWidgetBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>487</width>
+ <height>531</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Events</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_listview</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_controlsBox</cstring>
+ </property>
+ <property name="title">
+ <string>Quick Controls</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>m_affectAllApps</cstring>
+ </property>
+ <property name="text">
+ <string>Apply to &amp;all applications</string>
+ </property>
+ </widget>
+ <spacer row="1" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>Spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="2" column="3">
+ <property name="name">
+ <cstring>Spacer17</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>318</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="2" column="1">
+ <property name="name">
+ <cstring>m_buttonDisable</cstring>
+ </property>
+ <property name="text">
+ <string>Turn O&amp;ff All</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Allows you to change the behavior for all events at once</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>m_buttonEnable</cstring>
+ </property>
+ <property name="text">
+ <string>Turn O&amp;n All</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Allows you to change the behavior for all events at once</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="2">
+ <property name="name">
+ <cstring>m_comboEnable</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="2">
+ <property name="name">
+ <cstring>m_comboDisable</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_actionsBox</cstring>
+ </property>
+ <property name="title">
+ <string>Actions</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="5" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_stderr</cstring>
+ </property>
+ <property name="text">
+ <string>Print a message to standard &amp;error output</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_messageBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show a &amp;message in a pop-up window</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_execute</cstring>
+ </property>
+ <property name="text">
+ <string>E&amp;xecute a program:</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Layout25</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_playSound</cstring>
+ </property>
+ <property name="text">
+ <string>Play a &amp;sound:</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_playButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Test the Sound</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_taskbar</cstring>
+ </property>
+ <property name="text">
+ <string>Mark &amp;taskbar entry</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_logToFile</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Log to a file:</string>
+ </property>
+ </widget>
+ <spacer row="4" column="0">
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KURLRequester" row="2" column="2">
+ <property name="name">
+ <cstring>m_executePath</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="2">
+ <property name="name">
+ <cstring>m_logfilePath</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="0" column="2">
+ <property name="name">
+ <cstring>m_soundPath</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_passivePopup</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Use a passive window that does not interrupt other work</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_extension</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Less Options</string>
+ </property>
+ <property name="toggleButton">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_playerButton</cstring>
+ </property>
+ <property name="text">
+ <string>Player Settings</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_messageBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_passivePopup</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_execute</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_executePath</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_playSound</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_soundPath</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_logToFile</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_logfilePath</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>m_listview</tabstop>
+ <tabstop>m_playSound</tabstop>
+ <tabstop>m_playButton</tabstop>
+ <tabstop>m_soundPath</tabstop>
+ <tabstop>m_logToFile</tabstop>
+ <tabstop>m_logfilePath</tabstop>
+ <tabstop>m_execute</tabstop>
+ <tabstop>m_executePath</tabstop>
+ <tabstop>m_messageBox</tabstop>
+ <tabstop>m_passivePopup</tabstop>
+ <tabstop>m_stderr</tabstop>
+ <tabstop>m_affectAllApps</tabstop>
+ <tabstop>m_buttonEnable</tabstop>
+ <tabstop>m_comboEnable</tabstop>
+ <tabstop>m_buttonDisable</tabstop>
+ <tabstop>m_comboDisable</tabstop>
+ <tabstop>m_extension</tabstop>
+ <tabstop>m_playerButton</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+ <include location="global" impldecl="in implementation">klistview.h</include>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+ <include location="global" impldecl="in implementation">kcombobox.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/kio/kfile/kopenwith.cpp b/kio/kfile/kopenwith.cpp
new file mode 100644
index 000000000..f1a71341b
--- /dev/null
+++ b/kio/kfile/kopenwith.cpp
@@ -0,0 +1,851 @@
+/* This file is part of the KDE libraries
+
+ Copyright (C) 1997 Torben Weis <weis@stud.uni-frankfurt.de>
+ Copyright (C) 1999 Dirk Mueller <mueller@kde.org>
+ Portions copyright (C) 1999 Preston Brown <pbrown@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qdialog.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qtoolbutton.h>
+#include <qcheckbox.h>
+#include <qtooltip.h>
+#include <qstyle.h>
+#include <qwhatsthis.h>
+
+#include <kapplication.h>
+#include <kbuttonbox.h>
+#include <kcombobox.h>
+#include <kdesktopfile.h>
+#include <kdialog.h>
+#include <kglobal.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmimemagic.h>
+#include <krun.h>
+#include <kstandarddirs.h>
+#include <kstringhandler.h>
+#include <kuserprofile.h>
+#include <kurlcompletion.h>
+#include <kurlrequester.h>
+#include <dcopclient.h>
+#include <kmimetype.h>
+#include <kservicegroup.h>
+#include <klistview.h>
+#include <ksycoca.h>
+#include <kstdguiitem.h>
+
+#include "kopenwith.h"
+#include "kopenwith_p.h"
+
+#include <kdebug.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#define SORT_SPEC (QDir::DirsFirst | QDir::Name | QDir::IgnoreCase)
+
+
+// ----------------------------------------------------------------------
+
+KAppTreeListItem::KAppTreeListItem( KListView* parent, const QString & name,
+ const QPixmap& pixmap, bool parse, bool dir, const QString &p, const QString &c )
+ : QListViewItem( parent, name )
+{
+ init(pixmap, parse, dir, p, c);
+}
+
+
+// ----------------------------------------------------------------------
+
+KAppTreeListItem::KAppTreeListItem( QListViewItem* parent, const QString & name,
+ const QPixmap& pixmap, bool parse, bool dir, const QString &p, const QString &c )
+ : QListViewItem( parent, name )
+{
+ init(pixmap, parse, dir, p, c);
+}
+
+
+// ----------------------------------------------------------------------
+
+void KAppTreeListItem::init(const QPixmap& pixmap, bool parse, bool dir, const QString &_path, const QString &_exec)
+{
+ setPixmap(0, pixmap);
+ parsed = parse;
+ directory = dir;
+ path = _path; // relative path
+ exec = _exec;
+}
+
+
+/* Ensures that directories sort before non-directories */
+int KAppTreeListItem::compare(QListViewItem *i, int col, bool ascending) const
+{
+ KAppTreeListItem *other = dynamic_cast<KAppTreeListItem *>(i);
+
+ // Directories sort first
+ if (directory && !other->directory)
+ return -1;
+
+ else if (!directory && other->directory)
+ return 1;
+
+ else // both directories or both not
+ return QListViewItem::compare(i, col, ascending);
+}
+
+// ----------------------------------------------------------------------
+// Ensure that case is ignored
+QString KAppTreeListItem::key(int column, bool /*ascending*/) const
+{
+ return text(column).upper();
+}
+
+void KAppTreeListItem::activate()
+{
+ if ( directory )
+ setOpen(!isOpen());
+}
+
+void KAppTreeListItem::setOpen( bool o )
+{
+ if( o && !parsed ) { // fill the children before opening
+ ((KApplicationTree *) parent())->addDesktopGroup( path, this );
+ parsed = true;
+ }
+ QListViewItem::setOpen( o );
+}
+
+bool KAppTreeListItem::isDirectory()
+{
+ return directory;
+}
+
+// ----------------------------------------------------------------------
+
+KApplicationTree::KApplicationTree( QWidget *parent )
+ : KListView( parent ), currentitem(0)
+{
+ addColumn( i18n("Known Applications") );
+ setRootIsDecorated( true );
+
+ addDesktopGroup( QString::null );
+ cleanupTree();
+
+ connect( this, SIGNAL( currentChanged(QListViewItem*) ),
+ SLOT( slotItemHighlighted(QListViewItem*) ) );
+ connect( this, SIGNAL( selectionChanged(QListViewItem*) ),
+ SLOT( slotSelectionChanged(QListViewItem*) ) );
+}
+
+// ----------------------------------------------------------------------
+
+bool KApplicationTree::isDirSel()
+{
+ if (!currentitem) return false; // if currentitem isn't set
+ return currentitem->isDirectory();
+}
+
+// ----------------------------------------------------------------------
+
+static QPixmap appIcon(const QString &iconName)
+{
+ QPixmap normal = KGlobal::iconLoader()->loadIcon(iconName, KIcon::Small, 0, KIcon::DefaultState, 0L, true);
+ // make sure they are not larger than 20x20
+ if (normal.width() > 20 || normal.height() > 20)
+ {
+ QImage tmp = normal.convertToImage();
+ tmp = tmp.smoothScale(20, 20);
+ normal.convertFromImage(tmp);
+ }
+ return normal;
+}
+
+void KApplicationTree::addDesktopGroup( const QString &relPath, KAppTreeListItem *item)
+{
+ KServiceGroup::Ptr root = KServiceGroup::group(relPath);
+ if (!root || !root->isValid()) return;
+
+ KServiceGroup::List list = root->entries();
+
+ KAppTreeListItem * newItem;
+ for( KServiceGroup::List::ConstIterator it = list.begin();
+ it != list.end(); it++)
+ {
+ QString icon;
+ QString text;
+ QString relPath;
+ QString exec;
+ bool isDir = false;
+ KSycocaEntry *p = (*it);
+ if (p->isType(KST_KService))
+ {
+ KService *service = static_cast<KService *>(p);
+
+ if (service->noDisplay())
+ continue;
+
+ icon = service->icon();
+ text = service->name();
+ exec = service->exec();
+ }
+ else if (p->isType(KST_KServiceGroup))
+ {
+ KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
+
+ if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0)
+ continue;
+
+ icon = serviceGroup->icon();
+ text = serviceGroup->caption();
+ relPath = serviceGroup->relPath();
+ isDir = true;
+ }
+ else
+ {
+ kdWarning(250) << "KServiceGroup: Unexpected object in list!" << endl;
+ continue;
+ }
+
+ QPixmap pixmap = appIcon( icon );
+
+ if (item)
+ newItem = new KAppTreeListItem( item, text, pixmap, false, isDir,
+ relPath, exec );
+ else
+ newItem = new KAppTreeListItem( this, text, pixmap, false, isDir,
+ relPath, exec );
+ if (isDir)
+ newItem->setExpandable( true );
+ }
+}
+
+
+// ----------------------------------------------------------------------
+
+void KApplicationTree::slotItemHighlighted(QListViewItem* i)
+{
+ // i may be 0 (see documentation)
+ if(!i)
+ return;
+
+ KAppTreeListItem *item = (KAppTreeListItem *) i;
+
+ currentitem = item;
+
+ if( (!item->directory ) && (!item->exec.isEmpty()) )
+ emit highlighted( item->text(0), item->exec );
+}
+
+
+// ----------------------------------------------------------------------
+
+void KApplicationTree::slotSelectionChanged(QListViewItem* i)
+{
+ // i may be 0 (see documentation)
+ if(!i)
+ return;
+
+ KAppTreeListItem *item = (KAppTreeListItem *) i;
+
+ currentitem = item;
+
+ if( ( !item->directory ) && (!item->exec.isEmpty() ) )
+ emit selected( item->text(0), item->exec );
+}
+
+// ----------------------------------------------------------------------
+
+void KApplicationTree::resizeEvent( QResizeEvent * e)
+{
+ setColumnWidth(0, width()-QApplication::style().pixelMetric(QStyle::PM_ScrollBarExtent)
+ -2*QApplication::style().pixelMetric(QStyle::PM_DefaultFrameWidth));
+ KListView::resizeEvent(e);
+}
+
+// Prune empty directories from the tree
+void KApplicationTree::cleanupTree()
+{
+ QListViewItem *item=firstChild();
+ while(item!=0)
+ {
+ if(item->isExpandable())
+ {
+ QListViewItem *temp=item->itemBelow();
+ if(item->text(0)!=i18n("Applications"))
+ item->setOpen(false);
+ item=temp;
+ continue;
+ }
+ item=item->itemBelow();
+ }
+}
+
+/***************************************************************
+ *
+ * KOpenWithDlg
+ *
+ ***************************************************************/
+class KOpenWithDlgPrivate
+{
+public:
+ KOpenWithDlgPrivate() : saveNewApps(false) { };
+ QPushButton* ok;
+ bool saveNewApps;
+ KService::Ptr curService;
+};
+
+KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, QWidget* parent )
+ :QDialog( parent, "openwith", true )
+{
+ setCaption( i18n( "Open With" ) );
+ QString text;
+ if( _urls.count() == 1 )
+ {
+ text = i18n("<qt>Select the program that should be used to open <b>%1</b>. "
+ "If the program is not listed, enter the name or click "
+ "the browse button.</qt>").arg( _urls.first().fileName() );
+ }
+ else
+ // Should never happen ??
+ text = i18n( "Choose the name of the program with which to open the selected files." );
+ setServiceType( _urls );
+ init( text, QString() );
+}
+
+KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, const QString&_text,
+ const QString& _value, QWidget *parent)
+ :QDialog( parent, "openwith", true )
+{
+ QString caption = KStringHandler::csqueeze( _urls.first().prettyURL() );
+ if (_urls.count() > 1)
+ caption += QString::fromLatin1("...");
+ setCaption(caption);
+ setServiceType( _urls );
+ init( _text, _value );
+}
+
+KOpenWithDlg::KOpenWithDlg( const QString &serviceType, const QString& value,
+ QWidget *parent)
+ :QDialog( parent, "openwith", true )
+{
+ setCaption(i18n("Choose Application for %1").arg(serviceType));
+ QString text = i18n("<qt>Select the program for the file type: <b>%1</b>. "
+ "If the program is not listed, enter the name or click "
+ "the browse button.</qt>").arg(serviceType);
+ qServiceType = serviceType;
+ init( text, value );
+ if (remember)
+ remember->hide();
+}
+
+KOpenWithDlg::KOpenWithDlg( QWidget *parent)
+ :QDialog( parent, "openwith", true )
+{
+ setCaption(i18n("Choose Application"));
+ QString text = i18n("<qt>Select a program. "
+ "If the program is not listed, enter the name or click "
+ "the browse button.</qt>");
+ qServiceType = QString::null;
+ init( text, QString::null );
+}
+
+void KOpenWithDlg::setServiceType( const KURL::List& _urls )
+{
+ if ( _urls.count() == 1 )
+ {
+ qServiceType = KMimeType::findByURL( _urls.first())->name();
+ if (qServiceType == QString::fromLatin1("application/octet-stream"))
+ qServiceType = QString::null;
+ }
+ else
+ qServiceType = QString::null;
+}
+
+void KOpenWithDlg::init( const QString& _text, const QString& _value )
+{
+ d = new KOpenWithDlgPrivate;
+ bool bReadOnly = kapp && !kapp->authorize("shell_access");
+ m_terminaldirty = false;
+ m_pTree = 0L;
+ m_pService = 0L;
+ d->curService = 0L;
+
+ QBoxLayout *topLayout = new QVBoxLayout( this, KDialog::marginHint(),
+ KDialog::spacingHint() );
+ label = new QLabel( _text, this );
+ topLayout->addWidget(label);
+
+ QHBoxLayout* hbox = new QHBoxLayout(topLayout);
+
+ QToolButton *clearButton = new QToolButton( this );
+ clearButton->setIconSet( BarIcon( "locationbar_erase" ) );
+ clearButton->setFixedSize( clearButton->sizeHint() );
+ connect( clearButton, SIGNAL( clicked() ), SLOT( slotClear() ) );
+ QToolTip::add( clearButton, i18n( "Clear input field" ) );
+
+ hbox->addWidget( clearButton );
+
+ if (!bReadOnly)
+ {
+ // init the history combo and insert it into the URL-Requester
+ KHistoryCombo *combo = new KHistoryCombo();
+ combo->setDuplicatesEnabled( false );
+ KConfig *kc = KGlobal::config();
+ KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") );
+ int max = kc->readNumEntry( QString::fromLatin1("Maximum history"), 15 );
+ combo->setMaxCount( max );
+ int mode = kc->readNumEntry(QString::fromLatin1("CompletionMode"),
+ KGlobalSettings::completionMode());
+ combo->setCompletionMode((KGlobalSettings::Completion)mode);
+ QStringList list = kc->readListEntry( QString::fromLatin1("History") );
+ combo->setHistoryItems( list, true );
+ edit = new KURLRequester( combo, this );
+ }
+ else
+ {
+ clearButton->hide();
+ edit = new KURLRequester( this );
+ edit->lineEdit()->setReadOnly(true);
+ edit->button()->hide();
+ }
+
+ edit->setURL( _value );
+ QWhatsThis::add(edit,i18n(
+ "Following the command, you can have several place holders which will be replaced "
+ "with the actual values when the actual program is run:\n"
+ "%f - a single file name\n"
+ "%F - a list of files; use for applications that can open several local files at once\n"
+ "%u - a single URL\n"
+ "%U - a list of URLs\n"
+ "%d - the directory of the file to open\n"
+ "%D - a list of directories\n"
+ "%i - the icon\n"
+ "%m - the mini-icon\n"
+ "%c - the comment"));
+
+ hbox->addWidget(edit);
+
+ if ( edit->comboBox() ) {
+ KURLCompletion *comp = new KURLCompletion( KURLCompletion::ExeCompletion );
+ edit->comboBox()->setCompletionObject( comp );
+ edit->comboBox()->setAutoDeleteCompletionObject( true );
+ }
+
+ connect ( edit, SIGNAL(returnPressed()), SLOT(slotOK()) );
+ connect ( edit, SIGNAL(textChanged(const QString&)), SLOT(slotTextChanged()) );
+
+ m_pTree = new KApplicationTree( this );
+ topLayout->addWidget(m_pTree);
+
+ connect( m_pTree, SIGNAL( selected( const QString&, const QString& ) ),
+ SLOT( slotSelected( const QString&, const QString& ) ) );
+ connect( m_pTree, SIGNAL( highlighted( const QString&, const QString& ) ),
+ SLOT( slotHighlighted( const QString&, const QString& ) ) );
+ connect( m_pTree, SIGNAL( doubleClicked(QListViewItem*) ),
+ SLOT( slotDbClick() ) );
+
+ terminal = new QCheckBox( i18n("Run in &terminal"), this );
+ if (bReadOnly)
+ terminal->hide();
+ connect(terminal, SIGNAL(toggled(bool)), SLOT(slotTerminalToggled(bool)));
+
+ topLayout->addWidget(terminal);
+
+ QBoxLayout* nocloseonexitLayout = new QHBoxLayout( 0, 0, KDialog::spacingHint() );
+ QSpacerItem* spacer = new QSpacerItem( 20, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
+ nocloseonexitLayout->addItem( spacer );
+
+ nocloseonexit = new QCheckBox( i18n("&Do not close when command exits"), this );
+ nocloseonexit->setChecked( false );
+ nocloseonexit->setDisabled( true );
+
+ // check to see if we use konsole if not disable the nocloseonexit
+ // because we don't know how to do this on other terminal applications
+ KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
+ QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
+
+ if (bReadOnly || preferredTerminal != "konsole")
+ nocloseonexit->hide();
+
+ nocloseonexitLayout->addWidget( nocloseonexit );
+ topLayout->addLayout( nocloseonexitLayout );
+
+ if (!qServiceType.isNull())
+ {
+ remember = new QCheckBox(i18n("&Remember application association for this type of file"), this);
+ // remember->setChecked(true);
+ topLayout->addWidget(remember);
+ }
+ else
+ remember = 0L;
+
+ // Use KButtonBox for the aligning pushbuttons nicely
+ KButtonBox* b = new KButtonBox( this );
+ b->addStretch( 2 );
+
+ d->ok = b->addButton( KStdGuiItem::ok() );
+ d->ok->setDefault( true );
+ connect( d->ok, SIGNAL( clicked() ), SLOT( slotOK() ) );
+
+ QPushButton* cancel = b->addButton( KStdGuiItem::cancel() );
+ connect( cancel, SIGNAL( clicked() ), SLOT( reject() ) );
+
+ b->layout();
+ topLayout->addWidget( b );
+
+ //edit->setText( _value );
+ // This is what caused "can't click on items before clicking on Name header".
+ // Probably due to the resizeEvent handler using width().
+ //resize( minimumWidth(), sizeHint().height() );
+ edit->setFocus();
+ slotTextChanged();
+}
+
+
+// ----------------------------------------------------------------------
+
+KOpenWithDlg::~KOpenWithDlg()
+{
+ delete d;
+ d = 0;
+}
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotClear()
+{
+ edit->setURL(QString::null);
+ edit->setFocus();
+}
+
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotSelected( const QString& /*_name*/, const QString& _exec )
+{
+ kdDebug(250)<<"KOpenWithDlg::slotSelected"<<endl;
+ KService::Ptr pService = d->curService;
+ edit->setURL( _exec ); // calls slotTextChanged :(
+ d->curService = pService;
+}
+
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotHighlighted( const QString& _name, const QString& )
+{
+ kdDebug(250)<<"KOpenWithDlg::slotHighlighted"<<endl;
+ qName = _name;
+ d->curService = KService::serviceByName( qName );
+ if (!m_terminaldirty)
+ {
+ // ### indicate that default value was restored
+ terminal->setChecked(d->curService->terminal());
+ QString terminalOptions = d->curService->terminalOptions();
+ nocloseonexit->setChecked( (terminalOptions.contains( "--noclose" ) > 0) );
+ m_terminaldirty = false; // slotTerminalToggled changed it
+ }
+}
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotTextChanged()
+{
+ kdDebug(250)<<"KOpenWithDlg::slotTextChanged"<<endl;
+ // Forget about the service
+ d->curService = 0L;
+ d->ok->setEnabled( !edit->url().isEmpty());
+}
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotTerminalToggled(bool)
+{
+ // ### indicate that default value was overridden
+ m_terminaldirty = true;
+ nocloseonexit->setDisabled( ! terminal->isChecked() );
+}
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotDbClick()
+{
+ if (m_pTree->isDirSel() ) return; // check if a directory is selected
+ slotOK();
+}
+
+void KOpenWithDlg::setSaveNewApplications(bool b)
+{
+ d->saveNewApps = b;
+}
+
+void KOpenWithDlg::slotOK()
+{
+ QString typedExec(edit->url());
+ QString fullExec(typedExec);
+
+ QString serviceName;
+ QString initialServiceName;
+ QString preferredTerminal;
+ m_pService = d->curService;
+ if (!m_pService) {
+ // No service selected - check the command line
+
+ // Find out the name of the service from the command line, removing args and paths
+ serviceName = KRun::binaryName( typedExec, true );
+ if (serviceName.isEmpty())
+ {
+ // TODO add a KMessageBox::error here after the end of the message freeze
+ return;
+ }
+ initialServiceName = serviceName;
+ kdDebug(250) << "initialServiceName=" << initialServiceName << endl;
+ int i = 1; // We have app, app-2, app-3... Looks better for the user.
+ bool ok = false;
+ // Check if there's already a service by that name, with the same Exec line
+ do {
+ kdDebug(250) << "looking for service " << serviceName << endl;
+ KService::Ptr serv = KService::serviceByDesktopName( serviceName );
+ ok = !serv; // ok if no such service yet
+ // also ok if we find the exact same service (well, "kwrite" == "kwrite %U"
+ if ( serv && serv->type() == "Application")
+ {
+ QString exec = serv->exec();
+ fullExec = exec;
+ exec.replace("%u", "", false);
+ exec.replace("%f", "", false);
+ exec.replace("-caption %c", "");
+ exec.replace("-caption \"%c\"", "");
+ exec.replace("%i", "");
+ exec.replace("%m", "");
+ exec = exec.simplifyWhiteSpace();
+ if (exec == typedExec)
+ {
+ ok = true;
+ m_pService = serv;
+ kdDebug(250) << k_funcinfo << "OK, found identical service: " << serv->desktopEntryPath() << endl;
+ }
+ }
+ if (!ok) // service was found, but it was different -> keep looking
+ {
+ ++i;
+ serviceName = initialServiceName + "-" + QString::number(i);
+ }
+ }
+ while (!ok);
+ }
+ if ( m_pService )
+ {
+ // Existing service selected
+ serviceName = m_pService->name();
+ initialServiceName = serviceName;
+ fullExec = m_pService->exec();
+ }
+
+ if (terminal->isChecked())
+ {
+ KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
+ preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
+ m_command = preferredTerminal;
+ // only add --noclose when we are sure it is konsole we're using
+ if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
+ m_command += QString::fromLatin1(" --noclose");
+ m_command += QString::fromLatin1(" -e ");
+ m_command += edit->url();
+ kdDebug(250) << "Setting m_command to " << m_command << endl;
+ }
+ if ( m_pService && terminal->isChecked() != m_pService->terminal() )
+ m_pService = 0L; // It's not exactly this service we're running
+
+ bool bRemember = remember && remember->isChecked();
+
+ if ( !bRemember && m_pService)
+ {
+ accept();
+ return;
+ }
+
+ if (!bRemember && !d->saveNewApps)
+ {
+ // Create temp service
+ m_pService = new KService(initialServiceName, fullExec, QString::null);
+ if (terminal->isChecked())
+ {
+ m_pService->setTerminal(true);
+ // only add --noclose when we are sure it is konsole we're using
+ if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
+ m_pService->setTerminalOptions("--noclose");
+ }
+ accept();
+ return;
+ }
+
+ // if we got here, we can't seem to find a service for what they
+ // wanted. The other possibility is that they have asked for the
+ // association to be remembered. Create/update service.
+
+ QString newPath;
+ QString oldPath;
+ QString menuId;
+ if (m_pService)
+ {
+ oldPath = m_pService->desktopEntryPath();
+ newPath = m_pService->locateLocal();
+ menuId = m_pService->menuId();
+ kdDebug(250) << "Updating exitsing service " << m_pService->desktopEntryPath() << " ( " << newPath << " ) " << endl;
+ }
+ else
+ {
+ newPath = KService::newServicePath(false /* hidden */, serviceName, &menuId);
+ kdDebug(250) << "Creating new service " << serviceName << " ( " << newPath << " ) " << endl;
+ }
+
+ int maxPreference = 1;
+ if (!qServiceType.isEmpty())
+ {
+ KServiceTypeProfile::OfferList offerList = KServiceTypeProfile::offers( qServiceType );
+ if (!offerList.isEmpty())
+ maxPreference = offerList.first().preference();
+ }
+
+ KDesktopFile *desktop = 0;
+ if (!oldPath.isEmpty() && (oldPath != newPath))
+ {
+ KDesktopFile orig(oldPath, true);
+ desktop = orig.copyTo(newPath);
+ }
+ else
+ {
+ desktop = new KDesktopFile(newPath);
+ }
+ desktop->writeEntry("Type", QString::fromLatin1("Application"));
+ desktop->writeEntry("Name", initialServiceName);
+ desktop->writePathEntry("Exec", fullExec);
+ if (terminal->isChecked())
+ {
+ desktop->writeEntry("Terminal", true);
+ // only add --noclose when we are sure it is konsole we're using
+ if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
+ desktop->writeEntry("TerminalOptions", "--noclose");
+ }
+ else
+ {
+ desktop->writeEntry("Terminal", false);
+ }
+ desktop->writeEntry("InitialPreference", maxPreference + 1);
+
+
+ if (bRemember || d->saveNewApps)
+ {
+ QStringList mimeList = desktop->readListEntry("MimeType", ';');
+ if (!qServiceType.isEmpty() && !mimeList.contains(qServiceType))
+ mimeList.append(qServiceType);
+ desktop->writeEntry("MimeType", mimeList, ';');
+
+ if ( !qServiceType.isEmpty() )
+ {
+ // Also make sure the "auto embed" setting for this mimetype is off
+ KDesktopFile mimeDesktop( locateLocal( "mime", qServiceType + ".desktop" ) );
+ mimeDesktop.writeEntry( "X-KDE-AutoEmbed", false );
+ mimeDesktop.sync();
+ }
+ }
+
+ // write it all out to the file
+ desktop->sync();
+ delete desktop;
+
+ KService::rebuildKSycoca(this);
+
+ m_pService = KService::serviceByMenuId( menuId );
+
+ Q_ASSERT( m_pService );
+
+ accept();
+}
+
+QString KOpenWithDlg::text() const
+{
+ if (!m_command.isEmpty())
+ return m_command;
+ else
+ return edit->url();
+}
+
+void KOpenWithDlg::hideNoCloseOnExit()
+{
+ // uncheck the checkbox because the value could be used when "Run in Terminal" is selected
+ nocloseonexit->setChecked( false );
+ nocloseonexit->hide();
+}
+
+void KOpenWithDlg::hideRunInTerminal()
+{
+ terminal->hide();
+ hideNoCloseOnExit();
+}
+
+void KOpenWithDlg::accept()
+{
+ KHistoryCombo *combo = static_cast<KHistoryCombo*>( edit->comboBox() );
+ if ( combo ) {
+ combo->addToHistory( edit->url() );
+
+ KConfig *kc = KGlobal::config();
+ KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") );
+ kc->writeEntry( QString::fromLatin1("History"), combo->historyItems() );
+ kc->writeEntry(QString::fromLatin1("CompletionMode"),
+ combo->completionMode());
+ // don't store the completion-list, as it contains all of KURLCompletion's
+ // executables
+ kc->sync();
+ }
+
+ QDialog::accept();
+}
+
+
+///////////////
+
+#ifndef KDE_NO_COMPAT
+bool KFileOpenWithHandler::displayOpenWithDialog( const KURL::List& urls )
+{
+ KOpenWithDlg l( urls, i18n("Open with:"), QString::null, 0L );
+ if ( l.exec() )
+ {
+ KService::Ptr service = l.service();
+ if ( !!service )
+ return KRun::run( *service, urls );
+
+ kdDebug(250) << "No service set, running " << l.text() << endl;
+ return KRun::run( l.text(), urls );
+ }
+ return false;
+}
+#endif
+
+#include "kopenwith.moc"
+#include "kopenwith_p.moc"
+
diff --git a/kio/kfile/kopenwith.h b/kio/kfile/kopenwith.h
new file mode 100644
index 000000000..c343816aa
--- /dev/null
+++ b/kio/kfile/kopenwith.h
@@ -0,0 +1,209 @@
+//
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef __open_with_h__
+#define __open_with_h__
+
+#include <qdialog.h>
+
+#include <kurl.h>
+#include <krun.h>
+#include <kservice.h>
+
+class KApplicationTree;
+class KURLRequester;
+
+class QWidget;
+class QCheckBox;
+class QPushButton;
+class QLabel;
+
+class KOpenWithDlgPrivate;
+
+/* ------------------------------------------------------------------------- */
+/**
+ * "Open with" dialog box.
+ * Used automatically by KRun, and used by libkonq.
+ *
+ * @author David Faure <faure@kde.org>
+ */
+class KIO_EXPORT KOpenWithDlg : public QDialog //#TODO: Use KDialogBase for KDE4
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Create a dialog that asks for a application to open a given
+ * URL(s) with.
+ *
+ * @param urls the URLs that should be opened. The list can be empty,
+ * if the dialog is used to choose an application but not for some particular URLs.
+ * @param parent parent widget
+ */
+ KOpenWithDlg( const KURL::List& urls, QWidget *parent = 0L );
+
+ /**
+ * Create a dialog that asks for a application to open a given
+ * URL(s) with.
+ *
+ * @param urls is the URL that should be opened
+ * @param text appears as a label on top of the entry box.
+ * @param value is the initial value of the line
+ * @param parent parent widget
+ */
+ KOpenWithDlg( const KURL::List& urls, const QString& text, const QString& value,
+ QWidget *parent = 0L );
+
+ /**
+ * Create a dialog to select a service for a given service type.
+ * Note that this dialog doesn't apply to URLs.
+ *
+ * @param serviceType the service type we want to choose an application for.
+ * @param value is the initial value of the line
+ * @param parent parent widget
+ */
+ KOpenWithDlg( const QString& serviceType, const QString& value,
+ QWidget *parent = 0L );
+
+ /**
+ * Create a dialog to select an application
+ * Note that this dialog doesn't apply to URLs.
+ *
+ * @param parent parent widget
+ * @since 3.1
+ */
+ KOpenWithDlg( QWidget *parent = 0L );
+
+ /**
+ * Destructor
+ */
+ ~KOpenWithDlg();
+
+ /**
+ * @return the text the user entered
+ */
+ QString text() const;
+ /**
+ * Hide the "Do not &close when command exits" Checkbox
+ */
+ void hideNoCloseOnExit();
+ /**
+ * Hide the "Run in &terminal" Checkbox
+ */
+ void hideRunInTerminal();
+ /**
+ * @return the chosen service in the application tree
+ * Can be null, if the user typed some text and didn't select a service.
+ */
+ KService::Ptr service() const { return m_pService; }
+ /**
+ * Set whether a new .desktop file should be created if the user selects an
+ * application for which no corresponding .desktop file can be found.
+ *
+ * Regardless of this setting a new .desktop file may still be created if
+ * the user has chosen to remember the file association.
+ *
+ * The default is false: no .desktop files are created.
+ * @since 3.2
+ */
+ void setSaveNewApplications(bool b);
+
+public slots:
+ /**
+ * The slot for clearing the edit widget
+ */
+ void slotClear();
+ void slotSelected( const QString&_name, const QString& _exec );
+ void slotHighlighted( const QString& _name, const QString& _exec );
+ void slotTextChanged();
+ void slotTerminalToggled(bool);
+ void slotDbClick();
+ void slotOK();
+
+protected slots:
+ /**
+ * Reimplemented from QDialog::accept() to save history of the combobox
+ */
+ virtual void accept();
+
+protected:
+
+ /**
+ * Determine service type from URLs
+ */
+ void setServiceType( const KURL::List& _urls );
+
+ /**
+ * Create a dialog that asks for a application to open a given
+ * URL(s) with.
+ *
+ * @param text appears as a label on top of the entry box.
+ * @param value is the initial value of the line
+ */
+ void init( const QString& text, const QString& value );
+
+ KURLRequester * edit;
+ QString m_command;
+
+ KApplicationTree* m_pTree;
+ QLabel *label;
+
+ QString qName, qServiceType;
+ bool m_terminaldirty;
+ QCheckBox *terminal, *remember, *nocloseonexit;
+ QPushButton *UNUSED;
+ QPushButton *UNUSED2;
+
+ KService::Ptr m_pService;
+
+ KOpenWithDlgPrivate *d;
+};
+
+/* ------------------------------------------------------------------------- */
+
+#ifndef KDE_NO_COMPAT
+/**
+ * This class handles the displayOpenWithDialog call, made by KRun
+ * when it has no idea what to do with a URL.
+ * It displays the open-with dialog box.
+ *
+ * If you use KRun you _need_ to create an instance of KFileOpenWithHandler
+ * (except if you can make sure you only use it for executables or
+ * Type=Application desktop files)
+ *
+ *
+ */
+class KIO_EXPORT_DEPRECATED KFileOpenWithHandler : public KOpenWithHandler
+{
+public:
+ KFileOpenWithHandler() : KOpenWithHandler() {}
+ virtual ~KFileOpenWithHandler() {}
+
+ /**
+ * Opens an open-with dialog box for @p urls
+ * @returns true if the operation succeeded
+ */
+ virtual bool displayOpenWithDialog( const KURL::List& urls );
+};
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
+#endif
diff --git a/kio/kfile/kopenwith_p.h b/kio/kfile/kopenwith_p.h
new file mode 100644
index 000000000..ccee6bd22
--- /dev/null
+++ b/kio/kfile/kopenwith_p.h
@@ -0,0 +1,101 @@
+//
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef __open_with_p_h__
+#define __open_with_p_h__
+
+#include <kurl.h>
+#include <klistview.h>
+
+class KURLRequester;
+
+class QWidget;
+class QCheckBox;
+class QPushButton;
+class QLabel;
+class QStringList;
+
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @internal
+ */
+class KAppTreeListItem : public QListViewItem
+{
+ bool parsed;
+ bool directory;
+ QString path;
+ QString exec;
+
+protected:
+ int compare(QListViewItem *i, int col, bool ascending ) const;
+ QString key(int column, bool ascending) const;
+
+ void init(const QPixmap& pixmap, bool parse, bool dir, const QString &_path, const QString &exec);
+
+public:
+ KAppTreeListItem( KListView* parent, const QString & name, const QPixmap& pixmap,
+ bool parse, bool dir, const QString &p, const QString &c );
+ KAppTreeListItem( QListViewItem* parent, const QString & name, const QPixmap& pixmap,
+ bool parse, bool dir, const QString &p, const QString &c );
+ bool isDirectory();
+
+protected:
+ virtual void activate();
+ virtual void setOpen( bool o );
+
+ friend class KApplicationTree;
+};
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @internal
+ */
+class KApplicationTree : public KListView
+{
+ Q_OBJECT
+public:
+ KApplicationTree( QWidget *parent );
+
+ /**
+ * Add a group of .desktop/.kdelnk entries
+ */
+ void addDesktopGroup( const QString &relPath, KAppTreeListItem *item = 0 );
+
+ bool isDirSel();
+
+protected:
+ void resizeEvent( QResizeEvent *_ev );
+ KAppTreeListItem* currentitem;
+ void cleanupTree();
+
+public slots:
+ void slotItemHighlighted(QListViewItem* i);
+ void slotSelectionChanged(QListViewItem* i);
+
+signals:
+ void selected( const QString& _name, const QString& _exec );
+ void highlighted( const QString& _name, const QString& _exec );
+};
+
+/* ------------------------------------------------------------------------- */
+
+#endif
diff --git a/kio/kfile/kpreviewprops.cpp b/kio/kfile/kpreviewprops.cpp
new file mode 100644
index 000000000..986e46597
--- /dev/null
+++ b/kio/kfile/kpreviewprops.cpp
@@ -0,0 +1,89 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2005 Stephan Binner <binner@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ */
+
+#include "kpreviewprops.h"
+
+#include <qlayout.h>
+
+#include <kfilemetapreview.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+
+class KPreviewPropsPlugin::KPreviewPropsPluginPrivate
+{
+public:
+ KPreviewPropsPluginPrivate() {}
+ ~KPreviewPropsPluginPrivate() {}
+};
+
+KPreviewPropsPlugin::KPreviewPropsPlugin(KPropertiesDialog* props)
+ : KPropsDlgPlugin(props)
+{
+ d = new KPreviewPropsPluginPrivate;
+
+ if (properties->items().count()>1)
+ return;
+
+ createLayout();
+}
+
+void KPreviewPropsPlugin::createLayout()
+{
+ // let the dialog create the page frame
+ QFrame* topframe = properties->addPage(i18n("P&review"));
+ topframe->setFrameStyle(QFrame::NoFrame);
+
+ QVBoxLayout* tmp = new QVBoxLayout(topframe, 0, 0);
+
+ preview = new KFileMetaPreview(topframe);
+
+ tmp->addWidget(preview) ;
+ connect( properties, SIGNAL( aboutToShowPage( QWidget * ) ), SLOT( aboutToShowPage( QWidget* ) ) );
+}
+
+KPreviewPropsPlugin::~KPreviewPropsPlugin()
+{
+ delete d;
+}
+
+bool KPreviewPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1)
+ return false;
+ if( !KGlobalSettings::showFilePreview(_items.first()->url()))
+ return false;
+ KMimeType::Ptr mt = KMimeType::findByURL( _items.first()->url() );
+ if ( mt->inherits("inode/directory") || mt->name() == "application/octet-stream" )
+ return false;
+
+ //TODO Copy everything of KFileMetaPreview::previewProviderFor() ?
+
+ return true;
+}
+
+void KPreviewPropsPlugin::aboutToShowPage( QWidget* widget )
+{
+ if ( widget != preview->parent() )
+ return;
+
+ disconnect( properties, SIGNAL( aboutToShowPage( QWidget * ) ), this, SLOT( aboutToShowPage( QWidget* ) ) );
+ preview->showPreview(properties->item()->url());
+}
+
+#include "kpreviewprops.moc"
diff --git a/kio/kfile/kpreviewprops.h b/kio/kfile/kpreviewprops.h
new file mode 100644
index 000000000..be3019083
--- /dev/null
+++ b/kio/kfile/kpreviewprops.h
@@ -0,0 +1,57 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2005 Stephan Binner <binner@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ */
+
+#ifndef __KPREVIEWPROPS_H__
+#define __KPREVIEWPROPS_H__
+
+#include <kpropertiesdialog.h>
+
+class KFileMetaPreview;
+
+/*!
+ * PreviewProps plugin
+ * This plugin displays a preview of the given file
+ * @since 3.5
+ */
+class KIO_EXPORT KPreviewPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+
+public:
+
+ KPreviewPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KPreviewPropsPlugin();
+
+ /**
+ * Tests whether a preview for the first item should be shown
+ */
+ static bool supports( KFileItemList _items );
+
+private slots:
+ void aboutToShowPage( QWidget* );
+
+private:
+ KFileMetaPreview* preview;
+ void createLayout();
+
+ class KPreviewPropsPluginPrivate;
+ KPreviewPropsPluginPrivate *d;
+};
+
+#endif
diff --git a/kio/kfile/kpreviewwidgetbase.cpp b/kio/kfile/kpreviewwidgetbase.cpp
new file mode 100644
index 000000000..43b2b5fdc
--- /dev/null
+++ b/kio/kfile/kpreviewwidgetbase.cpp
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the KDE project.
+ * Copyright (C) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "kpreviewwidgetbase.h"
+#include <qstringlist.h>
+
+class KPreviewWidgetBase::KPreviewWidgetBasePrivate
+{
+public:
+ QStringList supportedMimeTypes;
+};
+
+QPtrDict<KPreviewWidgetBase::KPreviewWidgetBasePrivate> * KPreviewWidgetBase::s_private;
+
+KPreviewWidgetBase::KPreviewWidgetBase( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+ if ( !s_private )
+ s_private = new QPtrDict<KPreviewWidgetBasePrivate>();
+
+ s_private->insert( this, new KPreviewWidgetBasePrivate() );
+}
+
+KPreviewWidgetBase::~KPreviewWidgetBase()
+{
+ s_private->remove( this );
+ if ( s_private->isEmpty() )
+ {
+ delete s_private;
+ s_private = 0L;
+ }
+}
+
+void KPreviewWidgetBase::setSupportedMimeTypes( const QStringList& mimeTypes )
+{
+ d()->supportedMimeTypes = mimeTypes;
+}
+
+QStringList KPreviewWidgetBase::supportedMimeTypes() const
+{
+ return d()->supportedMimeTypes;
+}
+
+#include "kpreviewwidgetbase.moc"
diff --git a/kio/kfile/kpreviewwidgetbase.h b/kio/kfile/kpreviewwidgetbase.h
new file mode 100644
index 000000000..80f3f4ff4
--- /dev/null
+++ b/kio/kfile/kpreviewwidgetbase.h
@@ -0,0 +1,92 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 2001 Frerich Raabe <raabe@kde.org>
+ * 2003 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KPREVIEWWIDGETBASE_H__
+#define __KPREVIEWWIDGETBASE_H__
+
+#include <qptrdict.h>
+#include <qwidget.h>
+
+#include <kdelibs_export.h>
+
+class KURL;
+
+/**
+ * Abstract baseclass for all preview widgets which shall be used via
+ * KFileDialog::setPreviewWidget(const KPreviewWidgetBase *).
+ * Ownership will be transferred to KFileDialog, so you have to create
+ * the preview with "new" and let KFileDialog delete it.
+ *
+ * Just derive your custom preview widget from KPreviewWidgetBase and implement
+ * all the pure virtual methods. The slot showPreview(const KURL &) is called
+ * every time the file selection changes.
+ *
+ * @short Abstract baseclass for all preview widgets.
+ * @author Frerich Raabe <raabe@kde.org>
+ */
+class KIO_EXPORT KPreviewWidgetBase : public QWidget
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor. Construct the user interface of your preview widget here
+ * and pass the KFileDialog this preview widget is going to be used in as
+ * the parent.
+ *
+ * @param parent The KFileDialog this preview widget is going to be used in
+ * @param name The internal name of this object
+ */
+ KPreviewWidgetBase(QWidget *parent, const char *name=0);
+ ~KPreviewWidgetBase();
+
+public slots:
+ /**
+ * This slot is called every time the user selects another file in the
+ * file dialog. Implement the stuff necessary to reflect the change here.
+ *
+ * @param url The URL of the currently selected file.
+ */
+ virtual void showPreview(const KURL &url) = 0;
+
+ /**
+ * Reimplement this to clear the preview. This is called when e.g. the
+ * selection is cleared or when multiple selections exist, or the directory
+ * is changed.
+ */
+ virtual void clearPreview() = 0;
+
+ QStringList supportedMimeTypes() const;
+
+protected:
+ void setSupportedMimeTypes( const QStringList& mimeTypes );
+
+protected:
+ virtual void virtual_hook( int, void* ) {};
+
+private:
+ class KPreviewWidgetBasePrivate;
+ KPreviewWidgetBasePrivate * d() const {
+ return s_private->find( const_cast<KPreviewWidgetBase*>( this ) );
+ }
+ static QPtrDict<KPreviewWidgetBasePrivate> * s_private;
+};
+
+#endif
diff --git a/kio/kfile/kpropertiesdesktopadvbase.ui b/kio/kfile/kpropertiesdesktopadvbase.ui
new file mode 100644
index 000000000..fe1122136
--- /dev/null
+++ b/kio/kfile/kpropertiesdesktopadvbase.ui
@@ -0,0 +1,279 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KPropertiesDesktopAdvBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>widget11</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>463</width>
+ <height>294</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Terminal</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="1" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>terminalCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Run in terminal</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if the application you want to run is a text mode application or if you want the information that is provided by the terminal emulator window.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>terminalEditLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Terminal options:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>terminalEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>terminalCloseCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Do not &amp;close when command exits</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if the text mode application offers relevant information on exit. Keeping the terminal emulator open allows you to retrieve this information.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="2">
+ <property name="name">
+ <cstring>terminalEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup2_2</cstring>
+ </property>
+ <property name="title">
+ <string>User</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>suidCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Ru&amp;n as a different user</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want to run this application with a different user id. Every process has a different user id associated with it. This id code determines file access and other permissions. The password of the user is required to use this option.</string>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>suidEditLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Username:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>suidEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the user name you want to run the application as.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="2">
+ <property name="name">
+ <cstring>suidEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the user name you want to run the application as here.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup4</cstring>
+ </property>
+ <property name="title">
+ <string>Startup</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>startupInfoCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Enable &amp;launch feedback</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want to make clear that your application has started. This visual feedback may appear as a busy cursor or in the taskbar.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>systrayCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Place in system tray</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want to have a system tray handle for your application.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel12</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;DCOP registration:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>dcopCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Multiple Instances</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Single Instance</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Run Until Finished</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>dcopCombo</cstring>
+ </property>
+ </widget>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer33</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>terminalCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>terminalCloseCheck</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>terminalCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>terminalEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>terminalCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>terminalEditLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>suidCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>suidEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>suidCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>suidEditLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kio/kfile/kpropertiesdesktopbase.ui b/kio/kfile/kpropertiesdesktopbase.ui
new file mode 100644
index 000000000..7809d5135
--- /dev/null
+++ b/kio/kfile/kpropertiesdesktopbase.ui
@@ -0,0 +1,316 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KPropertiesDesktopBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KPropertiesDesktopBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>449</width>
+ <height>304</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <spacer row="5" column="3" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="6" column="0" rowspan="1" colspan="7">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Supported file types:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>filetypeList</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;This list should show the types of file that your application can handle. This list is organized by &lt;u&gt;mimetypes&lt;/u&gt;.&lt;/p&gt;
+&lt;p&gt;MIME, Multipurpose Internet (e)Mail Extension, is a standard protocol for identifying the type of data based on filename extensions and correspondent &lt;u&gt;mimetypes&lt;/u&gt;. Example: the "bmp" part that comes after the dot in flower.bmp indicates that it is a specific kind of image, &lt;u&gt;image/x-bmp&lt;/u&gt;. To know which application should open each type of file, the system should be informed about the abilities of each application to handle these extensions and mimetypes.&lt;/p&gt;
+&lt;p&gt;If you want to associate this application with one or more mimetypes that are not in this list, click on the button &lt;b&gt;Add&lt;/b&gt; below. If there are one or more filetypes that this application cannot handle, you may want to remove them from the list clicking on the button &lt;b&gt;Remove&lt;/b&gt; below.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KListView" row="7" column="0" rowspan="1" colspan="7">
+ <column>
+ <property name="text">
+ <string>Mimetype</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Description</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>filetypeList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;This list should show the types of file that your application can handle. This list is organized by &lt;u&gt;mimetypes&lt;/u&gt;.&lt;/p&gt;
+&lt;p&gt;MIME, Multipurpose Internet (e)Mail Extension, is a standard protocol for identifying the type of data based on filename extensions and correspondent &lt;u&gt;mimetypes&lt;/u&gt;. Example: the "bmp" part that comes after the dot in flower.bmp indicates that it is a specific kind of image, &lt;u&gt;image/x-bmp&lt;/u&gt;. To know which application should open each type of file, the system should be informed about the abilities of each application to handle these extensions and mimetypes.&lt;/p&gt;
+&lt;p&gt;If you want to associate this application with one or more mimetypes that are not in this list, click on the button &lt;b&gt;Add&lt;/b&gt; below. If there are one or more filetypes that this application cannot handle, you may want to remove them from the list clicking on the button &lt;b&gt;Remove&lt;/b&gt; below.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>nameLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the name you want to give to this application here. This application will appear under this name in the applications menu and in the panel.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="2" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>nameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the name you want to give to this application here. This application will appear under this name in the applications menu and in the panel.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Description:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genNameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the description of this application, based on its use, here. Examples: a dial up application (KPPP) would be "Dial up tool".</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="2" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>genNameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the description of this application, based on its use, here. Examples: a dial up application (KPPP) would be "Dial up tool".</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Comm&amp;ent:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>commentEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type any comment you think is useful here.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="2" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>commentEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type any comment you think is useful here.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Co&amp;mmand:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>commandEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the command to start this application here.
+
+Following the command, you can have several place holders which will be replaced with the actual values when the actual program is run:
+%f - a single file name
+%F - a list of files; use for applications that can open several local files at once
+%u - a single URL
+%U - a list of URLs
+%d - the directory of the file to open
+%D - a list of directories
+%i - the icon
+%m - the mini-icon
+%c - the caption</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="2" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>commandEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the command to start this application here.
+
+Following the command, you can have several place holders which will be replaced with the actual values when the actual program is run:
+%f - a single file name
+%F - a list of files; use for applications that can open several local files at once
+%u - a single URL
+%U - a list of URLs
+%d - the directory of the file to open
+%D - a list of directories
+%i - the icon
+%m - the mini-icon
+%c - the caption</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="6">
+ <property name="name">
+ <cstring>browseButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Browse...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click here to browse your file system in order to find the desired executable.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Work path:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>pathEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Sets the working directory for your application.</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="4" column="2" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>pathEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Sets the working directory for your application.</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="8" column="0">
+ <property name="name">
+ <cstring>addFiletypeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Add...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click on this button if you want to add a type of file (mimetype) that your application can handle.</string>
+ </property>
+ </widget>
+ <spacer row="8" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer31_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>53</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="8" column="3">
+ <property name="name">
+ <cstring>delFiletypeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If you want to remove a type of file (mimetype) that your application cannot handle, select the mimetype in the list above and click on this button.</string>
+ </property>
+ </widget>
+ <spacer row="8" column="4">
+ <property name="name">
+ <cstring>spacer31_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>53</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="8" column="5" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>advancedButton</cstring>
+ </property>
+ <property name="text">
+ <string>Ad&amp;vanced Options</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click here to modify the way this application will run, launch feedback, DCOP options or to run it as a different user.</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klistview.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kio/kfile/kpropertiesdialog.cpp b/kio/kfile/kpropertiesdialog.cpp
new file mode 100644
index 000000000..fd08d906d
--- /dev/null
+++ b/kio/kfile/kpropertiesdialog.cpp
@@ -0,0 +1,4157 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (c) 1999, 2000 Preston Brown <pbrown@kde.org>
+ Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
+ Copyright (c) 2000 David Faure <faure@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ * kpropertiesdialog.cpp
+ * View/Edit Properties of files, locally or remotely
+ *
+ * some FilePermissionsPropsPlugin-changes by
+ * Henner Zeller <zeller@think.de>
+ * some layout management by
+ * Bertrand Leconte <B.Leconte@mail.dotcom.fr>
+ * the rest of the layout management, bug fixes, adaptation to libkio,
+ * template feature by
+ * David Faure <faure@kde.org>
+ * More layout, cleanups, and fixes by
+ * Preston Brown <pbrown@kde.org>
+ * Plugin capability, cleanups and port to KDialogBase by
+ * Simon Hausmann <hausmann@kde.org>
+ * KDesktopPropsPlugin by
+ * Waldo Bastian <bastian@kde.org>
+ */
+
+#include <config.h>
+extern "C" {
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <sys/types.h>
+}
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <algorithm>
+#include <functional>
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <qstrlist.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qpainter.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qgroupbox.h>
+#include <qwhatsthis.h>
+#include <qtooltip.h>
+#include <qstyle.h>
+#include <qprogressbar.h>
+#include <qvbox.h>
+#include <qvaluevector.h>
+
+#ifdef USE_POSIX_ACL
+extern "C" {
+#include <sys/param.h>
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+}
+#endif
+
+#include <kapplication.h>
+#include <kdialog.h>
+#include <kdirsize.h>
+#include <kdirwatch.h>
+#include <kdirnotify_stub.h>
+#include <kdiskfreesp.h>
+#include <kdebug.h>
+#include <kdesktopfile.h>
+#include <kicondialog.h>
+#include <kurl.h>
+#include <kurlrequester.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kstandarddirs.h>
+#include <kio/job.h>
+#include <kio/chmodjob.h>
+#include <kio/renamedlg.h>
+#include <kio/netaccess.h>
+#include <kio/kservicetypefactory.h>
+#include <kfiledialog.h>
+#include <kmimetype.h>
+#include <kmountpoint.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kservice.h>
+#include <kcompletion.h>
+#include <klineedit.h>
+#include <kseparator.h>
+#include <ksqueezedtextlabel.h>
+#include <klibloader.h>
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+#include <kmetaprops.h>
+#include <kpreviewprops.h>
+#include <kprocess.h>
+#include <krun.h>
+#include <klistview.h>
+#include <kacl.h>
+#include "kfilesharedlg.h"
+
+#include "kpropertiesdesktopbase.h"
+#include "kpropertiesdesktopadvbase.h"
+#include "kpropertiesmimetypebase.h"
+#ifdef USE_POSIX_ACL
+#include "kacleditwidget.h"
+#endif
+
+#include "kpropertiesdialog.h"
+
+#ifdef Q_WS_WIN
+# include <win32_utils.h>
+#endif
+
+static QString nameFromFileName(QString nameStr)
+{
+ if ( nameStr.endsWith(".desktop") )
+ nameStr.truncate( nameStr.length() - 8 );
+ if ( nameStr.endsWith(".kdelnk") )
+ nameStr.truncate( nameStr.length() - 7 );
+ // Make it human-readable (%2F => '/', ...)
+ nameStr = KIO::decodeFileName( nameStr );
+ return nameStr;
+}
+
+mode_t KFilePermissionsPropsPlugin::fperm[3][4] = {
+ {S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID},
+ {S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID},
+ {S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX}
+ };
+
+class KPropertiesDialog::KPropertiesDialogPrivate
+{
+public:
+ KPropertiesDialogPrivate()
+ {
+ m_aborted = false;
+ fileSharePage = 0;
+ }
+ ~KPropertiesDialogPrivate()
+ {
+ }
+ bool m_aborted:1;
+ QWidget* fileSharePage;
+};
+
+KPropertiesDialog::KPropertiesDialog (KFileItem* item,
+ QWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(item->url().fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal)
+{
+ d = new KPropertiesDialogPrivate;
+ assert( item );
+ m_items.append( new KFileItem(*item) ); // deep copy
+
+ m_singleUrl = item->url();
+ assert(!m_singleUrl.isEmpty());
+
+ init (modal, autoShow);
+}
+
+KPropertiesDialog::KPropertiesDialog (const QString& title,
+ QWidget* parent, const char* name, bool modal)
+ : KDialogBase (KDialogBase::Tabbed, i18n ("Properties for %1").arg(title),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal)
+{
+ d = new KPropertiesDialogPrivate;
+
+ init (modal, false);
+}
+
+KPropertiesDialog::KPropertiesDialog (KFileItemList _items,
+ QWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed,
+ // TODO: replace <never used> with "Properties for 1 item". It's very confusing how it has to be translated otherwise
+ // (empty translation before the "\n" is not allowed by msgfmt...)
+ _items.count()>1 ? i18n( "<never used>","Properties for %n Selected Items",_items.count()) :
+ i18n( "Properties for %1" ).arg(KIO::decodeFileName(_items.first()->url().fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal)
+{
+ d = new KPropertiesDialogPrivate;
+
+ assert( !_items.isEmpty() );
+ m_singleUrl = _items.first()->url();
+ assert(!m_singleUrl.isEmpty());
+
+ KFileItemListIterator it ( _items );
+ // Deep copy
+ for ( ; it.current(); ++it )
+ m_items.append( new KFileItem( **it ) );
+
+ init (modal, autoShow);
+}
+
+#ifndef KDE_NO_COMPAT
+KPropertiesDialog::KPropertiesDialog (const KURL& _url, mode_t /* _mode is now unused */,
+ QWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed,
+ i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal),
+ m_singleUrl( _url )
+{
+ d = new KPropertiesDialogPrivate;
+
+ KIO::UDSEntry entry;
+
+ KIO::NetAccess::stat(_url, entry, parent);
+
+ m_items.append( new KFileItem( entry, _url ) );
+ init (modal, autoShow);
+}
+#endif
+
+KPropertiesDialog::KPropertiesDialog (const KURL& _url,
+ QWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed,
+ i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal),
+ m_singleUrl( _url )
+{
+ d = new KPropertiesDialogPrivate;
+
+ KIO::UDSEntry entry;
+
+ KIO::NetAccess::stat(_url, entry, parent);
+
+ m_items.append( new KFileItem( entry, _url ) );
+ init (modal, autoShow);
+}
+
+KPropertiesDialog::KPropertiesDialog (const KURL& _tempUrl, const KURL& _currentDir,
+ const QString& _defaultName,
+ QWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed,
+ i18n( "Properties for %1" ).arg(KIO::decodeFileName(_tempUrl.fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal),
+
+ m_singleUrl( _tempUrl ),
+ m_defaultName( _defaultName ),
+ m_currentDir( _currentDir )
+{
+ d = new KPropertiesDialogPrivate;
+
+ assert(!m_singleUrl.isEmpty());
+
+ // Create the KFileItem for the _template_ file, in order to read from it.
+ m_items.append( new KFileItem( KFileItem::Unknown, KFileItem::Unknown, m_singleUrl ) );
+ init (modal, autoShow);
+}
+
+bool KPropertiesDialog::showDialog(KFileItem* item, QWidget* parent,
+ const char* name, bool modal)
+{
+#ifdef Q_WS_WIN
+ QString localPath = item->localPath();
+ if (!localPath.isEmpty())
+ return showWin32FilePropertyDialog(localPath);
+#endif
+ new KPropertiesDialog(item, parent, name, modal);
+ return true;
+}
+
+bool KPropertiesDialog::showDialog(const KURL& _url, QWidget* parent,
+ const char* name, bool modal)
+{
+#ifdef Q_WS_WIN
+ if (_url.isLocalFile())
+ return showWin32FilePropertyDialog( _url.path() );
+#endif
+ new KPropertiesDialog(_url, parent, name, modal);
+ return true;
+}
+
+bool KPropertiesDialog::showDialog(const KFileItemList& _items, QWidget* parent,
+ const char* name, bool modal)
+{
+ if (_items.count()==1)
+ return KPropertiesDialog::showDialog(_items.getFirst(), parent, name, modal);
+ new KPropertiesDialog(_items, parent, name, modal);
+ return true;
+}
+
+void KPropertiesDialog::init (bool modal, bool autoShow)
+{
+ m_pageList.setAutoDelete( true );
+ m_items.setAutoDelete( true );
+
+ insertPages();
+
+ if (autoShow)
+ {
+ if (!modal)
+ show();
+ else
+ exec();
+ }
+}
+
+void KPropertiesDialog::showFileSharingPage()
+{
+ if (d->fileSharePage) {
+ showPage( pageIndex( d->fileSharePage));
+ }
+}
+
+void KPropertiesDialog::setFileSharingPage(QWidget* page) {
+ d->fileSharePage = page;
+}
+
+
+void KPropertiesDialog::setFileNameReadOnly( bool ro )
+{
+ KPropsDlgPlugin *it;
+
+ for ( it=m_pageList.first(); it != 0L; it=m_pageList.next() )
+ {
+ KFilePropsPlugin* plugin = dynamic_cast<KFilePropsPlugin*>(it);
+ if ( plugin ) {
+ plugin->setFileNameReadOnly( ro );
+ break;
+ }
+ }
+}
+
+void KPropertiesDialog::slotStatResult( KIO::Job * )
+{
+}
+
+KPropertiesDialog::~KPropertiesDialog()
+{
+ m_pageList.clear();
+ delete d;
+}
+
+void KPropertiesDialog::insertPlugin (KPropsDlgPlugin* plugin)
+{
+ connect (plugin, SIGNAL (changed ()),
+ plugin, SLOT (setDirty ()));
+
+ m_pageList.append (plugin);
+}
+
+bool KPropertiesDialog::canDisplay( KFileItemList _items )
+{
+ // TODO: cache the result of those calls. Currently we parse .desktop files far too many times
+ return KFilePropsPlugin::supports( _items ) ||
+ KFilePermissionsPropsPlugin::supports( _items ) ||
+ KDesktopPropsPlugin::supports( _items ) ||
+ KBindingPropsPlugin::supports( _items ) ||
+ KURLPropsPlugin::supports( _items ) ||
+ KDevicePropsPlugin::supports( _items ) ||
+ KFileMetaPropsPlugin::supports( _items ) ||
+ KPreviewPropsPlugin::supports( _items );
+}
+
+void KPropertiesDialog::slotOk()
+{
+ KPropsDlgPlugin *page;
+ d->m_aborted = false;
+
+ KFilePropsPlugin * filePropsPlugin = 0L;
+ if ( m_pageList.first()->isA("KFilePropsPlugin") )
+ filePropsPlugin = static_cast<KFilePropsPlugin *>(m_pageList.first());
+
+ // If any page is dirty, then set the main one (KFilePropsPlugin) as
+ // dirty too. This is what makes it possible to save changes to a global
+ // desktop file into a local one. In other cases, it doesn't hurt.
+ for ( page = m_pageList.first(); page != 0L; page = m_pageList.next() )
+ if ( page->isDirty() && filePropsPlugin )
+ {
+ filePropsPlugin->setDirty();
+ break;
+ }
+
+ // Apply the changes in the _normal_ order of the tabs now
+ // This is because in case of renaming a file, KFilePropsPlugin will call
+ // KPropertiesDialog::rename, so other tab will be ok with whatever order
+ // BUT for file copied from templates, we need to do the renaming first !
+ for ( page = m_pageList.first(); page != 0L && !d->m_aborted; page = m_pageList.next() )
+ if ( page->isDirty() )
+ {
+ kdDebug( 250 ) << "applying changes for " << page->className() << endl;
+ page->applyChanges();
+ // applyChanges may change d->m_aborted.
+ }
+ else
+ kdDebug( 250 ) << "skipping page " << page->className() << endl;
+
+ if ( !d->m_aborted && filePropsPlugin )
+ filePropsPlugin->postApplyChanges();
+
+ if ( !d->m_aborted )
+ {
+ emit applied();
+ emit propertiesClosed();
+ deleteLater();
+ accept();
+ } // else, keep dialog open for user to fix the problem.
+}
+
+void KPropertiesDialog::slotCancel()
+{
+ emit canceled();
+ emit propertiesClosed();
+
+ deleteLater();
+ done( Rejected );
+}
+
+void KPropertiesDialog::insertPages()
+{
+ if (m_items.isEmpty())
+ return;
+
+ if ( KFilePropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KFilePropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KFilePermissionsPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KFilePermissionsPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KDesktopPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KDesktopPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KBindingPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KBindingPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KURLPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KURLPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KDevicePropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KDevicePropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KFileMetaPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KFileMetaPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KPreviewPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KPreviewPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( kapp->authorizeKAction("sharefile") &&
+ KFileSharePropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KFileSharePropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ //plugins
+
+ if ( m_items.count() != 1 )
+ return;
+
+ KFileItem *item = m_items.first();
+ QString mimetype = item->mimetype();
+
+ if ( mimetype.isEmpty() )
+ return;
+
+ QString query = QString::fromLatin1(
+ "('KPropsDlg/Plugin' in ServiceTypes) and "
+ "((not exist [X-KDE-Protocol]) or "
+ " ([X-KDE-Protocol] == '%1' ) )" ).arg(item->url().protocol());
+
+ kdDebug( 250 ) << "trader query: " << query << endl;
+ KTrader::OfferList offers = KTrader::self()->query( mimetype, query );
+ KTrader::OfferList::ConstIterator it = offers.begin();
+ KTrader::OfferList::ConstIterator end = offers.end();
+ for (; it != end; ++it )
+ {
+ KPropsDlgPlugin *plugin = KParts::ComponentFactory
+ ::createInstanceFromLibrary<KPropsDlgPlugin>( (*it)->library().local8Bit().data(),
+ this,
+ (*it)->name().latin1() );
+ if ( !plugin )
+ continue;
+
+ insertPlugin( plugin );
+ }
+}
+
+void KPropertiesDialog::updateUrl( const KURL& _newUrl )
+{
+ Q_ASSERT( m_items.count() == 1 );
+ kdDebug(250) << "KPropertiesDialog::updateUrl (pre)" << _newUrl.url() << endl;
+ KURL newUrl = _newUrl;
+ emit saveAs(m_singleUrl, newUrl);
+ kdDebug(250) << "KPropertiesDialog::updateUrl (post)" << newUrl.url() << endl;
+
+ m_singleUrl = newUrl;
+ m_items.first()->setURL( newUrl );
+ assert(!m_singleUrl.isEmpty());
+ // If we have an Desktop page, set it dirty, so that a full file is saved locally
+ // Same for a URL page (because of the Name= hack)
+ for ( QPtrListIterator<KPropsDlgPlugin> it(m_pageList); it.current(); ++it )
+ if ( it.current()->isA("KExecPropsPlugin") || // KDE4 remove me
+ it.current()->isA("KURLPropsPlugin") ||
+ it.current()->isA("KDesktopPropsPlugin"))
+ {
+ //kdDebug(250) << "Setting page dirty" << endl;
+ it.current()->setDirty();
+ break;
+ }
+}
+
+void KPropertiesDialog::rename( const QString& _name )
+{
+ Q_ASSERT( m_items.count() == 1 );
+ kdDebug(250) << "KPropertiesDialog::rename " << _name << endl;
+ KURL newUrl;
+ // if we're creating from a template : use currentdir
+ if ( !m_currentDir.isEmpty() )
+ {
+ newUrl = m_currentDir;
+ newUrl.addPath( _name );
+ }
+ else
+ {
+ QString tmpurl = m_singleUrl.url();
+ if ( tmpurl.at(tmpurl.length() - 1) == '/')
+ // It's a directory, so strip the trailing slash first
+ tmpurl.truncate( tmpurl.length() - 1);
+ newUrl = tmpurl;
+ newUrl.setFileName( _name );
+ }
+ updateUrl( newUrl );
+}
+
+void KPropertiesDialog::abortApplying()
+{
+ d->m_aborted = true;
+}
+
+class KPropsDlgPlugin::KPropsDlgPluginPrivate
+{
+public:
+ KPropsDlgPluginPrivate()
+ {
+ }
+ ~KPropsDlgPluginPrivate()
+ {
+ }
+
+ bool m_bDirty;
+};
+
+KPropsDlgPlugin::KPropsDlgPlugin( KPropertiesDialog *_props )
+: QObject( _props, 0L )
+{
+ d = new KPropsDlgPluginPrivate;
+ properties = _props;
+ fontHeight = 2*properties->fontMetrics().height();
+ d->m_bDirty = false;
+}
+
+KPropsDlgPlugin::~KPropsDlgPlugin()
+{
+ delete d;
+}
+
+bool KPropsDlgPlugin::isDesktopFile( KFileItem * _item )
+{
+ // only local files
+ bool isLocal;
+ KURL url = _item->mostLocalURL( isLocal );
+ if ( !isLocal )
+ return false;
+
+ // only regular files
+ if ( !S_ISREG( _item->mode() ) )
+ return false;
+
+ QString t( url.path() );
+
+ // only if readable
+ FILE *f = fopen( QFile::encodeName(t), "r" );
+ if ( f == 0L )
+ return false;
+ fclose(f);
+
+ // return true if desktop file
+ return ( _item->mimetype() == "application/x-desktop" );
+}
+
+void KPropsDlgPlugin::setDirty( bool b )
+{
+ d->m_bDirty = b;
+}
+
+void KPropsDlgPlugin::setDirty()
+{
+ d->m_bDirty = true;
+}
+
+bool KPropsDlgPlugin::isDirty() const
+{
+ return d->m_bDirty;
+}
+
+void KPropsDlgPlugin::applyChanges()
+{
+ kdWarning(250) << "applyChanges() not implemented in page !" << endl;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class KFilePropsPlugin::KFilePropsPluginPrivate
+{
+public:
+ KFilePropsPluginPrivate()
+ {
+ dirSizeJob = 0L;
+ dirSizeUpdateTimer = 0L;
+ m_lined = 0;
+ m_freeSpaceLabel = 0;
+ }
+ ~KFilePropsPluginPrivate()
+ {
+ if ( dirSizeJob )
+ dirSizeJob->kill();
+ }
+
+ KDirSize * dirSizeJob;
+ QTimer *dirSizeUpdateTimer;
+ QFrame *m_frame;
+ bool bMultiple;
+ bool bIconChanged;
+ bool bKDesktopMode;
+ bool bDesktopFile;
+ QLabel *m_freeSpaceLabel;
+ QString mimeType;
+ QString oldFileName;
+ KLineEdit* m_lined;
+};
+
+KFilePropsPlugin::KFilePropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new KFilePropsPluginPrivate;
+ d->bMultiple = (properties->items().count() > 1);
+ d->bIconChanged = false;
+ d->bKDesktopMode = (QCString(qApp->name()) == "kdesktop"); // nasty heh?
+ d->bDesktopFile = KDesktopPropsPlugin::supports(properties->items());
+ kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin bMultiple=" << d->bMultiple << endl;
+
+ // We set this data from the first item, and we'll
+ // check that the other items match against it, resetting when not.
+ bool isLocal;
+ KFileItem * item = properties->item();
+ KURL url = item->mostLocalURL( isLocal );
+ bool isReallyLocal = item->url().isLocalFile();
+ bool bDesktopFile = isDesktopFile(item);
+ kdDebug() << "url=" << url << " bDesktopFile=" << bDesktopFile << " isLocal=" << isLocal << " isReallyLocal=" << isReallyLocal << endl;
+ mode_t mode = item->mode();
+ bool hasDirs = item->isDir() && !item->isLink();
+ bool hasRoot = url.path() == QString::fromLatin1("/");
+ QString iconStr = KMimeType::iconForURL(url, mode);
+ QString directory = properties->kurl().directory();
+ QString protocol = properties->kurl().protocol();
+ QString mimeComment = item->mimeComment();
+ d->mimeType = item->mimetype();
+ bool hasTotalSize;
+ KIO::filesize_t totalSize = item->size(hasTotalSize);
+ QString magicMimeComment;
+ if ( isLocal ) {
+ KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() );
+ if ( magicMimeType->name() != KMimeType::defaultMimeType() )
+ magicMimeComment = magicMimeType->comment();
+ }
+
+ // Those things only apply to 'single file' mode
+ QString filename = QString::null;
+ bool isTrash = false;
+ bool isDevice = false;
+ m_bFromTemplate = false;
+
+ // And those only to 'multiple' mode
+ uint iDirCount = hasDirs ? 1 : 0;
+ uint iFileCount = 1-iDirCount;
+
+ d->m_frame = properties->addPage (i18n("&General"));
+
+ QVBoxLayout *vbl = new QVBoxLayout( d->m_frame, 0,
+ KDialog::spacingHint(), "vbl");
+ QGridLayout *grid = new QGridLayout(0, 3); // unknown rows
+ grid->setColStretch(0, 0);
+ grid->setColStretch(1, 0);
+ grid->setColStretch(2, 1);
+ grid->addColSpacing(1, KDialog::spacingHint());
+ vbl->addLayout(grid);
+ int curRow = 0;
+
+ if ( !d->bMultiple )
+ {
+ QString path;
+ if ( !m_bFromTemplate ) {
+ isTrash = ( properties->kurl().protocol().find( "trash", 0, false)==0 );
+ if ( properties->kurl().protocol().find("device", 0, false)==0)
+ isDevice = true;
+ // Extract the full name, but without file: for local files
+ if ( isReallyLocal )
+ path = properties->kurl().path();
+ else
+ path = properties->kurl().prettyURL();
+ } else {
+ path = properties->currentDir().path(1) + properties->defaultName();
+ directory = properties->currentDir().prettyURL();
+ }
+
+ if (KExecPropsPlugin::supports(properties->items()) || // KDE4 remove me
+ d->bDesktopFile ||
+ KBindingPropsPlugin::supports(properties->items())) {
+ determineRelativePath( path );
+ }
+
+ // Extract the file name only
+ filename = properties->defaultName();
+ if ( filename.isEmpty() ) { // no template
+ filename = item->name(); // this gives support for UDS_NAME, e.g. for kio_trash or kio_system
+ } else {
+ m_bFromTemplate = true;
+ setDirty(); // to enforce that the copy happens
+ }
+ d->oldFileName = filename;
+
+ // Make it human-readable
+ filename = nameFromFileName( filename );
+
+ if ( d->bKDesktopMode && d->bDesktopFile ) {
+ KDesktopFile config( url.path(), true /* readonly */ );
+ if ( config.hasKey( "Name" ) ) {
+ filename = config.readName();
+ }
+ }
+
+ oldName = filename;
+ }
+ else
+ {
+ // Multiple items: see what they have in common
+ KFileItemList items = properties->items();
+ KFileItemListIterator it( items );
+ for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
+ {
+ KURL url = (*it)->url();
+ kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin " << url.prettyURL() << endl;
+ // The list of things we check here should match the variables defined
+ // at the beginning of this method.
+ if ( url.isLocalFile() != isLocal )
+ isLocal = false; // not all local
+ if ( bDesktopFile && isDesktopFile(*it) != bDesktopFile )
+ bDesktopFile = false; // not all desktop files
+ if ( (*it)->mode() != mode )
+ mode = (mode_t)0;
+ if ( KMimeType::iconForURL(url, mode) != iconStr )
+ iconStr = "kmultiple";
+ if ( url.directory() != directory )
+ directory = QString::null;
+ if ( url.protocol() != protocol )
+ protocol = QString::null;
+ if ( !mimeComment.isNull() && (*it)->mimeComment() != mimeComment )
+ mimeComment = QString::null;
+ if ( isLocal && !magicMimeComment.isNull() ) {
+ KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() );
+ if ( magicMimeType->comment() != magicMimeComment )
+ magicMimeComment = QString::null;
+ }
+
+ if ( url.path() == QString::fromLatin1("/") )
+ hasRoot = true;
+ if ( (*it)->isDir() && !(*it)->isLink() )
+ {
+ iDirCount++;
+ hasDirs = true;
+ }
+ else
+ {
+ iFileCount++;
+ bool hasSize;
+ totalSize += (*it)->size(hasSize);
+ hasTotalSize = hasTotalSize || hasSize;
+ }
+ }
+ }
+
+ if (!isReallyLocal && !protocol.isEmpty())
+ {
+ directory += ' ';
+ directory += '(';
+ directory += protocol;
+ directory += ')';
+ }
+
+ if ( !isDevice && !isTrash && (bDesktopFile || S_ISDIR(mode)) && !d->bMultiple /*not implemented for multiple*/ )
+ {
+ KIconButton *iconButton = new KIconButton( d->m_frame );
+ int bsize = 66 + 2 * iconButton->style().pixelMetric(QStyle::PM_ButtonMargin);
+ iconButton->setFixedSize(bsize, bsize);
+ iconButton->setIconSize(48);
+ iconButton->setStrictIconSize(false);
+ // This works for everything except Device icons on unmounted devices
+ // So we have to really open .desktop files
+ QString iconStr = KMimeType::findByURL( url, mode )->icon( url, isLocal );
+ if ( bDesktopFile && isLocal )
+ {
+ KDesktopFile config( url.path(), true );
+ config.setDesktopGroup();
+ iconStr = config.readEntry( "Icon" );
+ if ( config.hasDeviceType() )
+ iconButton->setIconType( KIcon::Desktop, KIcon::Device );
+ else
+ iconButton->setIconType( KIcon::Desktop, KIcon::Application );
+ } else
+ iconButton->setIconType( KIcon::Desktop, KIcon::FileSystem );
+ iconButton->setIcon(iconStr);
+ iconArea = iconButton;
+ connect( iconButton, SIGNAL( iconChanged(QString) ),
+ this, SLOT( slotIconChanged() ) );
+ } else {
+ QLabel *iconLabel = new QLabel( d->m_frame );
+ int bsize = 66 + 2 * iconLabel->style().pixelMetric(QStyle::PM_ButtonMargin);
+ iconLabel->setFixedSize(bsize, bsize);
+ iconLabel->setPixmap( KGlobal::iconLoader()->loadIcon( iconStr, KIcon::Desktop, 48) );
+ iconArea = iconLabel;
+ }
+ grid->addWidget(iconArea, curRow, 0, AlignLeft);
+
+ if (d->bMultiple || isTrash || isDevice || hasRoot)
+ {
+ QLabel *lab = new QLabel(d->m_frame );
+ if ( d->bMultiple )
+ lab->setText( KIO::itemsSummaryString( iFileCount + iDirCount, iFileCount, iDirCount, 0, false ) );
+ else
+ lab->setText( filename );
+ nameArea = lab;
+ } else
+ {
+ d->m_lined = new KLineEdit( d->m_frame );
+ d->m_lined->setText(filename);
+ nameArea = d->m_lined;
+ d->m_lined->setFocus();
+
+ // Enhanced rename: Don't highlight the file extension.
+ QString pattern;
+ KServiceTypeFactory::self()->findFromPattern( filename, &pattern );
+ if (!pattern.isEmpty() && pattern.at(0)=='*' && pattern.find('*',1)==-1)
+ d->m_lined->setSelection(0, filename.length()-pattern.stripWhiteSpace().length()+1);
+ else
+ {
+ int lastDot = filename.findRev('.');
+ if (lastDot > 0)
+ d->m_lined->setSelection(0, lastDot);
+ }
+
+ connect( d->m_lined, SIGNAL( textChanged( const QString & ) ),
+ this, SLOT( nameFileChanged(const QString & ) ) );
+ }
+
+ grid->addWidget(nameArea, curRow++, 2);
+
+ KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
+ grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
+ ++curRow;
+
+ QLabel *l;
+ if ( !mimeComment.isEmpty() && !isDevice && !isTrash)
+ {
+ l = new QLabel(i18n("Type:"), d->m_frame );
+
+ grid->addWidget(l, curRow, 0);
+
+ QHBox *box = new QHBox(d->m_frame);
+ box->setSpacing(20);
+ l = new QLabel(mimeComment, box );
+
+#ifdef Q_WS_X11
+ //TODO: wrap for win32 or mac?
+ QPushButton *button = new QPushButton(box);
+
+ QIconSet iconSet = SmallIconSet(QString::fromLatin1("configure"));
+ QPixmap pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal );
+ button->setIconSet( iconSet );
+ button->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
+ if ( d->mimeType == KMimeType::defaultMimeType() )
+ QToolTip::add(button, i18n("Create new file type"));
+ else
+ QToolTip::add(button, i18n("Edit file type"));
+
+ connect( button, SIGNAL( clicked() ), SLOT( slotEditFileType() ));
+
+ if (!kapp->authorizeKAction("editfiletype"))
+ button->hide();
+#endif
+
+ grid->addWidget(box, curRow++, 2);
+ }
+
+ if ( !magicMimeComment.isEmpty() && magicMimeComment != mimeComment )
+ {
+ l = new QLabel(i18n("Contents:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ l = new QLabel(magicMimeComment, d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ if ( !directory.isEmpty() )
+ {
+ l = new QLabel( i18n("Location:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ l = new KSqueezedTextLabel( d->m_frame );
+ l->setText( directory );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ if( hasDirs || hasTotalSize ) {
+ l = new QLabel(i18n("Size:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ m_sizeLabel = new QLabel( d->m_frame );
+ grid->addWidget( m_sizeLabel, curRow++, 2 );
+ } else {
+ m_sizeLabel = 0;
+ }
+
+ if ( !hasDirs ) // Only files [and symlinks]
+ {
+ if(hasTotalSize) {
+ m_sizeLabel->setText(KIO::convertSizeWithBytes(totalSize));
+ }
+
+ m_sizeDetermineButton = 0L;
+ m_sizeStopButton = 0L;
+ }
+ else // Directory
+ {
+ QHBoxLayout * sizelay = new QHBoxLayout(KDialog::spacingHint());
+ grid->addLayout( sizelay, curRow++, 2 );
+
+ // buttons
+ m_sizeDetermineButton = new QPushButton( i18n("Calculate"), d->m_frame );
+ m_sizeStopButton = new QPushButton( i18n("Stop"), d->m_frame );
+ connect( m_sizeDetermineButton, SIGNAL( clicked() ), this, SLOT( slotSizeDetermine() ) );
+ connect( m_sizeStopButton, SIGNAL( clicked() ), this, SLOT( slotSizeStop() ) );
+ sizelay->addWidget(m_sizeDetermineButton, 0);
+ sizelay->addWidget(m_sizeStopButton, 0);
+ sizelay->addStretch(10); // so that the buttons don't grow horizontally
+
+ // auto-launch for local dirs only, and not for '/'
+ if ( isLocal && !hasRoot )
+ {
+ m_sizeDetermineButton->setText( i18n("Refresh") );
+ slotSizeDetermine();
+ }
+ else
+ m_sizeStopButton->setEnabled( false );
+ }
+
+ if (!d->bMultiple && item->isLink()) {
+ l = new QLabel(i18n("Points to:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ l = new KSqueezedTextLabel(item->linkDest(), d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ if (!d->bMultiple) // Dates for multiple don't make much sense...
+ {
+ QDateTime dt;
+ bool hasTime;
+ time_t tim = item->time(KIO::UDS_CREATION_TIME, hasTime);
+ if ( hasTime )
+ {
+ l = new QLabel(i18n("Created:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ dt.setTime_t( tim );
+ l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ tim = item->time(KIO::UDS_MODIFICATION_TIME, hasTime);
+ if ( hasTime )
+ {
+ l = new QLabel(i18n("Modified:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ dt.setTime_t( tim );
+ l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ tim = item->time(KIO::UDS_ACCESS_TIME, hasTime);
+ if ( hasTime )
+ {
+ l = new QLabel(i18n("Accessed:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ dt.setTime_t( tim );
+ l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+ }
+
+ if ( isLocal && hasDirs ) // only for directories
+ {
+ sep = new KSeparator( KSeparator::HLine, d->m_frame);
+ grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
+ ++curRow;
+
+ QString mountPoint = KIO::findPathMountPoint( url.path() );
+
+ if (mountPoint != "/")
+ {
+ l = new QLabel(i18n("Mounted on:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ l = new KSqueezedTextLabel( mountPoint, d->m_frame );
+ grid->addWidget( l, curRow++, 2 );
+ }
+
+ l = new QLabel(i18n("Free disk space:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ d->m_freeSpaceLabel = new QLabel( d->m_frame );
+ grid->addWidget( d->m_freeSpaceLabel, curRow++, 2 );
+
+ KDiskFreeSp * job = new KDiskFreeSp;
+ connect( job, SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const QString& ) ),
+ this, SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const QString& ) ) );
+ job->readDF( mountPoint );
+ }
+
+ vbl->addStretch(1);
+}
+
+// QString KFilePropsPlugin::tabName () const
+// {
+// return i18n ("&General");
+// }
+
+void KFilePropsPlugin::setFileNameReadOnly( bool ro )
+{
+ if ( d->m_lined )
+ {
+ d->m_lined->setReadOnly( ro );
+ if (ro)
+ {
+ // Don't put the initial focus on the line edit when it is ro
+ QPushButton *button = properties->actionButton(KDialogBase::Ok);
+ if (button)
+ button->setFocus();
+ }
+ }
+}
+
+void KFilePropsPlugin::slotEditFileType()
+{
+#ifdef Q_WS_X11
+ QString mime;
+ if ( d->mimeType == KMimeType::defaultMimeType() ) {
+ int pos = d->oldFileName.findRev( '.' );
+ if ( pos != -1 )
+ mime = "*" + d->oldFileName.mid(pos);
+ else
+ mime = "*";
+ }
+ else
+ mime = d->mimeType;
+ //TODO: wrap for win32 or mac?
+ QString keditfiletype = QString::fromLatin1("keditfiletype");
+ KRun::runCommand( keditfiletype
+ + " --parent " + QString::number( (ulong)properties->topLevelWidget()->winId())
+ + " " + KProcess::quote(mime),
+ keditfiletype, keditfiletype /*unused*/);
+#endif
+}
+
+void KFilePropsPlugin::slotIconChanged()
+{
+ d->bIconChanged = true;
+ emit changed();
+}
+
+void KFilePropsPlugin::nameFileChanged(const QString &text )
+{
+ properties->enableButtonOK(!text.isEmpty());
+ emit changed();
+}
+
+void KFilePropsPlugin::determineRelativePath( const QString & path )
+{
+ // now let's make it relative
+ QStringList dirs;
+ if (KBindingPropsPlugin::supports(properties->items()))
+ {
+ m_sRelativePath =KGlobal::dirs()->relativeLocation("mime", path);
+ if (m_sRelativePath.startsWith("/"))
+ m_sRelativePath = QString::null;
+ }
+ else
+ {
+ m_sRelativePath =KGlobal::dirs()->relativeLocation("apps", path);
+ if (m_sRelativePath.startsWith("/"))
+ {
+ m_sRelativePath =KGlobal::dirs()->relativeLocation("xdgdata-apps", path);
+ if (m_sRelativePath.startsWith("/"))
+ m_sRelativePath = QString::null;
+ else
+ m_sRelativePath = path;
+ }
+ }
+ if ( m_sRelativePath.isEmpty() )
+ {
+ if (KBindingPropsPlugin::supports(properties->items()))
+ kdWarning(250) << "Warning : editing a mimetype file out of the mimetype dirs!" << endl;
+ }
+}
+
+void KFilePropsPlugin::slotFoundMountPoint( const QString&,
+ unsigned long kBSize,
+ unsigned long /*kBUsed*/,
+ unsigned long kBAvail )
+{
+ d->m_freeSpaceLabel->setText(
+ // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part.
+ i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)")
+ .arg(KIO::convertSizeFromKB(kBAvail))
+ .arg(KIO::convertSizeFromKB(kBSize))
+ .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
+}
+
+// attention: copy&paste below, due to compiler bug
+// it doesn't like those unsigned long parameters -- unsigned long& are ok :-/
+void KFilePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize,
+ const unsigned long& /*kBUsed*/,
+ const unsigned long& kBAvail,
+ const QString& )
+{
+ d->m_freeSpaceLabel->setText(
+ // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part.
+ i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)")
+ .arg(KIO::convertSizeFromKB(kBAvail))
+ .arg(KIO::convertSizeFromKB(kBSize))
+ .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
+}
+
+void KFilePropsPlugin::slotDirSizeUpdate()
+{
+ KIO::filesize_t totalSize = d->dirSizeJob->totalSize();
+ KIO::filesize_t totalFiles = d->dirSizeJob->totalFiles();
+ KIO::filesize_t totalSubdirs = d->dirSizeJob->totalSubdirs();
+ m_sizeLabel->setText( i18n("Calculating... %1 (%2)\n%3, %4")
+ .arg(KIO::convertSize(totalSize))
+ .arg(KGlobal::locale()->formatNumber(totalSize, 0))
+ .arg(i18n("1 file","%n files",totalFiles))
+ .arg(i18n("1 sub-folder","%n sub-folders",totalSubdirs)));
+}
+
+void KFilePropsPlugin::slotDirSizeFinished( KIO::Job * job )
+{
+ if (job->error())
+ m_sizeLabel->setText( job->errorString() );
+ else
+ {
+ KIO::filesize_t totalSize = static_cast<KDirSize*>(job)->totalSize();
+ KIO::filesize_t totalFiles = static_cast<KDirSize*>(job)->totalFiles();
+ KIO::filesize_t totalSubdirs = static_cast<KDirSize*>(job)->totalSubdirs();
+ m_sizeLabel->setText( QString::fromLatin1("%1 (%2)\n%3, %4")
+ .arg(KIO::convertSize(totalSize))
+ .arg(KGlobal::locale()->formatNumber(totalSize, 0))
+ .arg(i18n("1 file","%n files",totalFiles))
+ .arg(i18n("1 sub-folder","%n sub-folders",totalSubdirs)));
+ }
+ m_sizeStopButton->setEnabled(false);
+ // just in case you change something and try again :)
+ m_sizeDetermineButton->setText( i18n("Refresh") );
+ m_sizeDetermineButton->setEnabled(true);
+ d->dirSizeJob = 0L;
+ delete d->dirSizeUpdateTimer;
+ d->dirSizeUpdateTimer = 0L;
+}
+
+void KFilePropsPlugin::slotSizeDetermine()
+{
+ m_sizeLabel->setText( i18n("Calculating...") );
+ kdDebug(250) << " KFilePropsPlugin::slotSizeDetermine() properties->item()=" << properties->item() << endl;
+ kdDebug(250) << " URL=" << properties->item()->url().url() << endl;
+ d->dirSizeJob = KDirSize::dirSizeJob( properties->items() );
+ d->dirSizeUpdateTimer = new QTimer(this);
+ connect( d->dirSizeUpdateTimer, SIGNAL( timeout() ),
+ SLOT( slotDirSizeUpdate() ) );
+ d->dirSizeUpdateTimer->start(500);
+ connect( d->dirSizeJob, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotDirSizeFinished( KIO::Job * ) ) );
+ m_sizeStopButton->setEnabled(true);
+ m_sizeDetermineButton->setEnabled(false);
+
+ // also update the "Free disk space" display
+ if ( d->m_freeSpaceLabel )
+ {
+ bool isLocal;
+ KFileItem * item = properties->item();
+ KURL url = item->mostLocalURL( isLocal );
+ QString mountPoint = KIO::findPathMountPoint( url.path() );
+
+ KDiskFreeSp * job = new KDiskFreeSp;
+ connect( job, SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const QString& ) ),
+ this, SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const QString& ) ) );
+ job->readDF( mountPoint );
+ }
+}
+
+void KFilePropsPlugin::slotSizeStop()
+{
+ if ( d->dirSizeJob )
+ {
+ m_sizeLabel->setText( i18n("Stopped") );
+ d->dirSizeJob->kill();
+ d->dirSizeJob = 0;
+ }
+ if ( d->dirSizeUpdateTimer )
+ d->dirSizeUpdateTimer->stop();
+
+ m_sizeStopButton->setEnabled(false);
+ m_sizeDetermineButton->setEnabled(true);
+}
+
+KFilePropsPlugin::~KFilePropsPlugin()
+{
+ delete d;
+}
+
+bool KFilePropsPlugin::supports( KFileItemList /*_items*/ )
+{
+ return true;
+}
+
+// Don't do this at home
+void qt_enter_modal( QWidget *widget );
+void qt_leave_modal( QWidget *widget );
+
+void KFilePropsPlugin::applyChanges()
+{
+ if ( d->dirSizeJob )
+ slotSizeStop();
+
+ kdDebug(250) << "KFilePropsPlugin::applyChanges" << endl;
+
+ if (nameArea->inherits("QLineEdit"))
+ {
+ QString n = ((QLineEdit *) nameArea)->text();
+ // Remove trailing spaces (#4345)
+ while ( n[n.length()-1].isSpace() )
+ n.truncate( n.length() - 1 );
+ if ( n.isEmpty() )
+ {
+ KMessageBox::sorry( properties, i18n("The new file name is empty."));
+ properties->abortApplying();
+ return;
+ }
+
+ // Do we need to rename the file ?
+ kdDebug(250) << "oldname = " << oldName << endl;
+ kdDebug(250) << "newname = " << n << endl;
+ if ( oldName != n || m_bFromTemplate ) { // true for any from-template file
+ KIO::Job * job = 0L;
+ KURL oldurl = properties->kurl();
+
+ QString newFileName = KIO::encodeFileName(n);
+ if (d->bDesktopFile && !newFileName.endsWith(".desktop") && !newFileName.endsWith(".kdelnk"))
+ newFileName += ".desktop";
+
+ // Tell properties. Warning, this changes the result of properties->kurl() !
+ properties->rename( newFileName );
+
+ // Update also relative path (for apps and mimetypes)
+ if ( !m_sRelativePath.isEmpty() )
+ determineRelativePath( properties->kurl().path() );
+
+ kdDebug(250) << "New URL = " << properties->kurl().url() << endl;
+ kdDebug(250) << "old = " << oldurl.url() << endl;
+
+ // Don't remove the template !!
+ if ( !m_bFromTemplate ) // (normal renaming)
+ job = KIO::move( oldurl, properties->kurl() );
+ else // Copying a template
+ job = KIO::copy( oldurl, properties->kurl() );
+
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotCopyFinished( KIO::Job * ) ) );
+ connect( job, SIGNAL( renamed( KIO::Job *, const KURL &, const KURL & ) ),
+ SLOT( slotFileRenamed( KIO::Job *, const KURL &, const KURL & ) ) );
+ // wait for job
+ QWidget dummy(0,0,WType_Dialog|WShowModal);
+ qt_enter_modal(&dummy);
+ qApp->enter_loop();
+ qt_leave_modal(&dummy);
+ return;
+ }
+ properties->updateUrl(properties->kurl());
+ // Update also relative path (for apps and mimetypes)
+ if ( !m_sRelativePath.isEmpty() )
+ determineRelativePath( properties->kurl().path() );
+ }
+
+ // No job, keep going
+ slotCopyFinished( 0L );
+}
+
+void KFilePropsPlugin::slotCopyFinished( KIO::Job * job )
+{
+ kdDebug(250) << "KFilePropsPlugin::slotCopyFinished" << endl;
+ if (job)
+ {
+ // allow apply() to return
+ qApp->exit_loop();
+ if ( job->error() )
+ {
+ job->showErrorDialog( d->m_frame );
+ // Didn't work. Revert the URL to the old one
+ properties->updateUrl( static_cast<KIO::CopyJob*>(job)->srcURLs().first() );
+ properties->abortApplying(); // Don't apply the changes to the wrong file !
+ return;
+ }
+ }
+
+ assert( properties->item() );
+ assert( !properties->item()->url().isEmpty() );
+
+ // Save the file where we can -> usually in ~/.kde/...
+ if (KBindingPropsPlugin::supports(properties->items()) && !m_sRelativePath.isEmpty())
+ {
+ KURL newURL;
+ newURL.setPath( locateLocal("mime", m_sRelativePath) );
+ properties->updateUrl( newURL );
+ }
+ else if (d->bDesktopFile && !m_sRelativePath.isEmpty())
+ {
+ kdDebug(250) << "KFilePropsPlugin::slotCopyFinished " << m_sRelativePath << endl;
+ KURL newURL;
+ newURL.setPath( KDesktopFile::locateLocal(m_sRelativePath) );
+ kdDebug(250) << "KFilePropsPlugin::slotCopyFinished path=" << newURL.path() << endl;
+ properties->updateUrl( newURL );
+ }
+
+ if ( d->bKDesktopMode && d->bDesktopFile ) {
+ // Renamed? Update Name field
+ if ( d->oldFileName != properties->kurl().fileName() || m_bFromTemplate ) {
+ KDesktopFile config( properties->kurl().path() );
+ QString nameStr = nameFromFileName(properties->kurl().fileName());
+ config.writeEntry( "Name", nameStr );
+ config.writeEntry( "Name", nameStr, true, false, true );
+ }
+ }
+}
+
+void KFilePropsPlugin::applyIconChanges()
+{
+ KIconButton *iconButton = ::qt_cast<KIconButton *>( iconArea );
+ if ( !iconButton || !d->bIconChanged )
+ return;
+ // handle icon changes - only local files (or pseudo-local) for now
+ // TODO: Use KTempFile and KIO::file_copy with overwrite = true
+ KURL url = properties->kurl();
+ url = KIO::NetAccess::mostLocalURL( url, properties );
+ if (url.isLocalFile()) {
+ QString path;
+
+ if (S_ISDIR(properties->item()->mode()))
+ {
+ path = url.path(1) + QString::fromLatin1(".directory");
+ // don't call updateUrl because the other tabs (i.e. permissions)
+ // apply to the directory, not the .directory file.
+ }
+ else
+ path = url.path();
+
+ // Get the default image
+ QString str = KMimeType::findByURL( url,
+ properties->item()->mode(),
+ true )->KServiceType::icon();
+ // Is it another one than the default ?
+ QString sIcon;
+ if ( str != iconButton->icon() )
+ sIcon = iconButton->icon();
+ // (otherwise write empty value)
+
+ kdDebug(250) << "**" << path << "**" << endl;
+ QFile f( path );
+
+ // If default icon and no .directory file -> don't create one
+ if ( !sIcon.isEmpty() || f.exists() )
+ {
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not "
+ "have sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KDesktopFile cfg(path);
+ kdDebug(250) << "sIcon = " << (sIcon) << endl;
+ kdDebug(250) << "str = " << (str) << endl;
+ cfg.writeEntry( "Icon", sIcon );
+ cfg.sync();
+ }
+ }
+}
+
+void KFilePropsPlugin::slotFileRenamed( KIO::Job *, const KURL &, const KURL & newUrl )
+{
+ // This is called in case of an existing local file during the copy/move operation,
+ // if the user chooses Rename.
+ properties->updateUrl( newUrl );
+}
+
+void KFilePropsPlugin::postApplyChanges()
+{
+ // Save the icon only after applying the permissions changes (#46192)
+ applyIconChanges();
+
+ KURL::List lst;
+ KFileItemList items = properties->items();
+ for ( KFileItemListIterator it( items ); it.current(); ++it )
+ lst.append((*it)->url());
+ KDirNotify_stub allDirNotify("*", "KDirNotify*");
+ allDirNotify.FilesChanged( lst );
+}
+
+class KFilePermissionsPropsPlugin::KFilePermissionsPropsPluginPrivate
+{
+public:
+ KFilePermissionsPropsPluginPrivate()
+ {
+ }
+ ~KFilePermissionsPropsPluginPrivate()
+ {
+ }
+
+ QFrame *m_frame;
+ QCheckBox *cbRecursive;
+ QLabel *explanationLabel;
+ QComboBox *ownerPermCombo, *groupPermCombo, *othersPermCombo;
+ QCheckBox *extraCheckbox;
+ mode_t partialPermissions;
+ KFilePermissionsPropsPlugin::PermissionsMode pmode;
+ bool canChangePermissions;
+ bool isIrregular;
+ bool hasExtendedACL;
+ KACL extendedACL;
+ KACL defaultACL;
+ bool fileSystemSupportsACLs;
+};
+
+#define UniOwner (S_IRUSR|S_IWUSR|S_IXUSR)
+#define UniGroup (S_IRGRP|S_IWGRP|S_IXGRP)
+#define UniOthers (S_IROTH|S_IWOTH|S_IXOTH)
+#define UniRead (S_IRUSR|S_IRGRP|S_IROTH)
+#define UniWrite (S_IWUSR|S_IWGRP|S_IWOTH)
+#define UniExec (S_IXUSR|S_IXGRP|S_IXOTH)
+#define UniSpecial (S_ISUID|S_ISGID|S_ISVTX)
+
+// synced with PermissionsTarget
+const mode_t KFilePermissionsPropsPlugin::permissionsMasks[3] = {UniOwner, UniGroup, UniOthers};
+const mode_t KFilePermissionsPropsPlugin::standardPermissions[4] = { 0, UniRead, UniRead|UniWrite, (mode_t)-1 };
+
+// synced with PermissionsMode and standardPermissions
+const char *KFilePermissionsPropsPlugin::permissionsTexts[4][4] = {
+ { I18N_NOOP("Forbidden"),
+ I18N_NOOP("Can Read"),
+ I18N_NOOP("Can Read & Write"),
+ 0 },
+ { I18N_NOOP("Forbidden"),
+ I18N_NOOP("Can View Content"),
+ I18N_NOOP("Can View & Modify Content"),
+ 0 },
+ { 0, 0, 0, 0}, // no texts for links
+ { I18N_NOOP("Forbidden"),
+ I18N_NOOP("Can View Content & Read"),
+ I18N_NOOP("Can View/Read & Modify/Write"),
+ 0 }
+};
+
+
+KFilePermissionsPropsPlugin::KFilePermissionsPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new KFilePermissionsPropsPluginPrivate;
+ d->cbRecursive = 0L;
+ grpCombo = 0L; grpEdit = 0;
+ usrEdit = 0L;
+ QString path = properties->kurl().path(-1);
+ QString fname = properties->kurl().fileName();
+ bool isLocal = properties->kurl().isLocalFile();
+ bool isTrash = ( properties->kurl().protocol().find("trash", 0, false)==0 );
+ bool IamRoot = (geteuid() == 0);
+
+ KFileItem * item = properties->item();
+ bool isLink = item->isLink();
+ bool isDir = item->isDir(); // all dirs
+ bool hasDir = item->isDir(); // at least one dir
+ permissions = item->permissions(); // common permissions to all files
+ d->partialPermissions = permissions; // permissions that only some files have (at first we take everything)
+ d->isIrregular = isIrregular(permissions, isDir, isLink);
+ strOwner = item->user();
+ strGroup = item->group();
+ d->hasExtendedACL = item->ACL().isExtended() || item->defaultACL().isValid();
+ d->extendedACL = item->ACL();
+ d->defaultACL = item->defaultACL();
+ d->fileSystemSupportsACLs = false;
+
+ if ( properties->items().count() > 1 )
+ {
+ // Multiple items: see what they have in common
+ KFileItemList items = properties->items();
+ KFileItemListIterator it( items );
+ for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
+ {
+ if (!d->isIrregular)
+ d->isIrregular |= isIrregular((*it)->permissions(),
+ (*it)->isDir() == isDir,
+ (*it)->isLink() == isLink);
+ d->hasExtendedACL = d->hasExtendedACL || (*it)->hasExtendedACL();
+ if ( (*it)->isLink() != isLink )
+ isLink = false;
+ if ( (*it)->isDir() != isDir )
+ isDir = false;
+ hasDir |= (*it)->isDir();
+ if ( (*it)->permissions() != permissions )
+ {
+ permissions &= (*it)->permissions();
+ d->partialPermissions |= (*it)->permissions();
+ }
+ if ( (*it)->user() != strOwner )
+ strOwner = QString::null;
+ if ( (*it)->group() != strGroup )
+ strGroup = QString::null;
+ }
+ }
+
+ if (isLink)
+ d->pmode = PermissionsOnlyLinks;
+ else if (isDir)
+ d->pmode = PermissionsOnlyDirs;
+ else if (hasDir)
+ d->pmode = PermissionsMixed;
+ else
+ d->pmode = PermissionsOnlyFiles;
+
+ // keep only what's not in the common permissions
+ d->partialPermissions = d->partialPermissions & ~permissions;
+
+ bool isMyFile = false;
+
+ if (isLocal && !strOwner.isEmpty()) { // local files, and all owned by the same person
+ struct passwd *myself = getpwuid( geteuid() );
+ if ( myself != 0L )
+ {
+ isMyFile = (strOwner == QString::fromLocal8Bit(myself->pw_name));
+ } else
+ kdWarning() << "I don't exist ?! geteuid=" << geteuid() << endl;
+ } else {
+ //We don't know, for remote files, if they are ours or not.
+ //So we let the user change permissions, and
+ //KIO::chmod will tell, if he had no right to do it.
+ isMyFile = true;
+ }
+
+ d->canChangePermissions = (isMyFile || IamRoot) && (!isLink);
+
+
+ // create GUI
+
+ d->m_frame = properties->addPage(i18n("&Permissions"));
+
+ QBoxLayout *box = new QVBoxLayout( d->m_frame, 0, KDialog::spacingHint() );
+
+ QWidget *l;
+ QLabel *lbl;
+ QGroupBox *gb;
+ QGridLayout *gl;
+ QPushButton* pbAdvancedPerm = 0;
+
+ /* Group: Access Permissions */
+ gb = new QGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), d->m_frame );
+ gb->layout()->setSpacing(KDialog::spacingHint());
+ gb->layout()->setMargin(KDialog::marginHint());
+ box->addWidget (gb);
+
+ gl = new QGridLayout (gb->layout(), 7, 2);
+ gl->setColStretch(1, 1);
+
+ l = d->explanationLabel = new QLabel( "", gb );
+ if (isLink)
+ d->explanationLabel->setText(i18n("This file is a link and does not have permissions.",
+ "All files are links and do not have permissions.",
+ properties->items().count()));
+ else if (!d->canChangePermissions)
+ d->explanationLabel->setText(i18n("Only the owner can change permissions."));
+ gl->addMultiCellWidget(l, 0, 0, 0, 1);
+
+ lbl = new QLabel( i18n("O&wner:"), gb);
+ gl->addWidget(lbl, 1, 0);
+ l = d->ownerPermCombo = new QComboBox(gb);
+ lbl->setBuddy(l);
+ gl->addWidget(l, 1, 1);
+ connect(l, SIGNAL( highlighted(int) ), this, SIGNAL( changed() ));
+ QWhatsThis::add(l, i18n("Specifies the actions that the owner is allowed to do."));
+
+ lbl = new QLabel( i18n("Gro&up:"), gb);
+ gl->addWidget(lbl, 2, 0);
+ l = d->groupPermCombo = new QComboBox(gb);
+ lbl->setBuddy(l);
+ gl->addWidget(l, 2, 1);
+ connect(l, SIGNAL( highlighted(int) ), this, SIGNAL( changed() ));
+ QWhatsThis::add(l, i18n("Specifies the actions that the members of the group are allowed to do."));
+
+ lbl = new QLabel( i18n("O&thers:"), gb);
+ gl->addWidget(lbl, 3, 0);
+ l = d->othersPermCombo = new QComboBox(gb);
+ lbl->setBuddy(l);
+ gl->addWidget(l, 3, 1);
+ connect(l, SIGNAL( highlighted(int) ), this, SIGNAL( changed() ));
+ QWhatsThis::add(l, i18n("Specifies the actions that all users, who are neither "
+ "owner nor in the group, are allowed to do."));
+
+ if (!isLink) {
+ l = d->extraCheckbox = new QCheckBox(hasDir ?
+ i18n("Only own&er can rename and delete folder content") :
+ i18n("Is &executable"),
+ gb );
+ connect( d->extraCheckbox, SIGNAL( clicked() ), this, SIGNAL( changed() ) );
+ gl->addWidget(l, 4, 1);
+ QWhatsThis::add(l, hasDir ? i18n("Enable this option to allow only the folder's owner to "
+ "delete or rename the contained files and folders. Other "
+ "users can only add new files, which requires the 'Modify "
+ "Content' permission.")
+ : i18n("Enable this option to mark the file as executable. This only makes "
+ "sense for programs and scripts. It is required when you want to "
+ "execute them."));
+
+ QLayoutItem *spacer = new QSpacerItem(0, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
+ gl->addMultiCell(spacer, 5, 5, 0, 1);
+
+ pbAdvancedPerm = new QPushButton(i18n("A&dvanced Permissions"), gb);
+ gl->addMultiCellWidget(pbAdvancedPerm, 6, 6, 0, 1, AlignRight);
+ connect(pbAdvancedPerm, SIGNAL( clicked() ), this, SLOT( slotShowAdvancedPermissions() ));
+ }
+ else
+ d->extraCheckbox = 0;
+
+
+ /**** Group: Ownership ****/
+ gb = new QGroupBox ( 0, Qt::Vertical, i18n("Ownership"), d->m_frame );
+ gb->layout()->setSpacing(KDialog::spacingHint());
+ gb->layout()->setMargin(KDialog::marginHint());
+ box->addWidget (gb);
+
+ gl = new QGridLayout (gb->layout(), 4, 3);
+ gl->addRowSpacing(0, 10);
+
+ /*** Set Owner ***/
+ l = new QLabel( i18n("User:"), gb );
+ gl->addWidget (l, 1, 0);
+
+ /* GJ: Don't autocomplete more than 1000 users. This is a kind of random
+ * value. Huge sites having 10.000+ user have a fair chance of using NIS,
+ * (possibly) making this unacceptably slow.
+ * OTOH, it is nice to offer this functionality for the standard user.
+ */
+ int i, maxEntries = 1000;
+ struct passwd *user;
+ struct group *ge;
+
+ /* File owner: For root, offer a KLineEdit with autocompletion.
+ * For a user, who can never chown() a file, offer a QLabel.
+ */
+ if (IamRoot && isLocal)
+ {
+ usrEdit = new KLineEdit( gb );
+ KCompletion *kcom = usrEdit->completionObject();
+ kcom->setOrder(KCompletion::Sorted);
+ setpwent();
+ for (i=0; ((user = getpwent()) != 0L) && (i < maxEntries); i++)
+ kcom->addItem(QString::fromLatin1(user->pw_name));
+ endpwent();
+ usrEdit->setCompletionMode((i < maxEntries) ? KGlobalSettings::CompletionAuto :
+ KGlobalSettings::CompletionNone);
+ usrEdit->setText(strOwner);
+ gl->addWidget(usrEdit, 1, 1);
+ connect( usrEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ }
+ else
+ {
+ l = new QLabel(strOwner, gb);
+ gl->addWidget(l, 1, 1);
+ }
+
+ /*** Set Group ***/
+
+ QStringList groupList;
+ QCString strUser;
+ user = getpwuid(geteuid());
+ if (user != 0L)
+ strUser = user->pw_name;
+
+#ifdef Q_OS_UNIX
+ setgrent();
+ for (i=0; ((ge = getgrent()) != 0L) && (i < maxEntries); i++)
+ {
+ if (IamRoot)
+ groupList += QString::fromLatin1(ge->gr_name);
+ else
+ {
+ /* pick the groups to which the user belongs */
+ char ** members = ge->gr_mem;
+ char * member;
+ while ((member = *members) != 0L) {
+ if (strUser == member) {
+ groupList += QString::fromLocal8Bit(ge->gr_name);
+ break;
+ }
+ ++members;
+ }
+ }
+ }
+ endgrent();
+#endif //Q_OS_UNIX
+
+ /* add the effective Group to the list .. */
+ ge = getgrgid (getegid());
+ if (ge) {
+ QString name = QString::fromLatin1(ge->gr_name);
+ if (name.isEmpty())
+ name.setNum(ge->gr_gid);
+ if (groupList.find(name) == groupList.end())
+ groupList += name;
+ }
+
+ bool isMyGroup = groupList.contains(strGroup);
+
+ /* add the group the file currently belongs to ..
+ * .. if its not there already
+ */
+ if (!isMyGroup)
+ groupList += strGroup;
+
+ l = new QLabel( i18n("Group:"), gb );
+ gl->addWidget (l, 2, 0);
+
+ /* Set group: if possible to change:
+ * - Offer a KLineEdit for root, since he can change to any group.
+ * - Offer a QComboBox for a normal user, since he can change to a fixed
+ * (small) set of groups only.
+ * If not changeable: offer a QLabel.
+ */
+ if (IamRoot && isLocal)
+ {
+ grpEdit = new KLineEdit(gb);
+ KCompletion *kcom = new KCompletion;
+ kcom->setItems(groupList);
+ grpEdit->setCompletionObject(kcom, true);
+ grpEdit->setAutoDeleteCompletionObject( true );
+ grpEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
+ grpEdit->setText(strGroup);
+ gl->addWidget(grpEdit, 2, 1);
+ connect( grpEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ }
+ else if ((groupList.count() > 1) && isMyFile && isLocal)
+ {
+ grpCombo = new QComboBox(gb, "combogrouplist");
+ grpCombo->insertStringList(groupList);
+ grpCombo->setCurrentItem(groupList.findIndex(strGroup));
+ gl->addWidget(grpCombo, 2, 1);
+ connect( grpCombo, SIGNAL( activated( int ) ),
+ this, SIGNAL( changed() ) );
+ }
+ else
+ {
+ l = new QLabel(strGroup, gb);
+ gl->addWidget(l, 2, 1);
+ }
+
+ gl->setColStretch(2, 10);
+
+ // "Apply recursive" checkbox
+ if ( hasDir && !isLink && !isTrash )
+ {
+ d->cbRecursive = new QCheckBox( i18n("Apply changes to all subfolders and their contents"), d->m_frame );
+ connect( d->cbRecursive, SIGNAL( clicked() ), this, SIGNAL( changed() ) );
+ box->addWidget( d->cbRecursive );
+ }
+
+ updateAccessControls();
+
+
+ if ( isTrash || !d->canChangePermissions )
+ {
+ //don't allow to change properties for file into trash
+ enableAccessControls(false);
+ if ( pbAdvancedPerm && !d->hasExtendedACL )
+ pbAdvancedPerm->setEnabled(false);
+ }
+
+ box->addStretch (10);
+}
+
+#ifdef USE_POSIX_ACL
+static bool fileSystemSupportsACL( const QCString& pathCString )
+{
+ bool fileSystemSupportsACLs = false;
+#ifdef Q_OS_FREEBSD
+ struct statfs buf;
+ fileSystemSupportsACLs = ( statfs( pathCString.data(), &buf ) == 0 ) && ( buf.f_flags & MNT_ACLS );
+#else
+ fileSystemSupportsACLs =
+ getxattr( pathCString.data(), "system.posix_acl_access", NULL, 0 ) >= 0 || errno == ENODATA;
+#endif
+ return fileSystemSupportsACLs;
+}
+#endif
+
+
+void KFilePermissionsPropsPlugin::slotShowAdvancedPermissions() {
+
+ bool isDir = (d->pmode == PermissionsOnlyDirs) || (d->pmode == PermissionsMixed);
+ KDialogBase dlg(properties, 0, true, i18n("Advanced Permissions"),
+ KDialogBase::Ok|KDialogBase::Cancel);
+
+ QLabel *l, *cl[3];
+ QGroupBox *gb;
+ QGridLayout *gl;
+
+ QVBox *mainVBox = dlg.makeVBoxMainWidget();
+
+ // Group: Access Permissions
+ gb = new QGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), mainVBox );
+ gb->layout()->setSpacing(KDialog::spacingHint());
+ gb->layout()->setMargin(KDialog::marginHint());
+
+ gl = new QGridLayout (gb->layout(), 6, 6);
+ gl->addRowSpacing(0, 10);
+
+ QValueVector<QWidget*> theNotSpecials;
+
+ l = new QLabel(i18n("Class"), gb );
+ gl->addWidget(l, 1, 0);
+ theNotSpecials.append( l );
+
+ if (isDir)
+ l = new QLabel( i18n("Show\nEntries"), gb );
+ else
+ l = new QLabel( i18n("Read"), gb );
+ gl->addWidget (l, 1, 1);
+ theNotSpecials.append( l );
+ QString readWhatsThis;
+ if (isDir)
+ readWhatsThis = i18n("This flag allows viewing the content of the folder.");
+ else
+ readWhatsThis = i18n("The Read flag allows viewing the content of the file.");
+ QWhatsThis::add(l, readWhatsThis);
+
+ if (isDir)
+ l = new QLabel( i18n("Write\nEntries"), gb );
+ else
+ l = new QLabel( i18n("Write"), gb );
+ gl->addWidget (l, 1, 2);
+ theNotSpecials.append( l );
+ QString writeWhatsThis;
+ if (isDir)
+ writeWhatsThis = i18n("This flag allows adding, renaming and deleting of files. "
+ "Note that deleting and renaming can be limited using the Sticky flag.");
+ else
+ writeWhatsThis = i18n("The Write flag allows modifying the content of the file.");
+ QWhatsThis::add(l, writeWhatsThis);
+
+ QString execWhatsThis;
+ if (isDir) {
+ l = new QLabel( i18n("Enter folder", "Enter"), gb );
+ execWhatsThis = i18n("Enable this flag to allow entering the folder.");
+ }
+ else {
+ l = new QLabel( i18n("Exec"), gb );
+ execWhatsThis = i18n("Enable this flag to allow executing the file as a program.");
+ }
+ QWhatsThis::add(l, execWhatsThis);
+ theNotSpecials.append( l );
+ // GJ: Add space between normal and special modes
+ QSize size = l->sizeHint();
+ size.setWidth(size.width() + 15);
+ l->setFixedSize(size);
+ gl->addWidget (l, 1, 3);
+
+ l = new QLabel( i18n("Special"), gb );
+ gl->addMultiCellWidget(l, 1, 1, 4, 5);
+ QString specialWhatsThis;
+ if (isDir)
+ specialWhatsThis = i18n("Special flag. Valid for the whole folder, the exact "
+ "meaning of the flag can be seen in the right hand column.");
+ else
+ specialWhatsThis = i18n("Special flag. The exact meaning of the flag can be seen "
+ "in the right hand column.");
+ QWhatsThis::add(l, specialWhatsThis);
+
+ cl[0] = new QLabel( i18n("User"), gb );
+ gl->addWidget (cl[0], 2, 0);
+ theNotSpecials.append( cl[0] );
+
+ cl[1] = new QLabel( i18n("Group"), gb );
+ gl->addWidget (cl[1], 3, 0);
+ theNotSpecials.append( cl[1] );
+
+ cl[2] = new QLabel( i18n("Others"), gb );
+ gl->addWidget (cl[2], 4, 0);
+ theNotSpecials.append( cl[2] );
+
+ l = new QLabel(i18n("Set UID"), gb);
+ gl->addWidget(l, 2, 5);
+ QString setUidWhatsThis;
+ if (isDir)
+ setUidWhatsThis = i18n("If this flag is set, the owner of this folder will be "
+ "the owner of all new files.");
+ else
+ setUidWhatsThis = i18n("If this file is an executable and the flag is set, it will "
+ "be executed with the permissions of the owner.");
+ QWhatsThis::add(l, setUidWhatsThis);
+
+ l = new QLabel(i18n("Set GID"), gb);
+ gl->addWidget(l, 3, 5);
+ QString setGidWhatsThis;
+ if (isDir)
+ setGidWhatsThis = i18n("If this flag is set, the group of this folder will be "
+ "set for all new files.");
+ else
+ setGidWhatsThis = i18n("If this file is an executable and the flag is set, it will "
+ "be executed with the permissions of the group.");
+ QWhatsThis::add(l, setGidWhatsThis);
+
+ l = new QLabel(i18n("File permission", "Sticky"), gb);
+ gl->addWidget(l, 4, 5);
+ QString stickyWhatsThis;
+ if (isDir)
+ stickyWhatsThis = i18n("If the Sticky flag is set on a folder, only the owner "
+ "and root can delete or rename files. Otherwise everybody "
+ "with write permissions can do this.");
+ else
+ stickyWhatsThis = i18n("The Sticky flag on a file is ignored on Linux, but may "
+ "be used on some systems");
+ QWhatsThis::add(l, stickyWhatsThis);
+
+ mode_t aPermissions, aPartialPermissions;
+ mode_t dummy1, dummy2;
+
+ if (!d->isIrregular) {
+ switch (d->pmode) {
+ case PermissionsOnlyFiles:
+ getPermissionMasks(aPartialPermissions,
+ dummy1,
+ aPermissions,
+ dummy2);
+ break;
+ case PermissionsOnlyDirs:
+ case PermissionsMixed:
+ getPermissionMasks(dummy1,
+ aPartialPermissions,
+ dummy2,
+ aPermissions);
+ break;
+ case PermissionsOnlyLinks:
+ aPermissions = UniRead | UniWrite | UniExec | UniSpecial;
+ aPartialPermissions = 0;
+ break;
+ }
+ }
+ else {
+ aPermissions = permissions;
+ aPartialPermissions = d->partialPermissions;
+ }
+
+ // Draw Checkboxes
+ QCheckBox *cba[3][4];
+ for (int row = 0; row < 3 ; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ QCheckBox *cb = new QCheckBox( gb );
+ if ( col != 3 ) theNotSpecials.append( cb );
+ cba[row][col] = cb;
+ cb->setChecked(aPermissions & fperm[row][col]);
+ if ( aPartialPermissions & fperm[row][col] )
+ {
+ cb->setTristate();
+ cb->setNoChange();
+ }
+ else if (d->cbRecursive && d->cbRecursive->isChecked())
+ cb->setTristate();
+
+ cb->setEnabled( d->canChangePermissions );
+ gl->addWidget (cb, row+2, col+1);
+ switch(col) {
+ case 0:
+ QWhatsThis::add(cb, readWhatsThis);
+ break;
+ case 1:
+ QWhatsThis::add(cb, writeWhatsThis);
+ break;
+ case 2:
+ QWhatsThis::add(cb, execWhatsThis);
+ break;
+ case 3:
+ switch(row) {
+ case 0:
+ QWhatsThis::add(cb, setUidWhatsThis);
+ break;
+ case 1:
+ QWhatsThis::add(cb, setGidWhatsThis);
+ break;
+ case 2:
+ QWhatsThis::add(cb, stickyWhatsThis);
+ break;
+ }
+ break;
+ }
+ }
+ }
+ gl->setColStretch(6, 10);
+
+#ifdef USE_POSIX_ACL
+ KACLEditWidget *extendedACLs = 0;
+
+ // FIXME make it work with partial entries
+ if ( properties->items().count() == 1 ) {
+ QCString pathCString = QFile::encodeName( properties->item()->url().path() );
+ d->fileSystemSupportsACLs = fileSystemSupportsACL( pathCString );
+ }
+ if ( d->fileSystemSupportsACLs ) {
+ std::for_each( theNotSpecials.begin(), theNotSpecials.end(), std::mem_fun( &QWidget::hide ) );
+ extendedACLs = new KACLEditWidget( mainVBox );
+ if ( d->extendedACL.isValid() && d->extendedACL.isExtended() )
+ extendedACLs->setACL( d->extendedACL );
+ else
+ extendedACLs->setACL( KACL( aPermissions ) );
+
+ if ( d->defaultACL.isValid() )
+ extendedACLs->setDefaultACL( d->defaultACL );
+
+ if ( properties->items().first()->isDir() )
+ extendedACLs->setAllowDefaults( true );
+ if ( !d->canChangePermissions )
+ extendedACLs->setReadOnly( true );
+
+ }
+#endif
+ if (dlg.exec() != KDialogBase::Accepted)
+ return;
+
+ mode_t andPermissions = mode_t(~0);
+ mode_t orPermissions = 0;
+ for (int row = 0; row < 3; ++row)
+ for (int col = 0; col < 4; ++col) {
+ switch (cba[row][col]->state())
+ {
+ case QCheckBox::On:
+ orPermissions |= fperm[row][col];
+ //fall through
+ case QCheckBox::Off:
+ andPermissions &= ~fperm[row][col];
+ break;
+ default: // NoChange
+ break;
+ }
+ }
+
+ d->isIrregular = false;
+ KFileItemList items = properties->items();
+ for (KFileItemListIterator it(items); it.current(); ++it) {
+ if (isIrregular(((*it)->permissions() & andPermissions) | orPermissions,
+ (*it)->isDir(), (*it)->isLink())) {
+ d->isIrregular = true;
+ break;
+ }
+ }
+
+ permissions = orPermissions;
+ d->partialPermissions = andPermissions;
+
+#ifdef USE_POSIX_ACL
+ // override with the acls, if present
+ if ( extendedACLs ) {
+ d->extendedACL = extendedACLs->getACL();
+ d->defaultACL = extendedACLs->getDefaultACL();
+ d->hasExtendedACL = d->extendedACL.isExtended() || d->defaultACL.isValid();
+ permissions = d->extendedACL.basePermissions();
+ permissions |= ( andPermissions | orPermissions ) & ( S_ISUID|S_ISGID|S_ISVTX );
+ }
+#endif
+
+ updateAccessControls();
+ emit changed();
+}
+
+// QString KFilePermissionsPropsPlugin::tabName () const
+// {
+// return i18n ("&Permissions");
+// }
+
+KFilePermissionsPropsPlugin::~KFilePermissionsPropsPlugin()
+{
+ delete d;
+}
+
+bool KFilePermissionsPropsPlugin::supports( KFileItemList _items )
+{
+ KFileItemList::const_iterator it = _items.constBegin();
+ for ( ; it != _items.constEnd(); ++it ) {
+ KFileItem *item = *it;
+ if( !item->user().isEmpty() || !item->group().isEmpty() )
+ return true;
+ }
+ return false;
+}
+
+// sets a combo box in the Access Control frame
+void KFilePermissionsPropsPlugin::setComboContent(QComboBox *combo, PermissionsTarget target,
+ mode_t permissions, mode_t partial) {
+ combo->clear();
+ if (d->pmode == PermissionsOnlyLinks) {
+ combo->insertItem(i18n("Link"));
+ combo->setCurrentItem(0);
+ return;
+ }
+
+ mode_t tMask = permissionsMasks[target];
+ int textIndex;
+ for (textIndex = 0; standardPermissions[textIndex] != (mode_t)-1; textIndex++)
+ if ((standardPermissions[textIndex]&tMask) == (permissions&tMask&(UniRead|UniWrite)))
+ break;
+ Q_ASSERT(standardPermissions[textIndex] != (mode_t)-1); // must not happen, would be irreglar
+
+ for (int i = 0; permissionsTexts[(int)d->pmode][i]; i++)
+ combo->insertItem(i18n(permissionsTexts[(int)d->pmode][i]));
+
+ if (partial & tMask & ~UniExec) {
+ combo->insertItem(i18n("Varying (No Change)"));
+ combo->setCurrentItem(3);
+ }
+ else
+ combo->setCurrentItem(textIndex);
+}
+
+// permissions are irregular if they cant be displayed in a combo box.
+bool KFilePermissionsPropsPlugin::isIrregular(mode_t permissions, bool isDir, bool isLink) {
+ if (isLink) // links are always ok
+ return false;
+
+ mode_t p = permissions;
+ if (p & (S_ISUID | S_ISGID)) // setuid/setgid -> irregular
+ return true;
+ if (isDir) {
+ p &= ~S_ISVTX; // ignore sticky on dirs
+
+ // check supported flag combinations
+ mode_t p0 = p & UniOwner;
+ if ((p0 != 0) && (p0 != (S_IRUSR | S_IXUSR)) && (p0 != UniOwner))
+ return true;
+ p0 = p & UniGroup;
+ if ((p0 != 0) && (p0 != (S_IRGRP | S_IXGRP)) && (p0 != UniGroup))
+ return true;
+ p0 = p & UniOthers;
+ if ((p0 != 0) && (p0 != (S_IROTH | S_IXOTH)) && (p0 != UniOthers))
+ return true;
+ return false;
+ }
+ if (p & S_ISVTX) // sticky on file -> irregular
+ return true;
+
+ // check supported flag combinations
+ mode_t p0 = p & UniOwner;
+ bool usrXPossible = !p0; // true if this file could be an executable
+ if (p0 & S_IXUSR) {
+ if ((p0 == S_IXUSR) || (p0 == (S_IWUSR | S_IXUSR)))
+ return true;
+ usrXPossible = true;
+ }
+ else if (p0 == S_IWUSR)
+ return true;
+
+ p0 = p & UniGroup;
+ bool grpXPossible = !p0; // true if this file could be an executable
+ if (p0 & S_IXGRP) {
+ if ((p0 == S_IXGRP) || (p0 == (S_IWGRP | S_IXGRP)))
+ return true;
+ grpXPossible = true;
+ }
+ else if (p0 == S_IWGRP)
+ return true;
+ if (p0 == 0)
+ grpXPossible = true;
+
+ p0 = p & UniOthers;
+ bool othXPossible = !p0; // true if this file could be an executable
+ if (p0 & S_IXOTH) {
+ if ((p0 == S_IXOTH) || (p0 == (S_IWOTH | S_IXOTH)))
+ return true;
+ othXPossible = true;
+ }
+ else if (p0 == S_IWOTH)
+ return true;
+
+ // check that there either all targets are executable-compatible, or none
+ return (p & UniExec) && !(usrXPossible && grpXPossible && othXPossible);
+}
+
+// enables/disabled the widgets in the Access Control frame
+void KFilePermissionsPropsPlugin::enableAccessControls(bool enable) {
+ d->ownerPermCombo->setEnabled(enable);
+ d->groupPermCombo->setEnabled(enable);
+ d->othersPermCombo->setEnabled(enable);
+ if (d->extraCheckbox)
+ d->extraCheckbox->setEnabled(enable);
+ if ( d->cbRecursive )
+ d->cbRecursive->setEnabled(enable);
+}
+
+// updates all widgets in the Access Control frame
+void KFilePermissionsPropsPlugin::updateAccessControls() {
+ setComboContent(d->ownerPermCombo, PermissionsOwner,
+ permissions, d->partialPermissions);
+ setComboContent(d->groupPermCombo, PermissionsGroup,
+ permissions, d->partialPermissions);
+ setComboContent(d->othersPermCombo, PermissionsOthers,
+ permissions, d->partialPermissions);
+
+ switch(d->pmode) {
+ case PermissionsOnlyLinks:
+ enableAccessControls(false);
+ break;
+ case PermissionsOnlyFiles:
+ enableAccessControls(d->canChangePermissions && !d->isIrregular && !d->hasExtendedACL);
+ if (d->canChangePermissions)
+ d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ?
+ i18n("This file uses advanced permissions",
+ "These files use advanced permissions.",
+ properties->items().count()) : "");
+ if (d->partialPermissions & UniExec) {
+ d->extraCheckbox->setTristate();
+ d->extraCheckbox->setNoChange();
+ }
+ else {
+ d->extraCheckbox->setTristate(false);
+ d->extraCheckbox->setChecked(permissions & UniExec);
+ }
+ break;
+ case PermissionsOnlyDirs:
+ enableAccessControls(d->canChangePermissions && !d->isIrregular && !d->hasExtendedACL);
+ // if this is a dir, and we can change permissions, don't dis-allow
+ // recursive, we can do that for ACL setting.
+ if ( d->cbRecursive )
+ d->cbRecursive->setEnabled( d->canChangePermissions && !d->isIrregular );
+
+ if (d->canChangePermissions)
+ d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ?
+ i18n("This folder uses advanced permissions.",
+ "These folders use advanced permissions.",
+ properties->items().count()) : "");
+ if (d->partialPermissions & S_ISVTX) {
+ d->extraCheckbox->setTristate();
+ d->extraCheckbox->setNoChange();
+ }
+ else {
+ d->extraCheckbox->setTristate(false);
+ d->extraCheckbox->setChecked(permissions & S_ISVTX);
+ }
+ break;
+ case PermissionsMixed:
+ enableAccessControls(d->canChangePermissions && !d->isIrregular && !d->hasExtendedACL);
+ if (d->canChangePermissions)
+ d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ?
+ i18n("These files use advanced permissions.") : "");
+ break;
+ if (d->partialPermissions & S_ISVTX) {
+ d->extraCheckbox->setTristate();
+ d->extraCheckbox->setNoChange();
+ }
+ else {
+ d->extraCheckbox->setTristate(false);
+ d->extraCheckbox->setChecked(permissions & S_ISVTX);
+ }
+ break;
+ }
+}
+
+// gets masks for files and dirs from the Access Control frame widgets
+void KFilePermissionsPropsPlugin::getPermissionMasks(mode_t &andFilePermissions,
+ mode_t &andDirPermissions,
+ mode_t &orFilePermissions,
+ mode_t &orDirPermissions) {
+ andFilePermissions = mode_t(~UniSpecial);
+ andDirPermissions = mode_t(~(S_ISUID|S_ISGID));
+ orFilePermissions = 0;
+ orDirPermissions = 0;
+ if (d->isIrregular)
+ return;
+
+ mode_t m = standardPermissions[d->ownerPermCombo->currentItem()];
+ if (m != (mode_t) -1) {
+ orFilePermissions |= m & UniOwner;
+ if ((m & UniOwner) &&
+ ((d->pmode == PermissionsMixed) ||
+ ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange))))
+ andFilePermissions &= ~(S_IRUSR | S_IWUSR);
+ else {
+ andFilePermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR);
+ if ((m & S_IRUSR) && (d->extraCheckbox->state() == QButton::On))
+ orFilePermissions |= S_IXUSR;
+ }
+
+ orDirPermissions |= m & UniOwner;
+ if (m & S_IRUSR)
+ orDirPermissions |= S_IXUSR;
+ andDirPermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR);
+ }
+
+ m = standardPermissions[d->groupPermCombo->currentItem()];
+ if (m != (mode_t) -1) {
+ orFilePermissions |= m & UniGroup;
+ if ((m & UniGroup) &&
+ ((d->pmode == PermissionsMixed) ||
+ ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange))))
+ andFilePermissions &= ~(S_IRGRP | S_IWGRP);
+ else {
+ andFilePermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
+ if ((m & S_IRGRP) && (d->extraCheckbox->state() == QButton::On))
+ orFilePermissions |= S_IXGRP;
+ }
+
+ orDirPermissions |= m & UniGroup;
+ if (m & S_IRGRP)
+ orDirPermissions |= S_IXGRP;
+ andDirPermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
+ }
+
+ m = standardPermissions[d->othersPermCombo->currentItem()];
+ if (m != (mode_t) -1) {
+ orFilePermissions |= m & UniOthers;
+ if ((m & UniOthers) &&
+ ((d->pmode == PermissionsMixed) ||
+ ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange))))
+ andFilePermissions &= ~(S_IROTH | S_IWOTH);
+ else {
+ andFilePermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH);
+ if ((m & S_IROTH) && (d->extraCheckbox->state() == QButton::On))
+ orFilePermissions |= S_IXOTH;
+ }
+
+ orDirPermissions |= m & UniOthers;
+ if (m & S_IROTH)
+ orDirPermissions |= S_IXOTH;
+ andDirPermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH);
+ }
+
+ if (((d->pmode == PermissionsMixed) || (d->pmode == PermissionsOnlyDirs)) &&
+ (d->extraCheckbox->state() != QButton::NoChange)) {
+ andDirPermissions &= ~S_ISVTX;
+ if (d->extraCheckbox->state() == QButton::On)
+ orDirPermissions |= S_ISVTX;
+ }
+}
+
+void KFilePermissionsPropsPlugin::applyChanges()
+{
+ mode_t orFilePermissions;
+ mode_t orDirPermissions;
+ mode_t andFilePermissions;
+ mode_t andDirPermissions;
+
+ if (!d->canChangePermissions)
+ return;
+
+ if (!d->isIrregular)
+ getPermissionMasks(andFilePermissions,
+ andDirPermissions,
+ orFilePermissions,
+ orDirPermissions);
+ else {
+ orFilePermissions = permissions;
+ andFilePermissions = d->partialPermissions;
+ orDirPermissions = permissions;
+ andDirPermissions = d->partialPermissions;
+ }
+
+ QString owner, group;
+ if (usrEdit)
+ owner = usrEdit->text();
+ if (grpEdit)
+ group = grpEdit->text();
+ else if (grpCombo)
+ group = grpCombo->currentText();
+
+ if (owner == strOwner)
+ owner = QString::null; // no change
+
+ if (group == strGroup)
+ group = QString::null;
+
+ bool recursive = d->cbRecursive && d->cbRecursive->isChecked();
+ bool permissionChange = false;
+
+ KFileItemList files, dirs;
+ KFileItemList items = properties->items();
+ for (KFileItemListIterator it(items); it.current(); ++it) {
+ if ((*it)->isDir()) {
+ dirs.append(*it);
+ if ((*it)->permissions() != (((*it)->permissions() & andDirPermissions) | orDirPermissions))
+ permissionChange = true;
+ }
+ else if ((*it)->isFile()) {
+ files.append(*it);
+ if ((*it)->permissions() != (((*it)->permissions() & andFilePermissions) | orFilePermissions))
+ permissionChange = true;
+ }
+ }
+
+ const bool ACLChange = ( d->extendedACL != properties->item()->ACL() );
+ const bool defaultACLChange = ( d->defaultACL != properties->item()->defaultACL() );
+
+ if ( owner.isEmpty() && group.isEmpty() && !recursive
+ && !permissionChange && !ACLChange && !defaultACLChange )
+ return;
+
+ KIO::Job * job;
+ if (files.count() > 0) {
+ job = KIO::chmod( files, orFilePermissions, ~andFilePermissions,
+ owner, group, false );
+ if ( ACLChange && d->fileSystemSupportsACLs )
+ job->addMetaData( "ACL_STRING", d->extendedACL.isValid()?d->extendedACL.asString():"ACL_DELETE" );
+ if ( defaultACLChange && d->fileSystemSupportsACLs )
+ job->addMetaData( "DEFAULT_ACL_STRING", d->defaultACL.isValid()?d->defaultACL.asString():"ACL_DELETE" );
+
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotChmodResult( KIO::Job * ) ) );
+ // Wait for job
+ QWidget dummy(0,0,WType_Dialog|WShowModal);
+ qt_enter_modal(&dummy);
+ qApp->enter_loop();
+ qt_leave_modal(&dummy);
+ }
+ if (dirs.count() > 0) {
+ job = KIO::chmod( dirs, orDirPermissions, ~andDirPermissions,
+ owner, group, recursive );
+ if ( ACLChange && d->fileSystemSupportsACLs )
+ job->addMetaData( "ACL_STRING", d->extendedACL.isValid()?d->extendedACL.asString():"ACL_DELETE" );
+ if ( defaultACLChange && d->fileSystemSupportsACLs )
+ job->addMetaData( "DEFAULT_ACL_STRING", d->defaultACL.isValid()?d->defaultACL.asString():"ACL_DELETE" );
+
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotChmodResult( KIO::Job * ) ) );
+ // Wait for job
+ QWidget dummy(0,0,WType_Dialog|WShowModal);
+ qt_enter_modal(&dummy);
+ qApp->enter_loop();
+ qt_leave_modal(&dummy);
+ }
+}
+
+void KFilePermissionsPropsPlugin::slotChmodResult( KIO::Job * job )
+{
+ kdDebug(250) << "KFilePermissionsPropsPlugin::slotChmodResult" << endl;
+ if (job->error())
+ job->showErrorDialog( d->m_frame );
+ // allow apply() to return
+ qApp->exit_loop();
+}
+
+
+
+
+class KURLPropsPlugin::KURLPropsPluginPrivate
+{
+public:
+ KURLPropsPluginPrivate()
+ {
+ }
+ ~KURLPropsPluginPrivate()
+ {
+ }
+
+ QFrame *m_frame;
+};
+
+KURLPropsPlugin::KURLPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new KURLPropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("U&RL"));
+ QVBoxLayout *layout = new QVBoxLayout(d->m_frame, 0, KDialog::spacingHint());
+
+ QLabel *l;
+ l = new QLabel( d->m_frame, "Label_1" );
+ l->setText( i18n("URL:") );
+ layout->addWidget(l);
+
+ URLEdit = new KURLRequester( d->m_frame, "URL Requester" );
+ layout->addWidget(URLEdit);
+
+ QString path = properties->kurl().path();
+
+ QFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ URLStr = config.readPathEntry( "URL" );
+
+ if ( !URLStr.isNull() )
+ URLEdit->setURL( URLStr );
+
+ connect( URLEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+
+ layout->addStretch (1);
+}
+
+KURLPropsPlugin::~KURLPropsPlugin()
+{
+ delete d;
+}
+
+// QString KURLPropsPlugin::tabName () const
+// {
+// return i18n ("U&RL");
+// }
+
+bool KURLPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasLinkType();
+}
+
+void KURLPropsPlugin::applyChanges()
+{
+ QString path = properties->kurl().path();
+
+ QFile f( path );
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
+ "sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", QString::fromLatin1("Link"));
+ config.writePathEntry( "URL", URLEdit->url() );
+ // Users can't create a Link .desktop file with a Name field,
+ // but distributions can. Update the Name field in that case.
+ if ( config.hasKey("Name") )
+ {
+ QString nameStr = nameFromFileName(properties->kurl().fileName());
+ config.writeEntry( "Name", nameStr );
+ config.writeEntry( "Name", nameStr, true, false, true );
+
+ }
+}
+
+
+/* ----------------------------------------------------
+ *
+ * KBindingPropsPlugin
+ *
+ * -------------------------------------------------- */
+
+class KBindingPropsPlugin::KBindingPropsPluginPrivate
+{
+public:
+ KBindingPropsPluginPrivate()
+ {
+ }
+ ~KBindingPropsPluginPrivate()
+ {
+ }
+
+ QFrame *m_frame;
+};
+
+KBindingPropsPlugin::KBindingPropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
+{
+ d = new KBindingPropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("A&ssociation"));
+ patternEdit = new KLineEdit( d->m_frame, "LineEdit_1" );
+ commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
+ mimeEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
+
+ QBoxLayout *mainlayout = new QVBoxLayout(d->m_frame, 0, KDialog::spacingHint());
+ QLabel* tmpQLabel;
+
+ tmpQLabel = new QLabel( d->m_frame, "Label_1" );
+ tmpQLabel->setText( i18n("Pattern ( example: *.html;*.htm )") );
+ tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
+ mainlayout->addWidget(tmpQLabel, 1);
+
+ //patternEdit->setGeometry( 10, 40, 210, 30 );
+ //patternEdit->setText( "" );
+ patternEdit->setMaxLength( 512 );
+ patternEdit->setMinimumSize( patternEdit->sizeHint() );
+ patternEdit->setFixedHeight( fontHeight );
+ mainlayout->addWidget(patternEdit, 1);
+
+ tmpQLabel = new QLabel( d->m_frame, "Label_2" );
+ tmpQLabel->setText( i18n("Mime Type") );
+ tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
+ mainlayout->addWidget(tmpQLabel, 1);
+
+ //mimeEdit->setGeometry( 10, 160, 210, 30 );
+ mimeEdit->setMaxLength( 256 );
+ mimeEdit->setMinimumSize( mimeEdit->sizeHint() );
+ mimeEdit->setFixedHeight( fontHeight );
+ mainlayout->addWidget(mimeEdit, 1);
+
+ tmpQLabel = new QLabel( d->m_frame, "Label_3" );
+ tmpQLabel->setText( i18n("Comment") );
+ tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
+ mainlayout->addWidget(tmpQLabel, 1);
+
+ //commentEdit->setGeometry( 10, 100, 210, 30 );
+ commentEdit->setMaxLength( 256 );
+ commentEdit->setMinimumSize( commentEdit->sizeHint() );
+ commentEdit->setFixedHeight( fontHeight );
+ mainlayout->addWidget(commentEdit, 1);
+
+ cbAutoEmbed = new QCheckBox( i18n("Left click previews"), d->m_frame, "cbAutoEmbed" );
+ mainlayout->addWidget(cbAutoEmbed, 1);
+
+ mainlayout->addStretch (10);
+ mainlayout->activate();
+
+ QFile f( _props->kurl().path() );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KSimpleConfig config( _props->kurl().path() );
+ config.setDesktopGroup();
+ QString patternStr = config.readEntry( "Patterns" );
+ QString iconStr = config.readEntry( "Icon" );
+ QString commentStr = config.readEntry( "Comment" );
+ m_sMimeStr = config.readEntry( "MimeType" );
+
+ if ( !patternStr.isEmpty() )
+ patternEdit->setText( patternStr );
+ if ( !commentStr.isEmpty() )
+ commentEdit->setText( commentStr );
+ if ( !m_sMimeStr.isEmpty() )
+ mimeEdit->setText( m_sMimeStr );
+ cbAutoEmbed->setTristate();
+ if ( config.hasKey( "X-KDE-AutoEmbed" ) )
+ cbAutoEmbed->setChecked( config.readBoolEntry( "X-KDE-AutoEmbed" ) );
+ else
+ cbAutoEmbed->setNoChange();
+
+ connect( patternEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( commentEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( mimeEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( cbAutoEmbed, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+}
+
+KBindingPropsPlugin::~KBindingPropsPlugin()
+{
+ delete d;
+}
+
+// QString KBindingPropsPlugin::tabName () const
+// {
+// return i18n ("A&ssociation");
+// }
+
+bool KBindingPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasMimeTypeType();
+}
+
+void KBindingPropsPlugin::applyChanges()
+{
+ QString path = properties->kurl().path();
+ QFile f( path );
+
+ if ( !f.open( IO_ReadWrite ) )
+ {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
+ "sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", QString::fromLatin1("MimeType") );
+
+ config.writeEntry( "Patterns", patternEdit->text() );
+ config.writeEntry( "Comment", commentEdit->text() );
+ config.writeEntry( "Comment",
+ commentEdit->text(), true, false, true ); // for compat
+ config.writeEntry( "MimeType", mimeEdit->text() );
+ if ( cbAutoEmbed->state() == QButton::NoChange )
+ config.deleteEntry( "X-KDE-AutoEmbed", false );
+ else
+ config.writeEntry( "X-KDE-AutoEmbed", cbAutoEmbed->isChecked() );
+ config.sync();
+}
+
+/* ----------------------------------------------------
+ *
+ * KDevicePropsPlugin
+ *
+ * -------------------------------------------------- */
+
+class KDevicePropsPlugin::KDevicePropsPluginPrivate
+{
+public:
+ KDevicePropsPluginPrivate()
+ {
+ }
+ ~KDevicePropsPluginPrivate()
+ {
+ }
+
+ QFrame *m_frame;
+ QStringList mountpointlist;
+ QLabel *m_freeSpaceText;
+ QLabel *m_freeSpaceLabel;
+ QProgressBar *m_freeSpaceBar;
+};
+
+KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
+{
+ d = new KDevicePropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("De&vice"));
+
+ QStringList devices;
+ KMountPoint::List mountPoints = KMountPoint::possibleMountPoints();
+
+ for(KMountPoint::List::ConstIterator it = mountPoints.begin();
+ it != mountPoints.end(); ++it)
+ {
+ KMountPoint *mp = *it;
+ QString mountPoint = mp->mountPoint();
+ QString device = mp->mountedFrom();
+ kdDebug()<<"mountPoint :"<<mountPoint<<" device :"<<device<<" mp->mountType() :"<<mp->mountType()<<endl;
+
+ if ((mountPoint != "-") && (mountPoint != "none") && !mountPoint.isEmpty()
+ && device != "none")
+ {
+ devices.append( device + QString::fromLatin1(" (")
+ + mountPoint + QString::fromLatin1(")") );
+ m_devicelist.append(device);
+ d->mountpointlist.append(mountPoint);
+ }
+ }
+
+ QGridLayout *layout = new QGridLayout( d->m_frame, 0, 2, 0,
+ KDialog::spacingHint());
+ layout->setColStretch(1, 1);
+
+ QLabel* label;
+ label = new QLabel( d->m_frame );
+ label->setText( devices.count() == 0 ?
+ i18n("Device (/dev/fd0):") : // old style
+ i18n("Device:") ); // new style (combobox)
+ layout->addWidget(label, 0, 0);
+
+ device = new QComboBox( true, d->m_frame, "ComboBox_device" );
+ device->insertStringList( devices );
+ layout->addWidget(device, 0, 1);
+ connect( device, SIGNAL( activated( int ) ),
+ this, SLOT( slotActivated( int ) ) );
+
+ readonly = new QCheckBox( d->m_frame, "CheckBox_readonly" );
+ readonly->setText( i18n("Read only") );
+ layout->addWidget(readonly, 1, 1);
+
+ label = new QLabel( d->m_frame );
+ label->setText( i18n("File system:") );
+ layout->addWidget(label, 2, 0);
+
+ QLabel *fileSystem = new QLabel( d->m_frame );
+ layout->addWidget(fileSystem, 2, 1);
+
+ label = new QLabel( d->m_frame );
+ label->setText( devices.count()==0 ?
+ i18n("Mount point (/mnt/floppy):") : // old style
+ i18n("Mount point:")); // new style (combobox)
+ layout->addWidget(label, 3, 0);
+
+ mountpoint = new QLabel( d->m_frame, "LineEdit_mountpoint" );
+
+ layout->addWidget(mountpoint, 3, 1);
+
+ // show disk free
+ d->m_freeSpaceText = new QLabel(i18n("Free disk space:"), d->m_frame );
+ layout->addWidget(d->m_freeSpaceText, 4, 0);
+
+ d->m_freeSpaceLabel = new QLabel( d->m_frame );
+ layout->addWidget( d->m_freeSpaceLabel, 4, 1 );
+
+ d->m_freeSpaceBar = new QProgressBar( d->m_frame, "freeSpaceBar" );
+ layout->addMultiCellWidget(d->m_freeSpaceBar, 5, 5, 0, 1);
+
+ // we show it in the slot when we know the values
+ d->m_freeSpaceText->hide();
+ d->m_freeSpaceLabel->hide();
+ d->m_freeSpaceBar->hide();
+
+ KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
+ layout->addMultiCellWidget(sep, 6, 6, 0, 1);
+
+ unmounted = new KIconButton( d->m_frame );
+ int bsize = 66 + 2 * unmounted->style().pixelMetric(QStyle::PM_ButtonMargin);
+ unmounted->setFixedSize(bsize, bsize);
+ unmounted->setIconType(KIcon::Desktop, KIcon::Device);
+ layout->addWidget(unmounted, 7, 0);
+
+ label = new QLabel( i18n("Unmounted Icon"), d->m_frame );
+ layout->addWidget(label, 7, 1);
+
+ layout->setRowStretch(8, 1);
+
+ QString path( _props->kurl().path() );
+
+ QFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ QString deviceStr = config.readEntry( "Dev" );
+ QString mountPointStr = config.readEntry( "MountPoint" );
+ bool ro = config.readBoolEntry( "ReadOnly", false );
+ QString unmountedStr = config.readEntry( "UnmountIcon" );
+
+ fileSystem->setText( i18n(config.readEntry("FSType").local8Bit()) );
+
+ device->setEditText( deviceStr );
+ if ( !deviceStr.isEmpty() ) {
+ // Set default options for this device (first matching entry)
+ int index = m_devicelist.findIndex(deviceStr);
+ if (index != -1)
+ {
+ //kdDebug(250) << "found it " << index << endl;
+ slotActivated( index );
+ }
+ }
+
+ if ( !mountPointStr.isEmpty() )
+ {
+ mountpoint->setText( mountPointStr );
+ updateInfo();
+ }
+
+ readonly->setChecked( ro );
+
+ if ( unmountedStr.isEmpty() )
+ unmountedStr = KMimeType::defaultMimeTypePtr()->KServiceType::icon(); // default icon
+
+ unmounted->setIcon( unmountedStr );
+
+ connect( device, SIGNAL( activated( int ) ),
+ this, SIGNAL( changed() ) );
+ connect( device, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( readonly, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+ connect( unmounted, SIGNAL( iconChanged( QString ) ),
+ this, SIGNAL( changed() ) );
+
+ connect( device, SIGNAL( textChanged( const QString & ) ),
+ this, SLOT( slotDeviceChanged() ) );
+}
+
+KDevicePropsPlugin::~KDevicePropsPlugin()
+{
+ delete d;
+}
+
+// QString KDevicePropsPlugin::tabName () const
+// {
+// return i18n ("De&vice");
+// }
+
+void KDevicePropsPlugin::updateInfo()
+{
+ // we show it in the slot when we know the values
+ d->m_freeSpaceText->hide();
+ d->m_freeSpaceLabel->hide();
+ d->m_freeSpaceBar->hide();
+
+ if ( !mountpoint->text().isEmpty() )
+ {
+ KDiskFreeSp * job = new KDiskFreeSp;
+ connect( job, SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const QString& ) ),
+ this, SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const QString& ) ) );
+
+ job->readDF( mountpoint->text() );
+ }
+}
+
+void KDevicePropsPlugin::slotActivated( int index )
+{
+ // Update mountpoint so that it matches the device that was selected in the combo
+ device->setEditText( m_devicelist[index] );
+ mountpoint->setText( d->mountpointlist[index] );
+
+ updateInfo();
+}
+
+void KDevicePropsPlugin::slotDeviceChanged()
+{
+ // Update mountpoint so that it matches the typed device
+ int index = m_devicelist.findIndex( device->currentText() );
+ if ( index != -1 )
+ mountpoint->setText( d->mountpointlist[index] );
+ else
+ mountpoint->setText( QString::null );
+
+ updateInfo();
+}
+
+void KDevicePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize,
+ const unsigned long& /*kBUsed*/,
+ const unsigned long& kBAvail,
+ const QString& )
+{
+ d->m_freeSpaceText->show();
+ d->m_freeSpaceLabel->show();
+
+ int percUsed = 100 - (int)(100.0 * kBAvail / kBSize);
+
+ d->m_freeSpaceLabel->setText(
+ // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part.
+ i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)")
+ .arg(KIO::convertSizeFromKB(kBAvail))
+ .arg(KIO::convertSizeFromKB(kBSize))
+ .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
+
+ d->m_freeSpaceBar->setProgress(percUsed, 100);
+ d->m_freeSpaceBar->show();
+}
+
+bool KDevicePropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasDeviceType();
+}
+
+void KDevicePropsPlugin::applyChanges()
+{
+ QString path = properties->kurl().path();
+ QFile f( path );
+ if ( !f.open( IO_ReadWrite ) )
+ {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient "
+ "access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", QString::fromLatin1("FSDevice") );
+
+ config.writeEntry( "Dev", device->currentText() );
+ config.writeEntry( "MountPoint", mountpoint->text() );
+
+ config.writeEntry( "UnmountIcon", unmounted->icon() );
+ kdDebug(250) << "unmounted->icon() = " << unmounted->icon() << endl;
+
+ config.writeEntry( "ReadOnly", readonly->isChecked() );
+
+ config.sync();
+}
+
+
+/* ----------------------------------------------------
+ *
+ * KDesktopPropsPlugin
+ *
+ * -------------------------------------------------- */
+
+
+KDesktopPropsPlugin::KDesktopPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ QFrame *frame = properties->addPage(i18n("&Application"));
+ QVBoxLayout *mainlayout = new QVBoxLayout( frame, 0, KDialog::spacingHint() );
+
+ w = new KPropertiesDesktopBase(frame);
+ mainlayout->addWidget(w);
+
+ bool bKDesktopMode = (QCString(qApp->name()) == "kdesktop"); // nasty heh?
+
+ if (bKDesktopMode)
+ {
+ // Hide Name entry
+ w->nameEdit->hide();
+ w->nameLabel->hide();
+ }
+
+ w->pathEdit->setMode(KFile::Directory | KFile::LocalOnly);
+ w->pathEdit->lineEdit()->setAcceptDrops(false);
+
+ connect( w->nameEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
+ connect( w->genNameEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
+ connect( w->commentEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
+ connect( w->commandEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
+ connect( w->pathEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
+
+ connect( w->browseButton, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) );
+ connect( w->addFiletypeButton, SIGNAL( clicked() ), this, SLOT( slotAddFiletype() ) );
+ connect( w->delFiletypeButton, SIGNAL( clicked() ), this, SLOT( slotDelFiletype() ) );
+ connect( w->advancedButton, SIGNAL( clicked() ), this, SLOT( slotAdvanced() ) );
+
+ // now populate the page
+ QString path = _props->kurl().path();
+ QFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KDesktopFile config( path );
+ QString nameStr = config.readName();
+ QString genNameStr = config.readGenericName();
+ QString commentStr = config.readComment();
+ QString commandStr = config.readPathEntry( "Exec" );
+ if (commandStr.left(12) == "ksystraycmd ")
+ {
+ commandStr.remove(0, 12);
+ m_systrayBool = true;
+ }
+ else
+ m_systrayBool = false;
+
+ m_origCommandStr = commandStr;
+ QString pathStr = config.readPathEntry( "Path" );
+ m_terminalBool = config.readBoolEntry( "Terminal" );
+ m_terminalOptionStr = config.readEntry( "TerminalOptions" );
+ m_suidBool = config.readBoolEntry( "X-KDE-SubstituteUID" );
+ m_suidUserStr = config.readEntry( "X-KDE-Username" );
+ if( config.hasKey( "StartupNotify" ))
+ m_startupBool = config.readBoolEntry( "StartupNotify", true );
+ else
+ m_startupBool = config.readBoolEntry( "X-KDE-StartupNotify", true );
+ m_dcopServiceType = config.readEntry("X-DCOP-ServiceType").lower();
+
+ QStringList mimeTypes = config.readListEntry( "MimeType", ';' );
+
+ if ( nameStr.isEmpty() || bKDesktopMode ) {
+ // We'll use the file name if no name is specified
+ // because we _need_ a Name for a valid file.
+ // But let's do it in apply, not here, so that we pick up the right name.
+ setDirty();
+ }
+ if ( !bKDesktopMode )
+ w->nameEdit->setText(nameStr);
+
+ w->genNameEdit->setText( genNameStr );
+ w->commentEdit->setText( commentStr );
+ w->commandEdit->setText( commandStr );
+ w->pathEdit->lineEdit()->setText( pathStr );
+ w->filetypeList->setAllColumnsShowFocus(true);
+
+ KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr();
+ for(QStringList::ConstIterator it = mimeTypes.begin();
+ it != mimeTypes.end(); )
+ {
+ KMimeType::Ptr p = KMimeType::mimeType(*it);
+ ++it;
+ QString preference;
+ if (it != mimeTypes.end())
+ {
+ bool numeric;
+ (*it).toInt(&numeric);
+ if (numeric)
+ {
+ preference = *it;
+ ++it;
+ }
+ }
+ if (p && (p != defaultMimetype))
+ {
+ new QListViewItem(w->filetypeList, p->name(), p->comment(), preference);
+ }
+ }
+
+}
+
+KDesktopPropsPlugin::~KDesktopPropsPlugin()
+{
+}
+
+void KDesktopPropsPlugin::slotSelectMimetype()
+{
+ QListView *w = (QListView*)sender();
+ QListViewItem *item = w->firstChild();
+ while(item)
+ {
+ if (item->isSelected())
+ w->setSelected(item, false);
+ item = item->nextSibling();
+ }
+}
+
+void KDesktopPropsPlugin::slotAddFiletype()
+{
+ KDialogBase dlg(w, "KPropertiesMimetypes", true,
+ i18n("Add File Type for %1").arg(properties->kurl().fileName()),
+ KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok);
+
+ KGuiItem okItem(i18n("&Add"), QString::null /* no icon */,
+ i18n("Add the selected file types to\nthe list of supported file types."),
+ i18n("Add the selected file types to\nthe list of supported file types."));
+ dlg.setButtonOK(okItem);
+
+ KPropertiesMimetypeBase *mw = new KPropertiesMimetypeBase(&dlg);
+
+ dlg.setMainWidget(mw);
+
+ {
+ mw->listView->setRootIsDecorated(true);
+ mw->listView->setSelectionMode(QListView::Extended);
+ mw->listView->setAllColumnsShowFocus(true);
+ mw->listView->setFullWidth(true);
+ mw->listView->setMinimumSize(500,400);
+
+ connect(mw->listView, SIGNAL(selectionChanged()),
+ this, SLOT(slotSelectMimetype()));
+ connect(mw->listView, SIGNAL(doubleClicked( QListViewItem *, const QPoint &, int )),
+ &dlg, SLOT( slotOk()));
+
+ QMap<QString,QListViewItem*> majorMap;
+ QListViewItem *majorGroup;
+ KMimeType::List mimetypes = KMimeType::allMimeTypes();
+ QValueListIterator<KMimeType::Ptr> it(mimetypes.begin());
+ for (; it != mimetypes.end(); ++it) {
+ QString mimetype = (*it)->name();
+ if (mimetype == KMimeType::defaultMimeType())
+ continue;
+ int index = mimetype.find("/");
+ QString maj = mimetype.left(index);
+ QString min = mimetype.mid(index+1);
+
+ QMapIterator<QString,QListViewItem*> mit = majorMap.find( maj );
+ if ( mit == majorMap.end() ) {
+ majorGroup = new QListViewItem( mw->listView, maj );
+ majorGroup->setExpandable(true);
+ mw->listView->setOpen(majorGroup, true);
+ majorMap.insert( maj, majorGroup );
+ }
+ else
+ {
+ majorGroup = mit.data();
+ }
+
+ QListViewItem *item = new QListViewItem(majorGroup, min, (*it)->comment());
+ item->setPixmap(0, (*it)->pixmap(KIcon::Small, IconSize(KIcon::Small)));
+ }
+ QMapIterator<QString,QListViewItem*> mit = majorMap.find( "all" );
+ if ( mit != majorMap.end())
+ {
+ mw->listView->setCurrentItem(mit.data());
+ mw->listView->ensureItemVisible(mit.data());
+ }
+ }
+
+ if (dlg.exec() == KDialogBase::Accepted)
+ {
+ KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr();
+ QListViewItem *majorItem = mw->listView->firstChild();
+ while(majorItem)
+ {
+ QString major = majorItem->text(0);
+
+ QListViewItem *minorItem = majorItem->firstChild();
+ while(minorItem)
+ {
+ if (minorItem->isSelected())
+ {
+ QString mimetype = major + "/" + minorItem->text(0);
+ KMimeType::Ptr p = KMimeType::mimeType(mimetype);
+ if (p && (p != defaultMimetype))
+ {
+ mimetype = p->name();
+ bool found = false;
+ QListViewItem *item = w->filetypeList->firstChild();
+ while (item)
+ {
+ if (mimetype == item->text(0))
+ {
+ found = true;
+ break;
+ }
+ item = item->nextSibling();
+ }
+ if (!found) {
+ new QListViewItem(w->filetypeList, p->name(), p->comment());
+ emit changed();
+ }
+ }
+ }
+ minorItem = minorItem->nextSibling();
+ }
+
+ majorItem = majorItem->nextSibling();
+ }
+
+ }
+}
+
+void KDesktopPropsPlugin::slotDelFiletype()
+{
+ delete w->filetypeList->currentItem();
+ emit changed();
+}
+
+void KDesktopPropsPlugin::checkCommandChanged()
+{
+ if (KRun::binaryName(w->commandEdit->text(), true) !=
+ KRun::binaryName(m_origCommandStr, true))
+ {
+ QString m_origCommandStr = w->commandEdit->text();
+ m_dcopServiceType= QString::null; // Reset
+ }
+}
+
+void KDesktopPropsPlugin::applyChanges()
+{
+ kdDebug(250) << "KDesktopPropsPlugin::applyChanges" << endl;
+ QString path = properties->kurl().path();
+
+ QFile f( path );
+
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
+ "sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ // If the command is changed we reset certain settings that are strongly
+ // coupled to the command.
+ checkCommandChanged();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", QString::fromLatin1("Application"));
+ config.writeEntry( "Comment", w->commentEdit->text() );
+ config.writeEntry( "Comment", w->commentEdit->text(), true, false, true ); // for compat
+ config.writeEntry( "GenericName", w->genNameEdit->text() );
+ config.writeEntry( "GenericName", w->genNameEdit->text(), true, false, true ); // for compat
+
+ if (m_systrayBool)
+ config.writePathEntry( "Exec", w->commandEdit->text().prepend("ksystraycmd ") );
+ else
+ config.writePathEntry( "Exec", w->commandEdit->text() );
+ config.writePathEntry( "Path", w->pathEdit->lineEdit()->text() );
+
+ // Write mimeTypes
+ QStringList mimeTypes;
+ for( QListViewItem *item = w->filetypeList->firstChild();
+ item; item = item->nextSibling() )
+ {
+ QString preference = item->text(2);
+ mimeTypes.append(item->text(0));
+ if (!preference.isEmpty())
+ mimeTypes.append(preference);
+ }
+
+ config.writeEntry( "MimeType", mimeTypes, ';' );
+
+ if ( !w->nameEdit->isHidden() ) {
+ QString nameStr = w->nameEdit->text();
+ config.writeEntry( "Name", nameStr );
+ config.writeEntry( "Name", nameStr, true, false, true );
+ }
+
+ config.writeEntry("Terminal", m_terminalBool);
+ config.writeEntry("TerminalOptions", m_terminalOptionStr);
+ config.writeEntry("X-KDE-SubstituteUID", m_suidBool);
+ config.writeEntry("X-KDE-Username", m_suidUserStr);
+ config.writeEntry("StartupNotify", m_startupBool);
+ config.writeEntry("X-DCOP-ServiceType", m_dcopServiceType);
+ config.sync();
+
+ // KSycoca update needed?
+ QString sycocaPath = KGlobal::dirs()->relativeLocation("apps", path);
+ bool updateNeeded = !sycocaPath.startsWith("/");
+ if (!updateNeeded)
+ {
+ sycocaPath = KGlobal::dirs()->relativeLocation("xdgdata-apps", path);
+ updateNeeded = !sycocaPath.startsWith("/");
+ }
+ if (updateNeeded)
+ KService::rebuildKSycoca(w);
+}
+
+
+void KDesktopPropsPlugin::slotBrowseExec()
+{
+ KURL f = KFileDialog::getOpenURL( QString::null,
+ QString::null, w );
+ if ( f.isEmpty() )
+ return;
+
+ if ( !f.isLocalFile()) {
+ KMessageBox::sorry(w, i18n("Only executables on local file systems are supported."));
+ return;
+ }
+
+ QString path = f.path();
+ KRun::shellQuote( path );
+ w->commandEdit->setText( path );
+}
+
+void KDesktopPropsPlugin::slotAdvanced()
+{
+ KDialogBase dlg(w, "KPropertiesDesktopAdv", true,
+ i18n("Advanced Options for %1").arg(properties->kurl().fileName()),
+ KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok);
+ KPropertiesDesktopAdvBase *w = new KPropertiesDesktopAdvBase(&dlg);
+
+ dlg.setMainWidget(w);
+
+ // If the command is changed we reset certain settings that are strongly
+ // coupled to the command.
+ checkCommandChanged();
+
+ // check to see if we use konsole if not do not add the nocloseonexit
+ // because we don't know how to do this on other terminal applications
+ KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
+ QString preferredTerminal = confGroup.readPathEntry("TerminalApplication",
+ QString::fromLatin1("konsole"));
+
+ bool terminalCloseBool = false;
+
+ if (preferredTerminal == "konsole")
+ {
+ terminalCloseBool = (m_terminalOptionStr.contains( "--noclose" ) > 0);
+ w->terminalCloseCheck->setChecked(terminalCloseBool);
+ m_terminalOptionStr.replace( "--noclose", "");
+ }
+ else
+ {
+ w->terminalCloseCheck->hide();
+ }
+
+ w->terminalCheck->setChecked(m_terminalBool);
+ w->terminalEdit->setText(m_terminalOptionStr);
+ w->terminalCloseCheck->setEnabled(m_terminalBool);
+ w->terminalEdit->setEnabled(m_terminalBool);
+ w->terminalEditLabel->setEnabled(m_terminalBool);
+
+ w->suidCheck->setChecked(m_suidBool);
+ w->suidEdit->setText(m_suidUserStr);
+ w->suidEdit->setEnabled(m_suidBool);
+ w->suidEditLabel->setEnabled(m_suidBool);
+
+ w->startupInfoCheck->setChecked(m_startupBool);
+ w->systrayCheck->setChecked(m_systrayBool);
+
+ if (m_dcopServiceType == "unique")
+ w->dcopCombo->setCurrentItem(2);
+ else if (m_dcopServiceType == "multi")
+ w->dcopCombo->setCurrentItem(1);
+ else if (m_dcopServiceType == "wait")
+ w->dcopCombo->setCurrentItem(3);
+ else
+ w->dcopCombo->setCurrentItem(0);
+
+ // Provide username completion up to 1000 users.
+ KCompletion *kcom = new KCompletion;
+ kcom->setOrder(KCompletion::Sorted);
+ struct passwd *pw;
+ int i, maxEntries = 1000;
+ setpwent();
+ for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
+ kcom->addItem(QString::fromLatin1(pw->pw_name));
+ endpwent();
+ if (i < maxEntries)
+ {
+ w->suidEdit->setCompletionObject(kcom, true);
+ w->suidEdit->setAutoDeleteCompletionObject( true );
+ w->suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
+ }
+ else
+ {
+ delete kcom;
+ }
+
+ connect( w->terminalEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( w->terminalCloseCheck, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+ connect( w->terminalCheck, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+ connect( w->suidCheck, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+ connect( w->suidEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( w->startupInfoCheck, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+ connect( w->systrayCheck, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+ connect( w->dcopCombo, SIGNAL( highlighted( int ) ),
+ this, SIGNAL( changed() ) );
+
+ if ( dlg.exec() == QDialog::Accepted )
+ {
+ m_terminalOptionStr = w->terminalEdit->text().stripWhiteSpace();
+ m_terminalBool = w->terminalCheck->isChecked();
+ m_suidBool = w->suidCheck->isChecked();
+ m_suidUserStr = w->suidEdit->text().stripWhiteSpace();
+ m_startupBool = w->startupInfoCheck->isChecked();
+ m_systrayBool = w->systrayCheck->isChecked();
+
+ if (w->terminalCloseCheck->isChecked())
+ {
+ m_terminalOptionStr.append(" --noclose");
+ }
+
+ switch(w->dcopCombo->currentItem())
+ {
+ case 1: m_dcopServiceType = "multi"; break;
+ case 2: m_dcopServiceType = "unique"; break;
+ case 3: m_dcopServiceType = "wait"; break;
+ default: m_dcopServiceType = "none"; break;
+ }
+ }
+}
+
+bool KDesktopPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
+}
+
+void KPropertiesDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+void KPropsDlgPlugin::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+
+
+
+
+/**
+ * The following code is obsolete and only kept for binary compatibility
+ * To be removed in KDE 4
+ */
+
+class KExecPropsPlugin::KExecPropsPluginPrivate
+{
+public:
+ KExecPropsPluginPrivate()
+ {
+ }
+ ~KExecPropsPluginPrivate()
+ {
+ }
+
+ QFrame *m_frame;
+ QCheckBox *nocloseonexitCheck;
+};
+
+KExecPropsPlugin::KExecPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new KExecPropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("E&xecute"));
+ QVBoxLayout * mainlayout = new QVBoxLayout( d->m_frame, 0,
+ KDialog::spacingHint());
+
+ // Now the widgets in the top layout
+
+ QLabel* l;
+ l = new QLabel( i18n( "Comman&d:" ), d->m_frame );
+ mainlayout->addWidget(l);
+
+ QHBoxLayout * hlayout;
+ hlayout = new QHBoxLayout(KDialog::spacingHint());
+ mainlayout->addLayout(hlayout);
+
+ execEdit = new KLineEdit( d->m_frame );
+ QWhatsThis::add(execEdit,i18n(
+ "Following the command, you can have several place holders which will be replaced "
+ "with the actual values when the actual program is run:\n"
+ "%f - a single file name\n"
+ "%F - a list of files; use for applications that can open several local files at once\n"
+ "%u - a single URL\n"
+ "%U - a list of URLs\n"
+ "%d - the folder of the file to open\n"
+ "%D - a list of folders\n"
+ "%i - the icon\n"
+ "%m - the mini-icon\n"
+ "%c - the caption"));
+ hlayout->addWidget(execEdit, 1);
+
+ l->setBuddy( execEdit );
+
+ execBrowse = new QPushButton( d->m_frame );
+ execBrowse->setText( i18n("&Browse...") );
+ hlayout->addWidget(execBrowse);
+
+ // The groupbox about swallowing
+ QGroupBox* tmpQGroupBox;
+ tmpQGroupBox = new QGroupBox( i18n("Panel Embedding"), d->m_frame );
+ tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
+
+ mainlayout->addWidget(tmpQGroupBox);
+
+ QGridLayout *grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
+ grid->setSpacing( KDialog::spacingHint() );
+ grid->setColStretch(1, 1);
+
+ l = new QLabel( i18n( "&Execute on click:" ), tmpQGroupBox );
+ grid->addWidget(l, 0, 0);
+
+ swallowExecEdit = new KLineEdit( tmpQGroupBox );
+ grid->addWidget(swallowExecEdit, 0, 1);
+
+ l->setBuddy( swallowExecEdit );
+
+ l = new QLabel( i18n( "&Window title:" ), tmpQGroupBox );
+ grid->addWidget(l, 1, 0);
+
+ swallowTitleEdit = new KLineEdit( tmpQGroupBox );
+ grid->addWidget(swallowTitleEdit, 1, 1);
+
+ l->setBuddy( swallowTitleEdit );
+
+ // The groupbox about run in terminal
+
+ tmpQGroupBox = new QGroupBox( d->m_frame );
+ tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
+
+ mainlayout->addWidget(tmpQGroupBox);
+
+ grid = new QGridLayout(tmpQGroupBox->layout(), 3, 2);
+ grid->setSpacing( KDialog::spacingHint() );
+ grid->setColStretch(1, 1);
+
+ terminalCheck = new QCheckBox( tmpQGroupBox );
+ terminalCheck->setText( i18n("&Run in terminal") );
+ grid->addMultiCellWidget(terminalCheck, 0, 0, 0, 1);
+
+ // check to see if we use konsole if not do not add the nocloseonexit
+ // because we don't know how to do this on other terminal applications
+ KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
+ QString preferredTerminal = confGroup.readPathEntry("TerminalApplication",
+ QString::fromLatin1("konsole"));
+
+ int posOptions = 1;
+ d->nocloseonexitCheck = 0L;
+ if (preferredTerminal == "konsole")
+ {
+ posOptions = 2;
+ d->nocloseonexitCheck = new QCheckBox( tmpQGroupBox );
+ d->nocloseonexitCheck->setText( i18n("Do not &close when command exits") );
+ grid->addMultiCellWidget(d->nocloseonexitCheck, 1, 1, 0, 1);
+ }
+
+ terminalLabel = new QLabel( i18n( "&Terminal options:" ), tmpQGroupBox );
+ grid->addWidget(terminalLabel, posOptions, 0);
+
+ terminalEdit = new KLineEdit( tmpQGroupBox );
+ grid->addWidget(terminalEdit, posOptions, 1);
+
+ terminalLabel->setBuddy( terminalEdit );
+
+ // The groupbox about run with substituted uid.
+
+ tmpQGroupBox = new QGroupBox( d->m_frame );
+ tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
+
+ mainlayout->addWidget(tmpQGroupBox);
+
+ grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
+ grid->setSpacing(KDialog::spacingHint());
+ grid->setColStretch(1, 1);
+
+ suidCheck = new QCheckBox(tmpQGroupBox);
+ suidCheck->setText(i18n("Ru&n as a different user"));
+ grid->addMultiCellWidget(suidCheck, 0, 0, 0, 1);
+
+ suidLabel = new QLabel(i18n( "&Username:" ), tmpQGroupBox);
+ grid->addWidget(suidLabel, 1, 0);
+
+ suidEdit = new KLineEdit(tmpQGroupBox);
+ grid->addWidget(suidEdit, 1, 1);
+
+ suidLabel->setBuddy( suidEdit );
+
+ mainlayout->addStretch(1);
+
+ // now populate the page
+ QString path = _props->kurl().path();
+ QFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDollarExpansion( false );
+ config.setDesktopGroup();
+ execStr = config.readPathEntry( "Exec" );
+ swallowExecStr = config.readPathEntry( "SwallowExec" );
+ swallowTitleStr = config.readEntry( "SwallowTitle" );
+ termBool = config.readBoolEntry( "Terminal" );
+ termOptionsStr = config.readEntry( "TerminalOptions" );
+ suidBool = config.readBoolEntry( "X-KDE-SubstituteUID" );
+ suidUserStr = config.readEntry( "X-KDE-Username" );
+
+ if ( !swallowExecStr.isNull() )
+ swallowExecEdit->setText( swallowExecStr );
+ if ( !swallowTitleStr.isNull() )
+ swallowTitleEdit->setText( swallowTitleStr );
+
+ if ( !execStr.isNull() )
+ execEdit->setText( execStr );
+
+ if ( d->nocloseonexitCheck )
+ {
+ d->nocloseonexitCheck->setChecked( (termOptionsStr.contains( "--noclose" ) > 0) );
+ termOptionsStr.replace( "--noclose", "");
+ }
+ if ( !termOptionsStr.isNull() )
+ terminalEdit->setText( termOptionsStr );
+
+ terminalCheck->setChecked( termBool );
+ enableCheckedEdit();
+
+ suidCheck->setChecked( suidBool );
+ suidEdit->setText( suidUserStr );
+ enableSuidEdit();
+
+ // Provide username completion up to 1000 users.
+ KCompletion *kcom = new KCompletion;
+ kcom->setOrder(KCompletion::Sorted);
+ struct passwd *pw;
+ int i, maxEntries = 1000;
+ setpwent();
+ for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
+ kcom->addItem(QString::fromLatin1(pw->pw_name));
+ endpwent();
+ if (i < maxEntries)
+ {
+ suidEdit->setCompletionObject(kcom, true);
+ suidEdit->setAutoDeleteCompletionObject( true );
+ suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
+ }
+ else
+ {
+ delete kcom;
+ }
+
+ connect( swallowExecEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( swallowTitleEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( execEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( terminalEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ if (d->nocloseonexitCheck)
+ connect( d->nocloseonexitCheck, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+ connect( terminalCheck, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+ connect( suidCheck, SIGNAL( toggled( bool ) ),
+ this, SIGNAL( changed() ) );
+ connect( suidEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+
+ connect( execBrowse, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) );
+ connect( terminalCheck, SIGNAL( clicked() ), this, SLOT( enableCheckedEdit() ) );
+ connect( suidCheck, SIGNAL( clicked() ), this, SLOT( enableSuidEdit() ) );
+
+}
+
+KExecPropsPlugin::~KExecPropsPlugin()
+{
+ delete d;
+}
+
+void KExecPropsPlugin::enableCheckedEdit()
+{
+ bool checked = terminalCheck->isChecked();
+ terminalLabel->setEnabled( checked );
+ if (d->nocloseonexitCheck)
+ d->nocloseonexitCheck->setEnabled( checked );
+ terminalEdit->setEnabled( checked );
+}
+
+void KExecPropsPlugin::enableSuidEdit()
+{
+ bool checked = suidCheck->isChecked();
+ suidLabel->setEnabled( checked );
+ suidEdit->setEnabled( checked );
+}
+
+bool KExecPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
+}
+
+void KExecPropsPlugin::applyChanges()
+{
+ kdDebug(250) << "KExecPropsPlugin::applyChanges" << endl;
+ QString path = properties->kurl().path();
+
+ QFile f( path );
+
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
+ "sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", QString::fromLatin1("Application"));
+ config.writePathEntry( "Exec", execEdit->text() );
+ config.writePathEntry( "SwallowExec", swallowExecEdit->text() );
+ config.writeEntry( "SwallowTitle", swallowTitleEdit->text() );
+ config.writeEntry( "Terminal", terminalCheck->isChecked() );
+ QString temp = terminalEdit->text();
+ if (d->nocloseonexitCheck )
+ if ( d->nocloseonexitCheck->isChecked() )
+ temp += QString::fromLatin1("--noclose ");
+ temp = temp.stripWhiteSpace();
+ config.writeEntry( "TerminalOptions", temp );
+ config.writeEntry( "X-KDE-SubstituteUID", suidCheck->isChecked() );
+ config.writeEntry( "X-KDE-Username", suidEdit->text() );
+}
+
+
+void KExecPropsPlugin::slotBrowseExec()
+{
+ KURL f = KFileDialog::getOpenURL( QString::null,
+ QString::null, d->m_frame );
+ if ( f.isEmpty() )
+ return;
+
+ if ( !f.isLocalFile()) {
+ KMessageBox::sorry(d->m_frame, i18n("Only executables on local file systems are supported."));
+ return;
+ }
+
+ QString path = f.path();
+ KRun::shellQuote( path );
+ execEdit->setText( path );
+}
+
+class KApplicationPropsPlugin::KApplicationPropsPluginPrivate
+{
+public:
+ KApplicationPropsPluginPrivate()
+ {
+ m_kdesktopMode = QCString(qApp->name()) == "kdesktop"; // nasty heh?
+ }
+ ~KApplicationPropsPluginPrivate()
+ {
+ }
+
+ QFrame *m_frame;
+ bool m_kdesktopMode;
+};
+
+KApplicationPropsPlugin::KApplicationPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new KApplicationPropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("&Application"));
+ QVBoxLayout *toplayout = new QVBoxLayout( d->m_frame, 0, KDialog::spacingHint());
+
+ QIconSet iconSet;
+ QPixmap pixMap;
+
+ addExtensionButton = new QPushButton( QString::null, d->m_frame );
+ iconSet = SmallIconSet( "back" );
+ addExtensionButton->setIconSet( iconSet );
+ pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal );
+ addExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
+ connect( addExtensionButton, SIGNAL( clicked() ),
+ SLOT( slotAddExtension() ) );
+
+ delExtensionButton = new QPushButton( QString::null, d->m_frame );
+ iconSet = SmallIconSet( "forward" );
+ delExtensionButton->setIconSet( iconSet );
+ delExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
+ connect( delExtensionButton, SIGNAL( clicked() ),
+ SLOT( slotDelExtension() ) );
+
+ QLabel *l;
+
+ QGridLayout *grid = new QGridLayout(2, 2);
+ grid->setColStretch(1, 1);
+ toplayout->addLayout(grid);
+
+ if ( d->m_kdesktopMode )
+ {
+ // in kdesktop the name field comes from the first tab
+ nameEdit = 0L;
+ }
+ else
+ {
+ l = new QLabel(i18n("Name:"), d->m_frame, "Label_4" );
+ grid->addWidget(l, 0, 0);
+
+ nameEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
+ grid->addWidget(nameEdit, 0, 1);
+ }
+
+ l = new QLabel(i18n("Description:"), d->m_frame, "Label_5" );
+ grid->addWidget(l, 1, 0);
+
+ genNameEdit = new KLineEdit( d->m_frame, "LineEdit_4" );
+ grid->addWidget(genNameEdit, 1, 1);
+
+ l = new QLabel(i18n("Comment:"), d->m_frame, "Label_3" );
+ grid->addWidget(l, 2, 0);
+
+ commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
+ grid->addWidget(commentEdit, 2, 1);
+
+ l = new QLabel(i18n("File types:"), d->m_frame);
+ toplayout->addWidget(l, 0, AlignLeft);
+
+ grid = new QGridLayout(4, 3);
+ grid->setColStretch(0, 1);
+ grid->setColStretch(2, 1);
+ grid->setRowStretch( 0, 1 );
+ grid->setRowStretch( 3, 1 );
+ toplayout->addLayout(grid, 2);
+
+ extensionsList = new QListBox( d->m_frame );
+ extensionsList->setSelectionMode( QListBox::Extended );
+ grid->addMultiCellWidget(extensionsList, 0, 3, 0, 0);
+
+ grid->addWidget(addExtensionButton, 1, 1);
+ grid->addWidget(delExtensionButton, 2, 1);
+
+ availableExtensionsList = new QListBox( d->m_frame );
+ availableExtensionsList->setSelectionMode( QListBox::Extended );
+ grid->addMultiCellWidget(availableExtensionsList, 0, 3, 2, 2);
+
+ QString path = properties->kurl().path() ;
+ QFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KDesktopFile config( path );
+ QString commentStr = config.readComment();
+ QString genNameStr = config.readGenericName();
+
+ QStringList selectedTypes = config.readListEntry( "ServiceTypes" );
+ // For compatibility with KDE 1.x
+ selectedTypes += config.readListEntry( "MimeType", ';' );
+
+ QString nameStr = config.readName();
+ if ( nameStr.isEmpty() || d->m_kdesktopMode ) {
+ // We'll use the file name if no name is specified
+ // because we _need_ a Name for a valid file.
+ // But let's do it in apply, not here, so that we pick up the right name.
+ setDirty();
+ }
+
+ commentEdit->setText( commentStr );
+ genNameEdit->setText( genNameStr );
+ if ( nameEdit )
+ nameEdit->setText( nameStr );
+
+ selectedTypes.sort();
+ QStringList::Iterator sit = selectedTypes.begin();
+ for( ; sit != selectedTypes.end(); ++sit ) {
+ if ( !((*sit).isEmpty()) )
+ extensionsList->insertItem( *sit );
+ }
+
+ KMimeType::List mimeTypes = KMimeType::allMimeTypes();
+ QValueListIterator<KMimeType::Ptr> it2 = mimeTypes.begin();
+ for ( ; it2 != mimeTypes.end(); ++it2 )
+ addMimeType ( (*it2)->name() );
+
+ updateButton();
+
+ connect( extensionsList, SIGNAL( highlighted( int ) ),
+ this, SLOT( updateButton() ) );
+ connect( availableExtensionsList, SIGNAL( highlighted( int ) ),
+ this, SLOT( updateButton() ) );
+
+ connect( addExtensionButton, SIGNAL( clicked() ),
+ this, SIGNAL( changed() ) );
+ connect( delExtensionButton, SIGNAL( clicked() ),
+ this, SIGNAL( changed() ) );
+ if ( nameEdit )
+ connect( nameEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( commentEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( genNameEdit, SIGNAL( textChanged( const QString & ) ),
+ this, SIGNAL( changed() ) );
+ connect( availableExtensionsList, SIGNAL( selected( int ) ),
+ this, SIGNAL( changed() ) );
+ connect( extensionsList, SIGNAL( selected( int ) ),
+ this, SIGNAL( changed() ) );
+}
+
+KApplicationPropsPlugin::~KApplicationPropsPlugin()
+{
+ delete d;
+}
+
+// QString KApplicationPropsPlugin::tabName () const
+// {
+// return i18n ("&Application");
+// }
+
+void KApplicationPropsPlugin::updateButton()
+{
+ addExtensionButton->setEnabled(availableExtensionsList->currentItem()>-1);
+ delExtensionButton->setEnabled(extensionsList->currentItem()>-1);
+}
+
+void KApplicationPropsPlugin::addMimeType( const QString & name )
+{
+ // Add a mimetype to the list of available mime types if not in the extensionsList
+
+ bool insert = true;
+
+ for ( uint i = 0; i < extensionsList->count(); i++ )
+ if ( extensionsList->text( i ) == name )
+ insert = false;
+
+ if ( insert )
+ {
+ availableExtensionsList->insertItem( name );
+ availableExtensionsList->sort();
+ }
+}
+
+bool KApplicationPropsPlugin::supports( KFileItemList _items )
+{
+ // same constraints as KExecPropsPlugin : desktop file with Type = Application
+ return KExecPropsPlugin::supports( _items );
+}
+
+void KApplicationPropsPlugin::applyChanges()
+{
+ QString path = properties->kurl().path();
+
+ QFile f( path );
+
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not "
+ "have sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", QString::fromLatin1("Application"));
+ config.writeEntry( "Comment", commentEdit->text() );
+ config.writeEntry( "Comment", commentEdit->text(), true, false, true ); // for compat
+ config.writeEntry( "GenericName", genNameEdit->text() );
+ config.writeEntry( "GenericName", genNameEdit->text(), true, false, true ); // for compat
+
+ QStringList selectedTypes;
+ for ( uint i = 0; i < extensionsList->count(); i++ )
+ selectedTypes.append( extensionsList->text( i ) );
+
+ config.writeEntry( "MimeType", selectedTypes, ';' );
+ config.writeEntry( "ServiceTypes", "" );
+ // hmm, actually it should probably be the contrary (but see also typeslistitem.cpp)
+
+ QString nameStr = nameEdit ? nameEdit->text() : QString::null;
+ if ( nameStr.isEmpty() ) // nothing entered, or widget not existing at all (kdesktop mode)
+ nameStr = nameFromFileName(properties->kurl().fileName());
+
+ config.writeEntry( "Name", nameStr );
+ config.writeEntry( "Name", nameStr, true, false, true );
+
+ config.sync();
+}
+
+void KApplicationPropsPlugin::slotAddExtension()
+{
+ QListBoxItem *item = availableExtensionsList->firstItem();
+ QListBoxItem *nextItem;
+
+ while ( item )
+ {
+ nextItem = item->next();
+
+ if ( item->isSelected() )
+ {
+ extensionsList->insertItem( item->text() );
+ availableExtensionsList->removeItem( availableExtensionsList->index( item ) );
+ }
+
+ item = nextItem;
+ }
+
+ extensionsList->sort();
+ updateButton();
+}
+
+void KApplicationPropsPlugin::slotDelExtension()
+{
+ QListBoxItem *item = extensionsList->firstItem();
+ QListBoxItem *nextItem;
+
+ while ( item )
+ {
+ nextItem = item->next();
+
+ if ( item->isSelected() )
+ {
+ availableExtensionsList->insertItem( item->text() );
+ extensionsList->removeItem( extensionsList->index( item ) );
+ }
+
+ item = nextItem;
+ }
+
+ availableExtensionsList->sort();
+ updateButton();
+}
+
+
+
+#include "kpropertiesdialog.moc"
diff --git a/kio/kfile/kpropertiesdialog.h b/kio/kfile/kpropertiesdialog.h
new file mode 100644
index 000000000..b71ad7948
--- /dev/null
+++ b/kio/kfile/kpropertiesdialog.h
@@ -0,0 +1,918 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (c) 1999, 2000 Preston Brown <pbrown@kde.org>
+ Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
+ Copyright (c) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ * This file holds the definitions for all classes used to
+ * display a properties dialog.
+ */
+
+#ifndef __propsdlg_h
+#define __propsdlg_h
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+#include <kdemacros.h>
+#include <kurl.h>
+#include <kfileitem.h>
+#include <kdialogbase.h>
+
+class QLineEdit;
+class QCheckBox;
+class QPushButton;
+class KLineEdit;
+class KURLRequester;
+class QButton;
+class KIconButton;
+class KPropsDlgPlugin;
+class QComboBox;
+
+#define KPropsPage KPropsDlgPlugin
+
+namespace KIO { class Job; }
+
+/**
+ * The main properties dialog class.
+ * A Properties Dialog is a dialog which displays various information
+ * about a particular file or URL, or several files or URLs.
+ * This main class holds various related classes, which are instantiated in
+ * the form of tab entries in the tabbed dialog that this class provides.
+ * The various tabs themselves will let the user view, and sometimes change,
+ * information about the file or URL.
+ *
+ * \image html kpropertiesdialog.png "Typical KProperties Dialog"
+ *
+ * This class must be created with (void)new KPropertiesDialog(...)
+ * It will take care of deleting itself.
+ *
+ * If you are looking for more flexibility, see KFileMetaInfo and
+ * KFileMetaInfoWidget.
+ */
+class KIO_EXPORT KPropertiesDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Determine whether there are any property pages available for the
+ * given file items.
+ * @param _items the list of items to check.
+ * @return true if there are any property pages, otherwise false.
+ */
+ static bool canDisplay( KFileItemList _items );
+
+ /**
+ * Brings up a Properties dialog, as shown above.
+ * This is the normal constructor for
+ * file-manager type applications, where you have a KFileItem instance
+ * to work with. Normally you will use this
+ * method rather than the one below.
+ *
+ * @param item file item whose properties should be displayed.
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * @param autoShow tells the dialog whether it should show itself automatically.
+ */
+ KPropertiesDialog( KFileItem * item,
+ QWidget* parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true);
+
+ /**
+ * \overload
+ *
+ * You use this constructor for cases where you have a number of items,
+ * rather than a single item. Be careful which methods you use
+ * when passing a list of files or URLs, since some of them will only
+ * work on the first item in a list.
+ *
+ * @param _items list of file items whose properties should be displayed.
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * @param autoShow tells the dialog whether it should show itself automatically.
+ */
+ KPropertiesDialog( KFileItemList _items,
+ QWidget *parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true);
+
+#ifndef KDE_NO_COMPAT
+ /**
+ * @deprecated You should use the following constructor instead of this one.
+ * The only change that is required is to delete the _mode argument.
+ *
+ * @param _url the URL whose properties should be displayed
+ * @param _mode unused.
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * @param autoShow tells the dialog whether it should show itself automatically. */
+ KPropertiesDialog( const KURL& _url, mode_t _mode,
+ QWidget* parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true) KDE_DEPRECATED;
+#endif
+
+ /**
+ * Brings up a Properties dialog. Convenience constructor for
+ * non-file-manager applications, where you have a KURL rather than a
+ * KFileItem or KFileItemList.
+ *
+ * @param _url the URL whose properties should be displayed
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * IMPORTANT: This constructor, together with modal=true, leads to a grave
+ * display bug (due to KIO::stat() being run before the dialog has all the
+ * necessary information). Do not use this combination for now.
+ * For local files with a known mimetype, simply create a KFileItem and pass
+ * it to the other constructor.
+ *
+ * @param autoShow tells the dialog whethr it should show itself automatically.
+ */
+ KPropertiesDialog( const KURL& _url,
+ QWidget* parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true);
+
+ /**
+ * Creates a properties dialog for a new .desktop file (whose name
+ * is not known yet), based on a template. Special constructor for
+ * "File / New" in file-manager type applications.
+ *
+ * @param _tempUrl template used for reading only
+ * @param _currentDir directory where the file will be written to
+ * @param _defaultName something to put in the name field,
+ * like mimetype.desktop
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * @param autoShow tells the dialog whethr it should show itself automatically.
+ */
+ KPropertiesDialog( const KURL& _tempUrl, const KURL& _currentDir,
+ const QString& _defaultName,
+ QWidget* parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true);
+
+ /**
+ * Creates an empty properties dialog (for applications that want use
+ * a standard dialog, but for things not doable via the plugin-mechanism).
+ *
+ * @param title is the string display as the "filename" in the caption of the dialog.
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ */
+ KPropertiesDialog (const QString& title,
+ QWidget* parent = 0L, const char* name = 0L, bool modal = false);
+
+ /**
+ * Cleans up the properties dialog and frees any associated resources,
+ * including the dialog itself. Note that when a properties dialog is
+ * closed it cleans up and deletes itself.
+ */
+ virtual ~KPropertiesDialog();
+
+ /**
+ * Immediately displays a Properties dialog using constructor with
+ * the same parameters.
+ * On MS Windows, if @p item points to a local file, native (non modal) property
+ * dialog is displayed (@p parent and @p modal are ignored in this case).
+ *
+ * @return true on succesfull dialog displaying (can be false on win32).
+ * @since 3.4
+ */
+ static bool showDialog(KFileItem* item, QWidget* parent = 0,
+ const char* name = 0, bool modal = false);
+
+ /**
+ * Immediately displays a Properties dialog using constructor with
+ * the same parameters.
+ * On MS Windows, if @p _url points to a local file, native (non modal) property
+ * dialog is displayed (@p parent and @p modal are ignored in this case).
+ *
+ * @return true on succesfull dialog displaying (can be false on win32).
+ * @since 3.4
+ */
+ static bool showDialog(const KURL& _url, QWidget* parent = 0,
+ const char* name = 0, bool modal = false);
+
+ /**
+ * Immediately displays a Properties dialog using constructor with
+ * the same parameters.
+ * On MS Windows, if @p _items has one element and this element points
+ * to a local file, native (non modal) property dialog is displayed
+ * (@p parent and @p modal are ignored in this case).
+ *
+ * @return true on succesfull dialog displaying (can be false on win32).
+ * @since 3.4
+ */
+ static bool showDialog(const KFileItemList& _items, QWidget* parent = 0,
+ const char* name = 0, bool modal = false);
+
+ /**
+ * Adds a "3rd party" properties plugin to the dialog. Useful
+ * for extending the properties mechanism.
+ *
+ * To create a new plugin type, inherit from the base class KPropsDlgPlugin
+ * and implement all the methods. If you define a service .desktop file
+ * for your plugin, you do not need to call insertPlugin().
+ *
+ * @param plugin is a pointer to the KPropsDlgPlugin. The Properties
+ * dialog will do destruction for you. The KPropsDlgPlugin \b must
+ * have been created with the KPropertiesDialog as its parent.
+ * @see KPropsDlgPlugin
+ */
+ void insertPlugin (KPropsDlgPlugin *plugin);
+
+ /**
+ * The URL of the file that has its properties being displayed.
+ * This is only valid if the KPropertiesDialog was created/shown
+ * for one file or URL.
+ *
+ * @return a parsed URL.
+ */
+ const KURL& kurl() const { return m_singleUrl; }
+
+ /**
+ * @return the file item for which the dialog is shown
+ *
+ * Warning: this method returns the first item of the list.
+ * This means that you should use this only if you are sure the dialog is used
+ * for a single item. Otherwise, you probably want items() instead.
+ */
+ KFileItem *item() { return m_items.first(); }
+
+ /**
+ * @return the items for which the dialog is shown
+ */
+ KFileItemList items() const { return m_items; }
+
+ /**
+ * @return a pointer to the dialog
+ * @deprecated KPropertiesDialog directly inherits from KDialogBase, so use \a this instead
+ */
+ KDE_DEPRECATED KDialogBase* dialog() { return this; }
+ /**
+ * @return a pointer to the dialog
+ * @deprecated KPropertiesDialog directly inherits from KDialogBase, so use \a this instead
+ */
+ KDE_DEPRECATED const KDialogBase* dialog() const { return this; }
+
+ /**
+ * If the dialog is being built from a template, this method
+ * returns the current directory. If no template, it returns QString::null.
+ * See the template form of the constructor.
+ *
+ * @return the current directory or QString::null
+ */
+ const KURL& currentDir() const { return m_currentDir; }
+
+ /**
+ * If the dialog is being built from a template, this method
+ * returns the default name. If no template, it returns QString::null.
+ * See the template form of the constructor.
+ * @return the default name or QString::null
+ */
+ const QString& defaultName() const { return m_defaultName; }
+
+ /**
+ * Updates the item URL (either called by rename or because
+ * a global apps/mimelnk desktop file is being saved)
+ * Can only be called if the dialog applies to a single file or URL.
+ * @param _newUrl the new URL
+ */
+ void updateUrl( const KURL& _newUrl );
+
+ /**
+ * Renames the item to the specified name. This can only be called if
+ * the dialog applies to a single file or URL.
+ * @param _name new filename, encoded.
+ * \see FilePropsDlgPlugin::applyChanges
+ */
+ void rename( const QString& _name );
+
+ /**
+ * To abort applying changes.
+ */
+ void abortApplying();
+
+ /**
+ * Shows the page that was previously set by
+ * setFileSharingPage(), or does nothing if no page
+ * was set yet.
+ * \see setFileSharingPage
+ * @since 3.1
+ */
+ void showFileSharingPage();
+
+ /**
+ * Sets the file sharing page.
+ * This page is shown when calling showFileSharingPage().
+ *
+ * @param page the page to set
+ * \see showFileSharingPage
+ * @since 3.3
+ */
+ void setFileSharingPage(QWidget* page);
+
+ /**
+ * Call this to make the filename lineedit readonly, to prevent the user
+ * from renaming the file.
+ * \param ro true if the lineedit should be read only
+ * @since 3.2
+ */
+ void setFileNameReadOnly( bool ro );
+
+public slots:
+ /**
+ * Called when the user presses 'Ok'.
+ */
+ virtual void slotOk(); // Deletes the PropertiesDialog instance
+ /**
+ * Called when the user presses 'Cancel'.
+ */
+ virtual void slotCancel(); // Deletes the PropertiesDialog instance
+
+signals:
+ /**
+ * This signal is emitted when the Properties Dialog is closed (for
+ * example, with OK or Cancel buttons)
+ */
+ void propertiesClosed();
+
+ /**
+ * This signal is emitted when the properties changes are applied (for
+ * example, with the OK button)
+ */
+ void applied();
+
+ /**
+ * This signal is emitted when the properties changes are aborted (for
+ * example, with the Cancel button)
+ */
+
+ void canceled();
+ /**
+ * Emitted before changes to @p oldUrl are saved as @p newUrl.
+ * The receiver may change @p newUrl to point to an alternative
+ * save location.
+ */
+ void saveAs(const KURL &oldUrl, KURL &newUrl);
+
+private:
+
+ /**
+ * Common initialization for all constructors
+ */
+ void init (bool modal = false, bool autoShow = true);
+
+ /**
+ * Inserts all pages in the dialog.
+ */
+ void insertPages();
+
+ /**
+ * The URL of the props dialog (when shown for only one file)
+ */
+ KURL m_singleUrl;
+
+ /**
+ * List of items this props dialog is shown for
+ */
+ KFileItemList m_items;
+
+ /**
+ * For templates
+ */
+ QString m_defaultName;
+ KURL m_currentDir;
+
+ /**
+ * List of all plugins inserted ( first one first )
+ */
+ QPtrList<KPropsDlgPlugin> m_pageList;
+
+private slots:
+ void slotStatResult( KIO::Job * ); // No longer used
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KPropertiesDialogPrivate;
+ KPropertiesDialogPrivate *d;
+};
+
+/**
+ * A Plugin in the Properties dialog
+ * This is an abstract class. You must inherit from this class
+ * to build a new kind of tabbed page for the KPropertiesDialog.
+ * A plugin in itself is just a library containing code, not a dialog's page.
+ * It's up to the plugin to insert pages into the parent dialog.
+ *
+ * To make a plugin available, define a service that implements the KPropsDlg/Plugin
+ * servicetype, as well as the mimetypes for which the plugin should be created.
+ * For instance, ServiceTypes=KPropsDlg/Plugin,text/html,application/x-mymimetype.
+ *
+ * You can also include X-KDE-Protocol=file if you want that plugin
+ * to be loaded only for local files, for instance.
+ */
+class KIO_EXPORT KPropsDlgPlugin : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ * To insert tabs into the properties dialog, use the add methods provided by
+ * KDialogBase (the properties dialog is a KDialogBase).
+ */
+ KPropsDlgPlugin( KPropertiesDialog *_props );
+ virtual ~KPropsDlgPlugin();
+
+ /**
+ * Applies all changes to the file.
+ * This function is called when the user presses 'Ok'. The last plugin inserted
+ * is called first.
+ */
+ virtual void applyChanges();
+
+ /**
+ * Convenience method for most ::supports methods
+ * @return true if the file is a local, regular, readable, desktop file
+ */
+ static bool isDesktopFile( KFileItem * _item );
+
+ void setDirty( bool b );
+ bool isDirty() const;
+
+public slots:
+ void setDirty(); // same as setDirty( true )
+
+signals:
+ /**
+ * Emit this signal when the user changed anything in the plugin's tabs.
+ * The hosting PropertiesDialog will call applyChanges only if the
+ * PropsPlugin has emitted this signal before.
+ */
+ void changed();
+
+protected:
+ /**
+ * Pointer to the dialog
+ */
+ KPropertiesDialog *properties;
+
+ int fontHeight;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KPropsDlgPluginPrivate;
+ KPropsDlgPluginPrivate *d;
+};
+
+/**
+ * 'General' plugin
+ * This plugin displays the name of the file, its size and access times.
+ * @internal
+ */
+class KIO_EXPORT KFilePropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KFilePropsPlugin( KPropertiesDialog *_props );
+ virtual ~KFilePropsPlugin();
+
+ /**
+ * Applies all changes made. This plugin must be always the first
+ * plugin in the dialog, since this function may rename the file which
+ * may confuse other applyChanges functions.
+ */
+ virtual void applyChanges();
+
+ /**
+ * Tests whether the files specified by _items need a 'General' plugin.
+ */
+ static bool supports( KFileItemList _items );
+
+ /**
+ * Called after all plugins applied their changes
+ */
+ void postApplyChanges();
+
+ void setFileNameReadOnly( bool ro );
+
+protected slots:
+ void slotEditFileType();
+ void slotCopyFinished( KIO::Job * );
+ void slotFileRenamed( KIO::Job *, const KURL &, const KURL & );
+ void slotDirSizeUpdate();
+ void slotDirSizeFinished( KIO::Job * );
+ void slotFoundMountPoint( const QString& mp, unsigned long kBSize,
+ unsigned long kBUsed, unsigned long kBAvail );
+ void slotSizeStop();
+ void slotSizeDetermine();
+
+private slots:
+ // workaround for compiler bug
+ void slotFoundMountPoint( const unsigned long& kBSize, const unsigned long&
+ kBUsed, const unsigned long& kBAvail, const QString& mp );
+ void nameFileChanged(const QString &text );
+ void slotIconChanged();
+
+private:
+ void determineRelativePath( const QString & path );
+ void applyIconChanges();
+
+ QWidget *iconArea;
+ QWidget *nameArea;
+
+ QLabel *m_sizeLabel;
+ QPushButton *m_sizeDetermineButton;
+ QPushButton *m_sizeStopButton;
+
+ QString m_sRelativePath;
+ bool m_bFromTemplate;
+
+ /**
+ * The initial filename
+ */
+ QString oldName;
+
+ class KFilePropsPluginPrivate;
+ KFilePropsPluginPrivate *d;
+};
+
+/**
+ * 'Permissions' plugin
+ * In this plugin you can modify permissions and change
+ * the owner of a file.
+ * @internal
+ */
+class KIO_EXPORT KFilePermissionsPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ enum PermissionsMode {
+ PermissionsOnlyFiles = 0,
+ PermissionsOnlyDirs = 1,
+ PermissionsOnlyLinks = 2,
+ PermissionsMixed = 3
+ };
+
+ enum PermissionsTarget {
+ PermissionsOwner = 0,
+ PermissionsGroup = 1,
+ PermissionsOthers = 2
+ };
+
+ /**
+ * Constructor
+ */
+ KFilePermissionsPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KFilePermissionsPropsPlugin();
+
+ virtual void applyChanges();
+
+ /**
+ * Tests whether the file specified by _items needs a 'Permissions' plugin.
+ */
+ static bool supports( KFileItemList _items );
+
+private slots:
+
+ void slotChmodResult( KIO::Job * );
+ void slotShowAdvancedPermissions();
+
+private:
+ void setComboContent(QComboBox *combo, PermissionsTarget target,
+ mode_t permissions, mode_t partial);
+ bool isIrregular(mode_t permissions, bool isDir, bool isLink);
+ void enableAccessControls(bool enable);
+ void updateAccessControls();
+ void getPermissionMasks(mode_t &andFilePermissions,
+ mode_t &andDirPermissions,
+ mode_t &orFilePermissions,
+ mode_t &orDirPermissions);
+
+ static const mode_t permissionsMasks[3];
+ static const mode_t standardPermissions[4];
+ static const char *permissionsTexts[4][4];
+
+ // unused, for binary compatibility!
+ QCheckBox *permBox[3][4];
+
+ QComboBox *grpCombo;
+
+ KLineEdit *usrEdit, *grpEdit;
+
+ /**
+ * Old permissions
+ */
+ mode_t permissions;
+ /**
+ * Old group
+ */
+ QString strGroup;
+ /**
+ * Old owner
+ */
+ QString strOwner;
+
+ // unused, for compatibility
+ static mode_t fperm[3][4];
+
+ class KFilePermissionsPropsPluginPrivate;
+ KFilePermissionsPropsPluginPrivate *d;
+};
+
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * URL=....
+ *
+ * Such files are used to represent a program in kicker and konqueror.
+ * @internal
+ */
+class KIO_EXPORT KURLPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KURLPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KURLPropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+private:
+ KURLRequester *URLEdit;
+ KIconButton *iconBox;
+
+ QString URLStr;
+ QString iconStr;
+
+ QPixmap pixmap;
+ QString pixmapFile;
+private:
+ class KURLPropsPluginPrivate;
+ KURLPropsPluginPrivate *d;
+};
+
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * Type=MimeType
+ * @internal
+ */
+class KIO_EXPORT KBindingPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KBindingPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KBindingPropsPlugin();
+
+ virtual void applyChanges();
+ static bool supports( KFileItemList _items );
+
+private:
+
+ QLineEdit *commentEdit;
+ QLineEdit *patternEdit;
+ QLineEdit *mimeEdit;
+ QString m_sMimeStr;
+
+ QCheckBox * cbAutoEmbed;
+
+ class KBindingPropsPluginPrivate;
+ KBindingPropsPluginPrivate *d;
+};
+
+/**
+ * Properties plugin for device .desktop files
+ * @internal
+ */
+class KIO_EXPORT KDevicePropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ KDevicePropsPlugin( KPropertiesDialog *_props );
+ virtual ~KDevicePropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+private slots:
+ void slotActivated( int );
+ void slotDeviceChanged();
+ void slotFoundMountPoint( const unsigned long& kBSize,
+ const unsigned long& /*kBUsed*/,
+ const unsigned long& kBAvail,
+ const QString& );
+
+private:
+ void updateInfo();
+
+private:
+ QComboBox* device;
+ QLabel* mountpoint;
+ QCheckBox* readonly;
+ void* unused;
+ //KIconButton* mounted;
+ KIconButton* unmounted;
+
+ QStringList m_devicelist;
+ int indexDevice;
+ int indexMountPoint;
+ int indexFSType;
+
+ QPixmap pixmap;
+ QString pixmapFile;
+
+ class KDevicePropsPluginPrivate;
+ KDevicePropsPluginPrivate *d;
+};
+
+class KPropertiesDesktopBase;
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * Type=Application
+ *
+ * Such files are used to represent a program in kicker and konqueror.
+ * @internal
+ */
+class KIO_EXPORT KDesktopPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KDesktopPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KDesktopPropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+public slots:
+ void slotAddFiletype();
+ void slotDelFiletype();
+ void slotBrowseExec();
+ void slotAdvanced();
+ void slotSelectMimetype();
+
+private:
+ void checkCommandChanged();
+
+private:
+ KPropertiesDesktopBase* w;
+
+ QString m_origCommandStr;
+ QString m_terminalOptionStr;
+ QString m_suidUserStr;
+ QString m_dcopServiceType;
+ bool m_terminalBool;
+ bool m_terminalCloseBool;
+ bool m_suidBool;
+ bool m_startupBool;
+ bool m_systrayBool;
+
+ class KDesktopPropsPluginPrivate;
+ KDesktopPropsPluginPrivate *d;
+};
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * Type=Application
+ *
+ * Such files are used to represent a program in kicker and konqueror.
+ * @internal
+ * @deprecated replaced with KDesktopPropsPlugin
+ */
+ /// Remove in KDE4
+class KIO_EXPORT_DEPRECATED KExecPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KExecPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KExecPropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+public slots:
+ void slotBrowseExec();
+
+private slots:
+ void enableCheckedEdit();
+ void enableSuidEdit();
+
+private:
+
+ QLabel *terminalLabel;
+ QLabel *suidLabel;
+ KLineEdit *execEdit;
+ QCheckBox *terminalCheck;
+ QCheckBox *suidCheck;
+ KLineEdit *terminalEdit;
+ KLineEdit *suidEdit;
+ KLineEdit *swallowExecEdit;
+ KLineEdit *swallowTitleEdit;
+ QButton *execBrowse;
+
+ QString execStr;
+ QString swallowExecStr;
+ QString swallowTitleStr;
+ QString termOptionsStr;
+ bool termBool;
+ bool suidBool;
+ QString suidUserStr;
+
+ class KExecPropsPluginPrivate;
+ KExecPropsPluginPrivate *d;
+};
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * Type=Application
+ *
+ * Such files are used to represent a program in kicker and konqueror.
+ * @internal
+ * @deprecated replaced with KDesktopPropsPlugin
+ */
+ /// Remove in KDE4
+class KIO_EXPORT_DEPRECATED KApplicationPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KApplicationPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KApplicationPropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+public slots:
+ void slotDelExtension();
+ void slotAddExtension();
+
+private slots:
+ void updateButton();
+
+private:
+ void addMimeType( const QString & name );
+
+ QLineEdit *commentEdit;
+ QLineEdit *genNameEdit;
+ QLineEdit *nameEdit;
+ QListBox *extensionsList;
+ QListBox *availableExtensionsList;
+ QPushButton *addExtensionButton;
+ QPushButton *delExtensionButton;
+
+ class KApplicationPropsPluginPrivate;
+ KApplicationPropsPluginPrivate *d;
+};
+
+#endif
+
diff --git a/kio/kfile/kpropertiesmimetypebase.ui b/kio/kfile/kpropertiesmimetypebase.ui
new file mode 100644
index 000000000..0223f22a6
--- /dev/null
+++ b/kio/kfile/kpropertiesmimetypebase.ui
@@ -0,0 +1,70 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KPropertiesMimetypeBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>widget2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>265</width>
+ <height>213</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Select one or more file types to add:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>listView</cstring>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Mimetype</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Description</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>listView</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;Select one or more types of file that your application can handle here. This list is organized by &lt;u&gt;mimetypes&lt;/u&gt;.&lt;/p&gt;
+&lt;p&gt;MIME, Multipurpose Internet (e)Mail Extension, is a standard protocol for identifying the type of data based on filename extensions and correspondent &lt;u&gt;mimetypes&lt;/u&gt;. Example: the "bmp" part that comes after the dot in flower.bmp indicates that it is a specific kind of image, &lt;u&gt;image/x-bmp&lt;/u&gt;. To know which application should open each type of file, the system should be informed about the abilities of each application to handle these extensions and mimetypes.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">klistview.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kio/kfile/kpropsdlg.h b/kio/kfile/kpropsdlg.h
new file mode 100644
index 000000000..502a346e9
--- /dev/null
+++ b/kio/kfile/kpropsdlg.h
@@ -0,0 +1,4 @@
+// This is now called kpropertiesdialog.h
+#ifndef KDE_NO_COMPAT
+#include <kpropertiesdialog.h>
+#endif
diff --git a/kio/kfile/kpropsdlgplugin.desktop b/kio/kfile/kpropsdlgplugin.desktop
new file mode 100644
index 000000000..cb4405bb2
--- /dev/null
+++ b/kio/kfile/kpropsdlgplugin.desktop
@@ -0,0 +1,87 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KPropsDlg/Plugin
+Comment=Plugin for the Properties Dialog
+Comment[af]=Inprop module vir die Eienskappe Dialoog
+Comment[ar]=ملحق لمربع حوار خصائص
+Comment[az]=SeçənÉ™klÉ™r RabitÉ™ Qutusu Üçün ÆlavÉ™
+Comment[bg]=ПриÑтавка за диалога "ИнформациÑ"
+Comment[bn]=বৈশিষà§à¦Ÿà§à¦¯à¦¾à¦¬à¦²à§€ ডায়ালগ-à¦à¦° জনà§à¦¯ পà§à¦²à¦¾à¦—-ইন
+Comment[br]=Adveziant evit kendiviz ar perzhioù
+Comment[bs]=Dodatak za Properties dijalog
+Comment[ca]=Connector per al diàleg de les propietats
+Comment[cs]=Modul pro dialog vlastností
+Comment[csb]=Plugins dialogòwégò òkna Swòjiznë
+Comment[cy]=Ategyn am yr Ymgom Priodweddau
+Comment[da]=Plugin til egenskabsdialog
+Comment[de]=Erweiterung für den Eigenschaften-Dialog
+Comment[el]=ΠÏόσθετο για το Διάλογο ιδιοτήτων
+Comment[en_GB]=Plugin for the Properties Dialogue
+Comment[eo]=Internaĵo por la Eco-dialogo
+Comment[es]=Plugin para el diálogo de propiedades
+Comment[et]=Omaduste dialoogi plugin
+Comment[eu]=Propietateen elkarrizketa-koadroaren plugin-a
+Comment[fa]=وصله برای محاورۀ ویژگیها
+Comment[fi]=Lisäosa asetusikkunalle
+Comment[fr]=Module externe pour la boîte de dialogue des propriétés
+Comment[fy]=Plugin foar de 'Eigenskippen'-dialooch
+Comment[gl]=Plugin para o Diálogo de Propriedades
+Comment[he]=תוסף לדו־שיח המ×פייני×
+Comment[hi]=विशेषता संवाद के लिठपà¥à¤²à¤—इन
+Comment[hr]=Dodatak dijaloga 'Svojstva'
+Comment[hu]=Beépülő modul a tulajdonságok párbeszédablakhoz
+Comment[id]=Plugin untuk Dialog Properties
+Comment[is]=Ãforrit fyrir stillingarforritið
+Comment[it]=Plugin per la finestra delle proprietà
+Comment[ja]=設定ダイアログプラグイン
+Comment[ka]=პáƒáƒ áƒáƒ›áƒ”ტრების გáƒáƒ›áƒáƒ áƒ—ვის დიáƒáƒšáƒáƒ’ის მáƒáƒ“ული
+Comment[kk]=ҚаÑиеттер диалогтың модулі
+Comment[km]=កម្មវិធី​ជំនួយ​ážáž¶áž„​ក្នុង​សម្រាប់​ប្រអប់ លក្ážážŽáŸˆâ€‹ážŸáž˜áŸ’áž”ážáŸ’ážáž·
+Comment[ko]=대화창 íŠ¹ì„±ì„ ìœ„í•œ 플러그ì¸
+Comment[lb]=Plugin fir den Eegeschaften-Dialog
+Comment[lt]=Priedas savybių dialogui
+Comment[lv]=Īpašību Dialoga Iespraudnis
+Comment[mk]=Приклучок за дијалогот за ÑвојÑтва
+Comment[mn]=Шинж чанарууд диалогийн Plugin
+Comment[ms]=Plugmasuk untuk Dialog Ciri-ciri
+Comment[mt]=Plugin għad-djalogu tal-propjetajiet
+Comment[nb]=Programtillegg for dialogvinduet for egenskaper
+Comment[nds]=Plugin för den Egenschappen-Dialoog
+Comment[ne]=विशेषता संवादका लागि पà¥à¤²à¤—इन
+Comment[nl]=Plugin voor de 'Eigenschappen'-dialoog
+Comment[nn]=Tillegg til eigenskapar-dialogen
+Comment[nso]=Tsenyo ya Poledisano ya Dithoto
+Comment[oc]=Branquament pel dialeg de propietats
+Comment[pa]=ਵਿਸ਼ੇਸਤਾ ਵਾਰਤਾਲਾਪ ਲਈ ਪਲੱਗਿੰਨ
+Comment[pl]=Wtyczka do okna dialogowego Właściwości
+Comment[pt]='Plugin' para o diálogo de propriedades
+Comment[pt_BR]=Plug-in para a janela de Propriedades
+Comment[ro]=Modul pentru dialogul de proprietăţi
+Comment[ru]=Модуль Ð´Ð»Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð° наÑтроек
+Comment[rw]=Icomeka ry'Ikiganiro cy'Ibiranga
+Comment[se]=Lassemoduvla iešvuođahtaláseža várás
+Comment[sk]=modul pre ialóg ílastnosti
+Comment[sl]=Vstavek za pogovorno okno z lastnostmi
+Comment[sq]=Shtojcë për Dialogun e Rekuizitave
+Comment[sr]=Прикључак за дијалог Ñа ÑвојÑтвима
+Comment[sr@Latn]=PrikljuÄak za dijalog sa svojstvima
+Comment[sv]=Insticksprogram för egenskapsdialogen
+Comment[ta]=பணà¯à®ªà¯à®•à®³à¯ உரையாடலà¯à®•à¯à®•à®¾à®© சொரà¯à®•à¯à®ªà¯à®ªà¯Šà®°à¯à®³à¯
+Comment[te]=లకà±à°·à°£à°¾à°² సంభాషణ కొరకౠపà±à°²à°—à°¿à°¨à±
+Comment[tg]=ШтепÑели барои ХуÑуÑиÑтҳои Тирезаи Диалогӣ Ðндохтан
+Comment[th]=ปลั๊à¸à¸­à¸´à¸™à¸ªà¸³à¸«à¸£à¸±à¸šà¸à¸¥à¹ˆà¸­à¸‡à¸„ุณสมบัติ
+Comment[tr]=Özellikler İletişim Kutusu İçin Eklenti
+Comment[tt]=Caylaw Dialogı öçen Östämä
+Comment[uk]=Втулок Ð´Ð»Ñ Ð´Ñ–Ð°Ð»Ð¾Ð³Ñƒ влаÑтивоÑтей
+Comment[uz]=Xossalar dialogi uchun plagin
+Comment[uz@cyrillic]=ХоÑÑалар диалоги учун плагин
+Comment[ven]=U pulaga ha zwishumiswa zwa nyambedzano
+Comment[vi]=Bộ cầm phít cho hộp thoại đặc tả.
+Comment[xh]=Iplagi yangaphakathi Yezinto zobumnini Zencoko yababini
+Comment[zh_CN]=属性对è¯çš„æ’件
+Comment[zh_HK]=屬性å°è©±ç›’的外掛程å¼
+Comment[zh_TW]=屬性å°è©±ç›’的外掛程å¼
+Comment[zu]=I-plugin Yengxoxo Yezinkomba zobunini
+
+[PropertyDef::X-KDE-Protocol]
+Type=QString
diff --git a/kio/kfile/krecentdirs.cpp b/kio/kfile/krecentdirs.cpp
new file mode 100644
index 000000000..b32dd0481
--- /dev/null
+++ b/kio/kfile/krecentdirs.cpp
@@ -0,0 +1,99 @@
+/* -*- c++ -*-
+ * Copyright (C)2000 Waldo Bastian <bastian@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <krecentdirs.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kglobalsettings.h>
+
+#define MAX_DIR_HISTORY 3
+
+static void recentdirs_done(KConfig *config)
+{
+ if (config == KGlobal::config())
+ {
+ config->sync();
+ }
+ else
+ {
+ delete config;
+ }
+}
+
+static KConfig *recentdirs_readList(QString &key, QStringList &result, bool readOnly)
+{
+ KConfig *config;
+ if ((key.length() < 2) || (key[0] != ':'))
+ key = ":default";
+ if (key[1] == ':')
+ {
+ key = key.mid(2);
+ config = new KSimpleConfig(QString::fromLatin1("krecentdirsrc"), readOnly);
+ }
+ else
+ {
+ key = key.mid(1);
+ config = KGlobal::config();
+ config->setGroup(QString::fromLatin1("Recent Dirs"));
+ }
+
+ result=config->readPathListEntry(key);
+ if (result.isEmpty())
+ {
+ result.append(KGlobalSettings::documentPath());
+ }
+ return config;
+}
+
+QStringList KRecentDirs::list(const QString &fileClass)
+{
+ QString key = fileClass;
+ QStringList result;
+ recentdirs_done(recentdirs_readList(key, result, true));
+ return result;
+}
+
+QString KRecentDirs::dir(const QString &fileClass)
+{
+ QStringList result = list(fileClass);
+ return result[0];
+}
+
+void KRecentDirs::add(const QString &fileClass, const QString &directory)
+{
+ QString key = fileClass;
+ QStringList result;
+ KConfig *config = recentdirs_readList(key, result, false);
+ // make sure the dir is first in history
+ result.remove(directory);
+ result.prepend(directory);
+ while(result.count() > MAX_DIR_HISTORY)
+ result.remove(result.fromLast());
+ config->writePathEntry(key, result);
+ recentdirs_done(config);
+}
+
diff --git a/kio/kfile/krecentdirs.h b/kio/kfile/krecentdirs.h
new file mode 100644
index 000000000..078efcc50
--- /dev/null
+++ b/kio/kfile/krecentdirs.h
@@ -0,0 +1,70 @@
+/* -*- c++ -*-
+ * Copyright (C)2000 Waldo Bastian <bastian@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef __KRECENTDIRS_H
+#define __KRECENTDIRS_H
+
+#include <qstringlist.h>
+
+#include <kdelibs_export.h>
+
+/**
+ * The goal of this class is to make sure that, when the user needs to
+ * specify a file via the file selection dialog, this dialog will start
+ * in the directory most likely to contain the desired files.
+ *
+ * This works as follows: Each time the file selection dialog is
+ * shown, the programmer can specify a "file-class". The file-dialog will
+ * then start with the directory associated with this file-class. When
+ * the dialog closes, the directory currently shown in the file-dialog
+ * will be associated with the file-class.
+ *
+ * A file-class can either start with ':' or with '::'. If it starts with
+ * a single ':' the file-class is specific to the current application.
+ * If the file-class starts with '::' it is global to all applications.
+ */
+class KIO_EXPORT KRecentDirs
+{
+public:
+ /**
+ * Returns a list of directories associated with this file-class.
+ * The most recently used directory is at the front of the list.
+ */
+ static QStringList list(const QString &fileClass);
+
+ /**
+ * Returns the most recently used directory accociated with this file-class.
+ */
+ static QString dir(const QString &fileClass);
+
+ /**
+ * Associates @p directory with @p fileClass
+ */
+ static void add(const QString &fileClass, const QString &directory);
+};
+
+#endif
diff --git a/kio/kfile/krecentdocument.cpp b/kio/kfile/krecentdocument.cpp
new file mode 100644
index 000000000..9b3d4f75f
--- /dev/null
+++ b/kio/kfile/krecentdocument.cpp
@@ -0,0 +1,177 @@
+/* -*- c++ -*-
+ * Copyright (C)2000 Daniel M. Duley <mosfet@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <krecentdocument.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <kmimetype.h>
+#include <kdesktopfile.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qtextstream.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+
+#include <sys/types.h>
+#include <utime.h>
+
+QString KRecentDocument::recentDocumentDirectory()
+{
+ // need to change this path, not sure where
+ return locateLocal("data", QString::fromLatin1("RecentDocuments/"));
+}
+
+QStringList KRecentDocument::recentDocuments()
+{
+ QDir d(recentDocumentDirectory(), "*.desktop", QDir::Time,
+ QDir::Files | QDir::Readable | QDir::Hidden);
+
+ if (!d.exists())
+ d.mkdir(recentDocumentDirectory());
+
+ QStringList list = d.entryList();
+ QStringList fullList;
+
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ QString pathDesktop = d.absFilePath( *it );
+ KDesktopFile tmpDesktopFile( pathDesktop, false);
+ KURL urlDesktopFile(tmpDesktopFile.readURL());
+ if( urlDesktopFile.isLocalFile() && !QFile(urlDesktopFile.path()).exists())
+ d.remove(pathDesktop);
+ else
+ fullList.append( pathDesktop );
+ }
+
+ return fullList;
+}
+
+void KRecentDocument::add(const KURL& url)
+{
+ KRecentDocument::add(url, qApp->argv()[0]); // ### argv[0] might not match the service filename!
+}
+
+void KRecentDocument::add(const KURL& url, const QString& desktopEntryName)
+{
+ if ( url.isLocalFile() && !KGlobal::dirs()->relativeLocation("tmp", url.path()).startsWith("/"))
+ return;
+
+ QString openStr = url.url();
+ openStr.replace( QRegExp("\\$"), "$$" ); // Desktop files with type "Link" are $-variable expanded
+
+ kdDebug(250) << "KRecentDocument::add for " << openStr << endl;
+ KConfig *config = KGlobal::config();
+ QString oldGrp = config->group();
+ config->setGroup(QString::fromLatin1("RecentDocuments"));
+ bool useRecent = config->readBoolEntry(QString::fromLatin1("UseRecent"), true);
+ int maxEntries = config->readNumEntry(QString::fromLatin1("MaxEntries"), 10);
+
+ config->setGroup(oldGrp);
+ if(!useRecent)
+ return;
+
+ QString path = recentDocumentDirectory();
+
+ QString dStr = path + url.fileName();
+
+ QString ddesktop = dStr + QString::fromLatin1(".desktop");
+
+ int i=1;
+ // check for duplicates
+ while(QFile::exists(ddesktop)){
+ // see if it points to the same file and application
+ KSimpleConfig tmp(ddesktop);
+ tmp.setDesktopGroup();
+ if(tmp.readEntry(QString::fromLatin1("X-KDE-LastOpenedWith"))
+ == desktopEntryName)
+ {
+ utime(QFile::encodeName(ddesktop), NULL);
+ return;
+ }
+ // if not append a (num) to it
+ ++i;
+ if ( i > maxEntries )
+ break;
+ ddesktop = dStr + QString::fromLatin1("[%1].desktop").arg(i);
+ }
+
+ QDir dir(path);
+ // check for max entries, delete oldest files if exceeded
+ QStringList list = dir.entryList(QDir::Files | QDir::Hidden, QDir::Time | QDir::Reversed);
+ i = list.count();
+ if(i > maxEntries-1){
+ QStringList::Iterator it;
+ it = list.begin();
+ while(i > maxEntries-1){
+ QFile::remove(dir.absPath() + QString::fromLatin1("/") + (*it));
+ --i, ++it;
+ }
+ }
+
+ // create the applnk
+ KSimpleConfig conf(ddesktop);
+ conf.setDesktopGroup();
+ conf.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Link") );
+ conf.writePathEntry( QString::fromLatin1("URL"), openStr );
+ // If you change the line below, change the test in the above loop
+ conf.writeEntry( QString::fromLatin1("X-KDE-LastOpenedWith"), desktopEntryName );
+ QString name = url.fileName();
+ if (name.isEmpty())
+ name = openStr;
+ conf.writeEntry( QString::fromLatin1("Name"), name );
+ conf.writeEntry( QString::fromLatin1("Icon"), KMimeType::iconForURL( url ) );
+}
+
+void KRecentDocument::add(const QString &openStr, bool isUrl)
+{
+ if( isUrl ) {
+ add( KURL( openStr ) );
+ } else {
+ KURL url;
+ url.setPath( openStr );
+ add( url );
+ }
+}
+
+void KRecentDocument::clear()
+{
+ QStringList list = recentDocuments();
+ QDir dir;
+ for(QStringList::Iterator it = list.begin(); it != list.end() ; ++it)
+ dir.remove(*it);
+}
+
+int KRecentDocument::maximumItems()
+{
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver sa(config, QString::fromLatin1("RecentDocuments"));
+ return config->readNumEntry(QString::fromLatin1("MaxEntries"), 10);
+}
+
+
diff --git a/kio/kfile/krecentdocument.h b/kio/kfile/krecentdocument.h
new file mode 100644
index 000000000..5ec06c162
--- /dev/null
+++ b/kio/kfile/krecentdocument.h
@@ -0,0 +1,105 @@
+/* -*- c++ -*-
+ * Copyright (C)2000 Daniel M. Duley <mosfet@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef __KRECENTDOCUMENT_H
+#define __KRECENTDOCUMENT_H
+
+#include <qstring.h>
+#include <kurl.h>
+
+/**
+ * Manage the "Recent Document Menu" entries displayed by
+ * applications such as Kicker and Konqueror.
+ *
+ * These entries are automatically generated .desktop files pointing
+ * to the current application and document. You should call the
+ * static add() method whenever the user opens or saves a new
+ * document if you want it to show up in the menu.
+ *
+ * You don't have to worry about this if you are using any
+ * KFileDialog derived class to open and save documents, as it
+ * already calls this class. User defined limits on the maximum
+ * number of documents to save, etc... are all automatically handled.
+ *
+ * @author Daniel M. Duley <mosfet@kde.org>
+ */
+class KIO_EXPORT KRecentDocument
+{
+public:
+
+ /**
+ *
+ * Return a list of absolute paths to recent document .desktop files,
+ * sorted by date.
+ *
+ */
+ static QStringList recentDocuments();
+
+ /**
+ * Add a new item to the Recent Document menu.
+ *
+ * @param url The url to add.
+ */
+ static void add(const KURL& url);
+
+ /**
+ * Add a new item to the Recent Document menu, specifying the application to open it with.
+ * The above add() method uses argv[0] for the app name, which isn't always flexible enough.
+ * This method is used when an application launches another one to open a document.
+ *
+ * @param url The url to add.
+ * @param desktopEntryName The desktopEntryName of the service to use for opening this document.
+ */
+ static void add(const KURL& url, const QString& desktopEntryName);
+
+ /**
+ *
+ * Add a new item to the Recent Document menu. Calls add( url ).
+ *
+ * @param documentStr The full path to the document or URL to add.
+ * @param isURL Set to @p true if @p documentStr is an URL and not a local file path.
+ */
+ static void add(const QString &documentStr, bool isURL = false);
+
+ /**
+ * Clear the recent document menu of all entries.
+ */
+ static void clear();
+
+ /**
+ * Returns the maximum amount of recent document entries allowed.
+ */
+ static int maximumItems();
+
+ /**
+ * Returns the path to the directory where recent document .desktop files
+ * are stored.
+ */
+ static QString recentDocumentDirectory();
+};
+
+#endif
diff --git a/kio/kfile/kurlbar.cpp b/kio/kfile/kurlbar.cpp
new file mode 100644
index 000000000..446087522
--- /dev/null
+++ b/kio/kfile/kurlbar.cpp
@@ -0,0 +1,1036 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <unistd.h>
+
+#include <qapplication.h>
+#include <qcheckbox.h>
+#include <qdrawutil.h>
+#include <qfontmetrics.h>
+#include <qlabel.h>
+#include <qgrid.h>
+#include <qpainter.h>
+#include <qpopupmenu.h>
+#include <qstyle.h>
+#include <qvbox.h>
+#include <qwhatsthis.h>
+
+#include <kaboutdata.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kicondialog.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmimetype.h>
+#include <kprotocolinfo.h>
+#include <kstringhandler.h>
+#include <kurldrag.h>
+#include <kurlrequester.h>
+
+#include "kurlbar.h"
+
+/**
+ * Handles tooltips in the KURLBar
+ * @internal
+ */
+class KURLBarToolTip : public QToolTip
+{
+public:
+ KURLBarToolTip( QListBox *view ) : QToolTip( view ), m_view( view ) {}
+
+protected:
+ virtual void maybeTip( const QPoint& point ) {
+ QListBoxItem *item = m_view->itemAt( point );
+ if ( item ) {
+ QString text = static_cast<KURLBarItem*>( item )->toolTip();
+ if ( !text.isEmpty() )
+ tip( m_view->itemRect( item ), text );
+ }
+ }
+
+private:
+ QListBox *m_view;
+};
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+class KURLBarItem::KURLBarItemPrivate
+{
+public:
+ KURLBarItemPrivate()
+ {
+ isPersistent = true;
+ }
+
+ bool isPersistent;
+};
+
+KURLBarItem::KURLBarItem( KURLBar *parent,
+ const KURL& url, bool persistent, const QString& description,
+ const QString& icon, KIcon::Group group )
+ : QListBoxPixmap( KIconLoader::unknown() /*, parent->listBox()*/ ),
+ m_url( url ),
+ m_pixmap( 0L ),
+ m_parent( parent ),
+ m_appLocal( true )
+{
+ init( icon, group, description, persistent );
+}
+
+KURLBarItem::KURLBarItem( KURLBar *parent,
+ const KURL& url, const QString& description,
+ const QString& icon, KIcon::Group group )
+ : QListBoxPixmap( KIconLoader::unknown() /*, parent->listBox()*/ ),
+ m_url( url ),
+ m_pixmap( 0L ),
+ m_parent( parent ),
+ m_appLocal( true )
+{
+ init( icon, group, description, true /*persistent*/ );
+}
+
+void KURLBarItem::init( const QString& icon, KIcon::Group group,
+ const QString& description, bool persistent )
+{
+ d = new KURLBarItemPrivate;
+ d->isPersistent = persistent;
+
+ setCustomHighlighting( true );
+ setIcon( icon, group );
+ setDescription( description );
+}
+
+KURLBarItem::~KURLBarItem()
+{
+ delete d;
+}
+
+void KURLBarItem::setURL( const KURL& url )
+{
+ m_url = url;
+ if ( m_description.isEmpty() )
+ setText( url.fileName() );
+}
+
+void KURLBarItem::setIcon( const QString& icon, KIcon::Group group )
+{
+ m_icon = icon;
+ m_group = group;
+
+ if ( icon.isEmpty() )
+ m_pixmap = KMimeType::pixmapForURL( m_url, 0, group, iconSize() );
+ else
+ m_pixmap = KGlobal::iconLoader()->loadIcon( icon, group, iconSize(),
+ KIcon::DefaultState );
+}
+
+void KURLBarItem::setDescription( const QString& desc )
+{
+ m_description = desc;
+ setText( desc.isEmpty() ? m_url.fileName() : desc );
+}
+
+void KURLBarItem::setApplicationLocal( bool local )
+{
+ if ( !local && !isPersistent() )
+ {
+ kdWarning() << "KURLBar: dynamic (non-persistent) items can not be global." << endl;
+ return;
+ }
+
+ m_appLocal = local;
+}
+
+void KURLBarItem::setToolTip( const QString& tip )
+{
+ m_toolTip = tip;
+}
+
+QString KURLBarItem::toolTip() const
+{
+ return m_toolTip.isEmpty() ? m_url.prettyURL() : m_toolTip;
+}
+
+int KURLBarItem::iconSize() const
+{
+ return m_parent->iconSize();
+}
+
+void KURLBarItem::paint( QPainter *p )
+{
+ QListBox *box = listBox();
+ int w = width( box );
+ static const int margin = KDialog::spacingHint();
+
+ // draw sunken selection
+ if ( isCurrent() || isSelected() ) {
+ int h = height( box );
+
+ QBrush brush = box->colorGroup().brush( QColorGroup::Highlight );
+ p->fillRect( 0, 0, w, h, brush );
+ QPen pen = p->pen();
+ QPen oldPen = pen;
+ pen.setColor( box->colorGroup().mid() );
+ p->setPen( pen );
+
+ p->drawPoint( 0, 0 );
+ p->drawPoint( 0, h - 1 );
+ p->drawPoint( w - 1, 0 );
+ p->drawPoint( w - 1, h - 1 );
+
+ p->setPen( oldPen );
+ }
+
+ if ( m_parent->iconSize() < KIcon::SizeMedium ) {
+ // small icon -> draw icon next to text
+
+ // ### mostly cut & paste of QListBoxPixmap::paint() until Qt 3.1
+ // (where it will properly use pixmap() instead of the internal pixmap)
+ const QPixmap *pm = pixmap();
+ int yPos = QMAX( 0, (height(box) - pm->height())/2 );
+
+ p->drawPixmap( margin, yPos, *pm );
+ if ( !text().isEmpty() ) {
+ QFontMetrics fm = p->fontMetrics();
+ if ( pm->height() < fm.height() )
+ yPos = fm.ascent() + fm.leading()/2;
+ else
+ yPos = pm->height()/2 - fm.height()/2 + fm.ascent();
+
+ yPos += margin;
+ int stringWidth = box->width() - pm->width() - 2 - (margin * 2);
+ QString visibleText = KStringHandler::rPixelSqueeze( text(), fm, stringWidth );
+ int xPos = pm->width() + margin + 2;
+
+ if ( isCurrent() || isSelected() ) {
+ p->setPen( box->colorGroup().highlight().dark(115) );
+ p->drawText( xPos + ( QApplication::reverseLayout() ? -1 : 1),
+ yPos + 1, visibleText );
+ p->setPen( box->colorGroup().highlightedText() );
+ }
+
+ p->drawText( xPos, yPos, visibleText );
+ }
+ // end cut & paste (modulo pixmap centering)
+ }
+
+ else {
+ // big icons -> draw text below icon
+ int y = margin;
+ const QPixmap *pm = pixmap();
+
+ if ( !pm->isNull() ) {
+ int x = (w - pm->width()) / 2;
+ x = QMAX( x, margin );
+ p->drawPixmap( x, y, *pm );
+ }
+
+ if ( !text().isEmpty() ) {
+ QFontMetrics fm = p->fontMetrics();
+ y += pm->height() + fm.height() - fm.descent();
+
+ int stringWidth = box->width() - (margin * 2);
+ QString visibleText = KStringHandler::rPixelSqueeze( text(), fm, stringWidth );
+ int x = (w - fm.width( visibleText )) / 2;
+ x = QMAX( x, margin );
+
+ if ( isCurrent() || isSelected() ) {
+ p->setPen( box->colorGroup().highlight().dark(115) );
+ p->drawText( x + ( QApplication::reverseLayout() ? -1 : 1),
+ y + 1, visibleText );
+ p->setPen( box->colorGroup().highlightedText() );
+ }
+
+ p->drawText( x, y, visibleText );
+ }
+ }
+}
+
+QSize KURLBarItem::sizeHint() const
+{
+ int wmin = 0;
+ int hmin = 0;
+ const KURLBarListBox *lb =static_cast<const KURLBarListBox*>(listBox());
+
+ if ( m_parent->iconSize() < KIcon::SizeMedium ) {
+ wmin = QListBoxPixmap::width( lb ) + KDialog::spacingHint() * 2;
+ hmin = QListBoxPixmap::height( lb ) + KDialog::spacingHint() * 2;
+ }
+ else {
+ wmin = QMAX(lb->fontMetrics().width(text()), pixmap()->width()) + KDialog::spacingHint() * 2;
+ hmin = lb->fontMetrics().lineSpacing() + pixmap()->height() + KDialog::spacingHint() * 2;
+ }
+
+ if ( lb->isVertical() )
+ wmin = QMIN( wmin, lb->viewport()->sizeHint().width() );
+ else
+ hmin = QMIN( hmin, lb->viewport()->sizeHint().height() );
+
+ return QSize( wmin, hmin );
+}
+
+int KURLBarItem::width( const QListBox *lb ) const
+{
+ if ( static_cast<const KURLBarListBox *>( lb )->isVertical() )
+ return QMAX( sizeHint().width(), lb->viewport()->width() );
+ else
+ return sizeHint().width();
+}
+
+int KURLBarItem::height( const QListBox *lb ) const
+{
+ if ( static_cast<const KURLBarListBox *>( lb )->isVertical() )
+ return sizeHint().height();
+ else
+ return QMAX( sizeHint().height(), lb->viewport()->height() );
+}
+
+bool KURLBarItem::isPersistent() const
+{
+ return d->isPersistent;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+class KURLBar::KURLBarPrivate
+{
+public:
+ KURLBarPrivate()
+ {
+ currentURL.setPath( QDir::homeDirPath() );
+ defaultIconSize = 0;
+ }
+
+ int defaultIconSize;
+ KURL currentURL;
+};
+
+
+KURLBar::KURLBar( bool useGlobalItems, QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f ),
+ m_activeItem( 0L ),
+ m_useGlobal( useGlobalItems ),
+ m_isModified( false ),
+ m_isImmutable( false ),
+ m_listBox( 0L ),
+ m_iconSize( KIcon::SizeMedium )
+{
+ d = new KURLBarPrivate();
+
+ setListBox( 0L );
+ setSizePolicy( QSizePolicy( isVertical() ?
+ QSizePolicy::Maximum :
+ QSizePolicy::Preferred,
+ isVertical() ?
+ QSizePolicy::Preferred :
+ QSizePolicy::Maximum ));
+ QWhatsThis::add(this, i18n("<qt>The <b>Quick Access</b> panel provides easy access to commonly used file locations.<p>"
+ "Clicking on one of the shortcut entries will take you to that location.<p>"
+ "By right clicking on an entry you can add, edit and remove shortcuts.</qt>"));
+}
+
+KURLBar::~KURLBar()
+{
+ delete d;
+}
+
+KURLBarItem * KURLBar::insertItem(const KURL& url, const QString& description,
+ bool applicationLocal,
+ const QString& icon, KIcon::Group group )
+{
+ KURLBarItem *item = new KURLBarItem(this, url, description, icon, group);
+ item->setApplicationLocal( applicationLocal );
+ m_listBox->insertItem( item );
+ return item;
+}
+
+KURLBarItem * KURLBar::insertDynamicItem(const KURL& url, const QString& description,
+ const QString& icon, KIcon::Group group )
+{
+ KURLBarItem *item = new KURLBarItem(this, url, false, description, icon, group);
+ m_listBox->insertItem( item );
+ return item;
+}
+
+void KURLBar::setOrientation( Qt::Orientation orient )
+{
+ m_listBox->setOrientation( orient );
+ setSizePolicy( QSizePolicy( isVertical() ?
+ QSizePolicy::Maximum :
+ QSizePolicy::Preferred,
+ isVertical() ?
+ QSizePolicy::Preferred :
+ QSizePolicy::Maximum ));
+}
+
+Qt::Orientation KURLBar::orientation() const
+{
+ return m_listBox->orientation();
+}
+
+void KURLBar::setListBox( KURLBarListBox *view )
+{
+ delete m_listBox;
+
+ if ( !view ) {
+ m_listBox = new KURLBarListBox( this, "urlbar listbox" );
+ setOrientation( Vertical );
+ }
+ else {
+ m_listBox = view;
+ if ( m_listBox->parentWidget() != this )
+ m_listBox->reparent( this, QPoint(0,0) );
+ m_listBox->resize( width(), height() );
+ }
+
+ m_listBox->setSelectionMode( KListBox::Single );
+ paletteChange( palette() );
+ m_listBox->setFocusPolicy( TabFocus );
+
+ connect( m_listBox, SIGNAL( mouseButtonClicked( int, QListBoxItem *, const QPoint & ) ),
+ SLOT( slotSelected( int, QListBoxItem * )));
+ connect( m_listBox, SIGNAL( dropped( QDropEvent * )),
+ this, SLOT( slotDropped( QDropEvent * )));
+ connect( m_listBox, SIGNAL( contextMenuRequested( QListBoxItem *,
+ const QPoint& )),
+ SLOT( slotContextMenuRequested( QListBoxItem *, const QPoint& )));
+ connect( m_listBox, SIGNAL( returnPressed( QListBoxItem * ) ),
+ SLOT( slotSelected( QListBoxItem * ) ));
+}
+
+void KURLBar::setIconSize( int size )
+{
+ if ( size == m_iconSize )
+ return;
+
+ m_iconSize = size;
+
+ // reload the icons with the new size
+ KURLBarItem *item = static_cast<KURLBarItem*>( m_listBox->firstItem() );
+ while ( item ) {
+ item->setIcon( item->icon(), item->iconGroup() );
+ item = static_cast<KURLBarItem*>( item->next() );
+ }
+
+ resize( sizeHint() );
+ updateGeometry();
+}
+
+void KURLBar::clear()
+{
+ m_listBox->clear();
+}
+
+void KURLBar::resizeEvent( QResizeEvent *e )
+{
+ QFrame::resizeEvent( e );
+ m_listBox->resize( width(), height() );
+}
+
+void KURLBar::paletteChange( const QPalette & )
+{
+ QPalette pal = palette();
+ QColor gray = pal.color( QPalette::Normal, QColorGroup::Background );
+ QColor selectedTextColor = pal.color( QPalette::Normal, QColorGroup::BrightText );
+ QColor foreground = pal.color( QPalette::Normal, QColorGroup::Foreground );
+ pal.setColor( QPalette::Normal, QColorGroup::Base, gray );
+ pal.setColor( QPalette::Normal, QColorGroup::HighlightedText, selectedTextColor );
+ pal.setColor( QPalette::Normal, QColorGroup::Text, foreground );
+ pal.setColor( QPalette::Inactive, QColorGroup::Base, gray );
+ pal.setColor( QPalette::Inactive, QColorGroup::HighlightedText, selectedTextColor );
+ pal.setColor( QPalette::Inactive, QColorGroup::Text, foreground );
+
+ setPalette( pal );
+}
+
+QSize KURLBar::sizeHint() const
+{
+ return m_listBox->sizeHint();
+
+#if 0
+ // this code causes vertical and or horizontal scrollbars appearing
+ // depending on the text, font, moonphase and earth rotation. Just using
+ // m_listBox->sizeHint() fixes this (although the widget can then be
+ // resized to a smaller size so that scrollbars appear).
+ int w = 0;
+ int h = 0;
+ KURLBarItem *item;
+ bool vertical = isVertical();
+
+ for ( item = static_cast<KURLBarItem*>( m_listBox->firstItem() );
+ item;
+ item = static_cast<KURLBarItem*>( item->next() ) ) {
+
+ QSize sh = item->sizeHint();
+
+ if ( vertical ) {
+ w = QMAX( w, sh.width() );
+ h += sh.height();
+ }
+ else {
+ w += sh.width();
+ h = QMAX( h, sh.height() );
+ }
+ }
+
+// if ( vertical && m_listBox->verticalScrollBar()->isVisible() )
+// w += m_listBox->verticalScrollBar()->width();
+// else if ( !vertical && m_listBox->horizontalScrollBar()->isVisible() )
+// h += m_listBox->horizontalScrollBar()->height();
+
+ if ( w == 0 && h == 0 )
+ return QSize( 100, 200 );
+ else
+ return QSize( 6 + w, h );
+#endif
+}
+
+QSize KURLBar::minimumSizeHint() const
+{
+ QSize s = sizeHint(); // ###
+ int w = s.width() + m_listBox->verticalScrollBar()->width();
+ int h = s.height() + m_listBox->horizontalScrollBar()->height();
+ return QSize( w, h );
+}
+
+void KURLBar::slotSelected( int button, QListBoxItem *item )
+{
+ if ( button != Qt::LeftButton )
+ return;
+
+ slotSelected( item );
+}
+
+void KURLBar::slotSelected( QListBoxItem *item )
+{
+ if ( item && item != m_activeItem )
+ m_activeItem = static_cast<KURLBarItem*>( item );
+
+ if ( m_activeItem ) {
+ m_listBox->setCurrentItem( m_activeItem );
+ emit activated( m_activeItem->url() );
+ }
+}
+
+void KURLBar::setCurrentItem( const KURL& url )
+{
+ d->currentURL = url;
+
+ QString u = url.url(-1);
+
+ if ( m_activeItem && m_activeItem->url().url(-1) == u )
+ return;
+
+ bool hasURL = false;
+ QListBoxItem *item = m_listBox->firstItem();
+ while ( item ) {
+ if ( static_cast<KURLBarItem*>( item )->url().url(-1) == u ) {
+ m_activeItem = static_cast<KURLBarItem*>( item );
+ m_listBox->setCurrentItem( item );
+ m_listBox->setSelected( item, true );
+ hasURL = true;
+ break;
+ }
+ item = item->next();
+ }
+
+ if ( !hasURL ) {
+ m_activeItem = 0L;
+ m_listBox->clearSelection();
+ }
+}
+
+KURLBarItem * KURLBar::currentItem() const
+{
+ QListBoxItem *item = m_listBox->item( m_listBox->currentItem() );
+ if ( item )
+ return static_cast<KURLBarItem *>( item );
+ return 0L;
+}
+
+KURL KURLBar::currentURL() const
+{
+ KURLBarItem *item = currentItem();
+ return item ? item->url() : KURL();
+}
+
+void KURLBar::readConfig( KConfig *appConfig, const QString& itemGroup )
+{
+ m_isImmutable = appConfig->groupIsImmutable( itemGroup );
+ KConfigGroupSaver cs( appConfig, itemGroup );
+ d->defaultIconSize = m_iconSize;
+ m_iconSize = appConfig->readNumEntry( "Speedbar IconSize", m_iconSize );
+
+ if ( m_useGlobal ) { // read global items
+ KConfig *globalConfig = KGlobal::config();
+ KConfigGroupSaver cs( globalConfig, (QString)(itemGroup +" (Global)"));
+ int num = globalConfig->readNumEntry( "Number of Entries" );
+ for ( int i = 0; i < num; i++ ) {
+ readItem( i, globalConfig, false );
+ }
+ }
+
+ // read application local items
+ int num = appConfig->readNumEntry( "Number of Entries" );
+ for ( int i = 0; i < num; i++ ) {
+ readItem( i, appConfig, true );
+ }
+}
+
+void KURLBar::readItem( int i, KConfig *config, bool applicationLocal )
+{
+ QString number = QString::number( i );
+ KURL url = KURL::fromPathOrURL( config->readPathEntry( QString("URL_") + number ));
+ if ( !url.isValid() || !KProtocolInfo::isKnownProtocol( url ))
+ return; // nothing we could do.
+
+ insertItem( url,
+ config->readEntry( QString("Description_") + number ),
+ applicationLocal,
+ config->readEntry( QString("Icon_") + number ),
+ static_cast<KIcon::Group>(
+ config->readNumEntry( QString("IconGroup_") + number )) );
+}
+
+void KURLBar::writeConfig( KConfig *config, const QString& itemGroup )
+{
+ KConfigGroupSaver cs1( config, itemGroup );
+ if(!config->hasDefault("Speedbar IconSize") && m_iconSize == d->defaultIconSize )
+ config->revertToDefault("Speedbar IconSize");
+ else
+ config->writeEntry( "Speedbar IconSize", m_iconSize );
+
+ if ( !m_isModified )
+ return;
+
+ int i = 0;
+ int numLocal = 0;
+ KURLBarItem *item = static_cast<KURLBarItem*>( m_listBox->firstItem() );
+
+ while ( item )
+ {
+ if ( item->isPersistent() ) // we only save persistent items
+ {
+ if ( item->applicationLocal() )
+ {
+ writeItem( item, numLocal, config, false );
+ numLocal++;
+ }
+
+ i++;
+ }
+ item = static_cast<KURLBarItem*>( item->next() );
+ }
+ config->writeEntry("Number of Entries", numLocal);
+
+
+ // write the global entries to kdeglobals, if any
+ bool haveGlobalEntries = (i > numLocal);
+ if ( m_useGlobal && haveGlobalEntries ) {
+ config->setGroup( itemGroup + " (Global)" );
+
+ int numGlobals = 0;
+ item = static_cast<KURLBarItem*>( m_listBox->firstItem() );
+
+ while ( item )
+ {
+ if ( item->isPersistent() ) // we only save persistent items
+ {
+ if ( !item->applicationLocal() )
+ {
+ writeItem( item, numGlobals, config, true );
+ numGlobals++;
+ }
+ }
+
+ item = static_cast<KURLBarItem*>( item->next() );
+ }
+ config->writeEntry("Number of Entries", numGlobals, true, true);
+ }
+
+ m_isModified = false;
+}
+
+void KURLBar::writeItem( KURLBarItem *item, int i, KConfig *config,
+ bool global )
+{
+ if ( !item->isPersistent() )
+ return;
+
+ QString Description = "Description_";
+ QString URL = "URL_";
+ QString Icon = "Icon_";
+ QString IconGroup = "IconGroup_";
+
+ QString number = QString::number( i );
+ config->writePathEntry( URL + number, item->url().prettyURL(), true, global );
+
+ config->writeEntry( Description + number, item->description(),true,global);
+ config->writeEntry( Icon + number, item->icon(), true, global );
+ config->writeEntry( IconGroup + number, item->iconGroup(), true, global );
+}
+
+
+void KURLBar::slotDropped( QDropEvent *e )
+{
+ KURL::List urls;
+ if ( KURLDrag::decode( e, urls ) ) {
+ KURL url;
+ QString description;
+ QString icon;
+ bool appLocal = false;
+
+ KURL::List::Iterator it = urls.begin();
+ for ( ; it != urls.end(); ++it ) {
+ (void) insertItem( *it, description, appLocal, icon );
+ m_isModified = true;
+ updateGeometry();
+ }
+ }
+}
+
+void KURLBar::slotContextMenuRequested( QListBoxItem *_item, const QPoint& pos )
+{
+ if (m_isImmutable)
+ return;
+
+ KURLBarItem *item = dynamic_cast<KURLBarItem*>( _item );
+
+ static const int IconSize = 10;
+ static const int AddItem = 20;
+ static const int EditItem = 30;
+ static const int RemoveItem = 40;
+
+ KURL lastURL = m_activeItem ? m_activeItem->url() : KURL();
+
+ bool smallIcons = m_iconSize < KIcon::SizeMedium;
+ QPopupMenu *popup = new QPopupMenu();
+ popup->insertItem( smallIcons ?
+ i18n("&Large Icons") : i18n("&Small Icons"),
+ IconSize );
+ popup->insertSeparator();
+
+ if (item != 0L && item->isPersistent())
+ {
+ popup->insertItem(SmallIconSet("edit"), i18n("&Edit Entry..."), EditItem);
+ popup->insertSeparator();
+ }
+
+ popup->insertItem(SmallIconSet("filenew"), i18n("&Add Entry..."), AddItem);
+
+ if (item != 0L && item->isPersistent())
+ {
+ popup->insertItem( SmallIconSet("editdelete"), i18n("&Remove Entry"),
+ RemoveItem );
+ }
+
+ int result = popup->exec( pos );
+ switch ( result ) {
+ case IconSize:
+ setIconSize( smallIcons ? KIcon::SizeMedium : KIcon::SizeSmallMedium );
+ m_listBox->triggerUpdate( true );
+ break;
+ case AddItem:
+ addNewItem();
+ break;
+ case EditItem:
+ editItem( static_cast<KURLBarItem *>( item ) );
+ break;
+ case RemoveItem:
+ delete item;
+ m_isModified = true;
+ break;
+ default: // abort
+ break;
+ }
+
+ // reset current item
+ m_activeItem = 0L;
+ setCurrentItem( lastURL );
+}
+
+bool KURLBar::addNewItem()
+{
+ KURLBarItem *item = new KURLBarItem( this, d->currentURL,
+ i18n("Enter a description") );
+ if ( editItem( item ) ) {
+ m_listBox->insertItem( item );
+ return true;
+ }
+
+ delete item;
+ return false;
+}
+
+bool KURLBar::editItem( KURLBarItem *item )
+{
+ if ( !item || !item->isPersistent() ) // should never happen tho
+ return false;
+
+ KURL url = item->url();
+ QString description = item->description();
+ QString icon = item->icon();
+ bool appLocal = item->applicationLocal();
+
+ if ( KURLBarItemDialog::getInformation( m_useGlobal,
+ url, description,
+ icon, appLocal,
+ m_iconSize, this ))
+ {
+ item->setURL( url );
+ item->setDescription( description );
+ item->setIcon( icon );
+ item->setApplicationLocal( appLocal );
+ m_listBox->triggerUpdate( true );
+ m_isModified = true;
+ updateGeometry();
+ return true;
+ }
+
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+KURLBarListBox::KURLBarListBox( QWidget *parent, const char *name )
+ : KListBox( parent, name )
+{
+ m_toolTip = new KURLBarToolTip( this );
+ setAcceptDrops( true );
+ viewport()->setAcceptDrops( true );
+}
+
+KURLBarListBox::~KURLBarListBox()
+{
+ delete m_toolTip;
+}
+
+void KURLBarListBox::paintEvent( QPaintEvent* )
+{
+ QPainter p(this);
+ p.setPen( colorGroup().mid() );
+ p.drawRect( 0, 0, width(), height() );
+}
+
+QDragObject * KURLBarListBox::dragObject()
+{
+ KURL::List urls;
+ KURLBarItem *item = static_cast<KURLBarItem*>( firstItem() );
+
+ while ( item ) {
+ if ( item->isSelected() )
+ urls.append( item->url() );
+ item = static_cast<KURLBarItem*>( item->next() );
+ }
+
+ if ( !urls.isEmpty() ) // ### use custom drag-object with description etc.?
+ return new KURLDrag( urls, this, "urlbar drag" );
+
+ return 0L;
+}
+
+void KURLBarListBox::contentsDragEnterEvent( QDragEnterEvent *e )
+{
+ e->accept( KURLDrag::canDecode( e ));
+}
+
+void KURLBarListBox::contentsDropEvent( QDropEvent *e )
+{
+ emit dropped( e );
+}
+
+void KURLBarListBox::contextMenuEvent( QContextMenuEvent *e )
+{
+ if (e)
+ {
+ emit contextMenuRequested( itemAt( e->globalPos() ), e->globalPos() );
+ e->consume(); // Consume the event to avoid multiple contextMenuEvent calls...
+ }
+}
+
+void KURLBarListBox::setOrientation( Qt::Orientation orient )
+{
+ if ( orient == Vertical ) {
+ setColumnMode( 1 );
+ setRowMode( Variable );
+ }
+ else {
+ setRowMode( 1 );
+ setColumnMode( Variable );
+ }
+
+ m_orientation = orient;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+bool KURLBarItemDialog::getInformation( bool allowGlobal, KURL& url,
+ QString& description, QString& icon,
+ bool& appLocal, int iconSize,
+ QWidget *parent )
+{
+ KURLBarItemDialog *dialog = new KURLBarItemDialog( allowGlobal, url,
+ description, icon,
+ appLocal,
+ iconSize, parent );
+ if ( dialog->exec() == QDialog::Accepted ) {
+ // set the return parameters
+ url = dialog->url();
+ description = dialog->description();
+ icon = dialog->icon();
+ appLocal = dialog->applicationLocal();
+
+ delete dialog;
+ return true;
+ }
+
+ delete dialog;
+ return false;
+}
+
+KURLBarItemDialog::KURLBarItemDialog( bool allowGlobal, const KURL& url,
+ const QString& description,
+ QString icon, bool appLocal,
+ int iconSize,
+ QWidget *parent, const char *name )
+ : KDialogBase( parent, name, true,
+ i18n("Edit Quick Access Entry"), Ok | Cancel, Ok, true )
+{
+ QVBox *box = new QVBox( this );
+ QString text = i18n("<qt><b>Please provide a description, URL and icon for this Quick Access entry.</b></br></qt>");
+ QLabel *label = new QLabel( text, box );
+ box->setSpacing( spacingHint() );
+
+ QGrid *grid = new QGrid( 2, box );
+ grid->setSpacing( spacingHint() );
+
+ QString whatsThisText = i18n("<qt>This is the text that will appear in the Quick Access panel.<p>"
+ "The description should consist of one or two words "
+ "that will help you remember what this entry refers to.</qt>");
+ label = new QLabel( i18n("&Description:"), grid );
+ m_edit = new KLineEdit( grid, "description edit" );
+ m_edit->setText( description.isEmpty() ? url.fileName() : description );
+ label->setBuddy( m_edit );
+ QWhatsThis::add( label, whatsThisText );
+ QWhatsThis::add( m_edit, whatsThisText );
+
+ whatsThisText = i18n("<qt>This is the location associated with the entry. Any valid URL may be used. For example:<p>"
+ "%1<br>http://www.kde.org<br>ftp://ftp.kde.org/pub/kde/stable<p>"
+ "By clicking on the button next to the text edit box you can browse to an "
+ "appropriate URL.</qt>").arg(QDir::homeDirPath());
+ label = new QLabel( i18n("&URL:"), grid );
+ m_urlEdit = new KURLRequester( url.prettyURL(), grid );
+ m_urlEdit->setMode( KFile::Directory );
+ label->setBuddy( m_urlEdit );
+ QWhatsThis::add( label, whatsThisText );
+ QWhatsThis::add( m_urlEdit, whatsThisText );
+
+ whatsThisText = i18n("<qt>This is the icon that will appear in the Quick Access panel.<p>"
+ "Click on the button to select a different icon.</qt>");
+ label = new QLabel( i18n("Choose an &icon:"), grid );
+ m_iconButton = new KIconButton( grid, "icon button" );
+ m_iconButton->setIconSize( iconSize );
+ if ( icon.isEmpty() )
+ icon = KMimeType::iconForURL( url );
+ m_iconButton->setIcon( icon );
+ label->setBuddy( m_iconButton );
+ QWhatsThis::add( label, whatsThisText );
+ QWhatsThis::add( m_iconButton, whatsThisText );
+
+ if ( allowGlobal ) {
+ QString appName;
+ if ( KGlobal::instance()->aboutData() )
+ appName = KGlobal::instance()->aboutData()->programName();
+ if ( appName.isEmpty() )
+ appName = QString::fromLatin1( KGlobal::instance()->instanceName() );
+ m_appLocal = new QCheckBox( i18n("&Only show when using this application (%1)").arg( appName ), box );
+ m_appLocal->setChecked( appLocal );
+ QWhatsThis::add( m_appLocal,
+ i18n("<qt>Select this setting if you want this "
+ "entry to show only when using the current application (%1).<p>"
+ "If this setting is not selected, the entry will be available in all "
+ "applications.</qt>")
+ .arg(appName));
+ }
+ else
+ m_appLocal = 0L;
+ connect(m_urlEdit->lineEdit(),SIGNAL(textChanged ( const QString & )),this,SLOT(urlChanged(const QString & )));
+ m_edit->setFocus();
+ setMainWidget( box );
+}
+
+KURLBarItemDialog::~KURLBarItemDialog()
+{
+}
+
+void KURLBarItemDialog::urlChanged(const QString & text )
+{
+ enableButtonOK( !text.isEmpty() );
+}
+
+KURL KURLBarItemDialog::url() const
+{
+ QString text = m_urlEdit->url();
+ KURL u;
+ if ( text.at(0) == '/' )
+ u.setPath( text );
+ else
+ u = text;
+
+ return u;
+}
+
+QString KURLBarItemDialog::description() const
+{
+ return m_edit->text();
+}
+
+QString KURLBarItemDialog::icon() const
+{
+ return m_iconButton->icon();
+}
+
+bool KURLBarItemDialog::applicationLocal() const
+{
+ if ( !m_appLocal )
+ return true;
+
+ return m_appLocal->isChecked();
+}
+
+void KURLBarItem::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KURLBar::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KURLBarListBox::virtual_hook( int id, void* data )
+{ KListBox::virtual_hook( id, data ); }
+
+
+#include "kurlbar.moc"
diff --git a/kio/kfile/kurlbar.h b/kio/kfile/kurlbar.h
new file mode 100644
index 000000000..6bc5de6d5
--- /dev/null
+++ b/kio/kfile/kurlbar.h
@@ -0,0 +1,660 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KURLBAR_H
+#define KURLBAR_H
+
+#include <qevent.h>
+#include <qframe.h>
+#include <qtooltip.h>
+
+#include <kdialogbase.h>
+#include <kicontheme.h>
+#include <klistbox.h>
+#include <kurl.h>
+
+class KConfig;
+class KURLBar;
+
+/**
+ * An item to be used in KURLBar / KURLBarListBox. All the properties
+ * (url, icon, description, tooltip) can be changed dynamically.
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @see KURLBar
+ * @see KURLBarListBox
+ */
+class KIO_EXPORT KURLBarItem : public QListBoxPixmap
+{
+public:
+ /**
+ * Creates a KURLBarItem to be used in the @p parent KURLBar. You need
+ * to insert the item into the listbox manually, if you don't use
+ * KURLBar::insertItem().
+ *
+ * If description is empty, it will try to use the filename/directory
+ * of @p url, which will be shown as text of the item.
+ * @p url will be used as tooltip, unless you set a different tip with
+ * setToolTip().
+ * @p persistent specifies whether this item is a persistent item or a
+ * dynamic item, that is not saved with KURLBar::writeConfig().
+ * @since 3.2
+ */
+ KURLBarItem( KURLBar *parent, const KURL& url, bool persistent,
+ const QString& description = QString::null,
+ const QString& icon = QString::null,
+ KIcon::Group group = KIcon::Panel );
+
+ /**
+ * Creates a persistent KURLBarItem to be used in the @p parent KURLBar. You need
+ * to insert the item into the listbox manually, if you don't use
+ * KURLBar::insertItem().
+ *
+ * If description is empty, it will try to use the filename/directory
+ * of @p url, which will be shown as text of the item.
+ * @p url will be used as tooltip, unless you set a different tip with
+ * setToolTip().
+ * @p persistent specifies whether this item is a persistent item or a
+ * dynamic item, that is not saved with KURLBar::writeConfig().
+ */
+ KURLBarItem( KURLBar *parent, const KURL& url,
+ const QString& description = QString::null,
+ const QString& icon = QString::null,
+ KIcon::Group group = KIcon::Panel );
+
+ /**
+ * Destroys the item
+ */
+ ~KURLBarItem();
+
+ /**
+ * Sets @p url for this item. Also updates the visible text to the
+ * filename/directory of the url, if no description is set.
+ * @see url
+ */
+ void setURL( const KURL& url );
+ /**
+ * @p sets the icon for this item. See KIconLoader for a description
+ * of the icon groups.
+ * @see icon
+ */
+ void setIcon( const QString& icon, KIcon::Group group = KIcon::Panel );
+ /**
+ * Sets the description of this item that will be shown as item-text.
+ * @see description
+ */
+ void setDescription( const QString& desc );
+ /**
+ * Sets a tooltip to be used for this item.
+ * @see toolTip
+ */
+ void setToolTip( const QString& tip );
+
+ /**
+ * returns the preferred size of this item
+ * @since 3.1
+ */
+ QSize sizeHint() const;
+
+ /**
+ * returns the width of this item.
+ */
+ virtual int width( const QListBox * ) const;
+ /**
+ * returns the height of this item.
+ */
+ virtual int height( const QListBox * ) const;
+
+ /**
+ * returns the url of this item.
+ * @see setURL
+ */
+ const KURL& url() const { return m_url; }
+ /**
+ * returns the description of this item.
+ * @see setDescription
+ */
+ const QString& description() const { return m_description; }
+ /**
+ * returns the icon of this item.
+ * @see setIcon
+ */
+ const QString& icon() const { return m_icon; }
+ /**
+ * returns the tooltip of this item.
+ * @see setToolTip
+ */
+ QString toolTip() const;
+ /**
+ * returns the icon-group of this item (determines icon-effects).
+ * @see setIcon
+ */
+ KIcon::Group iconGroup() const { return m_group; }
+ /**
+ * returns the pixmap of this item.
+ */
+ virtual const QPixmap * pixmap() const { return &m_pixmap; }
+
+ /**
+ * Makes this item a local or global one. This has only an effect
+ * on persistent items of course.
+ * @see isPersistent
+ * @see applicationLocal
+ */
+ void setApplicationLocal( bool local );
+
+ /**
+ * returns whether this is a global item or a local one. KURLBar
+ * can differentiate between global and local items (only for the current
+ * application) for easy extensiblity.
+ * @see setApplicationLocal
+ */
+ bool applicationLocal() const { return m_appLocal; }
+
+ /**
+ * returns whether this item is persistent (via KURLBar::writeConfig()
+ * and KURLBar::readConfig()) or not.
+ * @since 3.2
+ */
+ bool isPersistent() const;
+
+protected:
+ virtual void paint( QPainter *p );
+
+private:
+ int iconSize() const;
+ void init( const QString& icon, KIcon::Group group,
+ const QString& description, bool persistent );
+
+ KURL m_url;
+ QString m_description;
+ QString m_icon;
+ QString m_toolTip;
+ QPixmap m_pixmap;
+ KIcon::Group m_group;
+ KURLBar *m_parent;
+ bool m_appLocal :1;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KURLBarItemPrivate;
+ KURLBarItemPrivate *d;
+};
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+class KURLBarListBox;
+
+/**
+ * KURLBar is a widget that displays icons together with a description. They
+ * can be arranged either horizontally or vertically. Clicking on an item
+ * will cause the activated() signal to be emitted. The user can edit
+ * existing items by choosing "Edit entry" in the contextmenu. He can also
+ * remove or add new entries (via drag&drop or the context menu).
+ *
+ * KURLBar offers the methods readConfig() and writeConfig() to
+ * read and write the configuration of all the entries. It can differentiate
+ * between global and local entries -- global entries will be saved in the
+ * global configuration (kdeglobals), while local entries will be saved in
+ * your application's KConfig object.
+ *
+ * Due to the configurability, you usually only insert some default entries
+ * once and then solely use the read and writeConfig methods to preserve the
+ * user's configuration.
+ *
+ * The widget has a "current" item, that is visualized to differentiate it
+ * from others.
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @short A URL-bar widget, as used in the KFileDialog
+ */
+class KIO_EXPORT KURLBar : public QFrame
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs a KURLBar. Set @p useGlobalItems to true if you want to
+ * allow global/local item separation.
+ */
+ KURLBar( bool useGlobalItems,
+ QWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+ /**
+ * Destroys the KURLBar.
+ */
+ ~KURLBar();
+
+ /**
+ * Inserts a new item into the KURLBar and returns the created
+ * KURLBarItem.
+ *
+ * @p url the url of the item
+ * @p description the description of the item (shown in the view)
+ * @p applicationLocal whether this should be a global or a local item
+ * @p icon an icon -- if empty, the default icon for the url will be used
+ * @p group the icon-group for using icon-effects
+ */
+ virtual KURLBarItem * insertItem( const KURL& url,
+ const QString& description,
+ bool applicationLocal = true,
+ const QString& icon = QString::null,
+ KIcon::Group group = KIcon::Panel );
+ /**
+ * Inserts a new dynamic item into the KURLBar and returns the created
+ * KURLBarItem.
+ *
+ * @p url the url of the item
+ * @p description the description of the item (shown in the view)
+ * @p icon an icon -- if empty, the default icon for the url will be used
+ * @p group the icon-group for using icon-effects
+ * @since 3.2
+ */
+ virtual KURLBarItem * insertDynamicItem( const KURL& url,
+ const QString& description,
+ const QString& icon = QString::null,
+ KIcon::Group group = KIcon::Panel );
+ /**
+ * The items can be arranged either vertically in one column or
+ * horizontally in one row.
+ * @see orientation
+ */
+ virtual void setOrientation( Qt::Orientation orient );
+ /**
+ * @returns the current orientation mode.
+ * @see setOrientation
+ */
+ Orientation orientation() const;
+
+ /**
+ * Allows to set a custom KURLBarListBox.
+ * Note: The previous listbox will be deleted. Items of the previous
+ * listbox will not be moved to the new box.
+ * @see listBox
+ */
+ virtual void setListBox( KURLBarListBox * );
+ /**
+ * @returns the KURLBarListBox that is used.
+ * @see setListBox
+ */
+ KURLBarListBox *listBox() const { return m_listBox; }
+
+ /**
+ * Sets the default iconsize to be used for items inserted with
+ * insertItem. By default KIcon::SizeMedium.
+ * @see iconsize
+ */
+ virtual void setIconSize( int size );
+ /**
+ * @returns the default iconsize used for items inserted with
+ * insertItem. By default KIcon::SizeMedium
+ * @see setIconSize
+ */
+ int iconSize() const { return m_iconSize; }
+
+ /**
+ * Clears the view, removes all items.
+ */
+ virtual void clear();
+
+ /**
+ * @returns a proper sizehint, depending on the orientation and the number
+ * of items available.
+ */
+ virtual QSize sizeHint() const;
+
+ /**
+ * @returns a proper minimum size (reimplemented)
+ */
+ virtual QSize minimumSizeHint() const;
+
+ /**
+ * Call this method to read a saved configuration from @p config,
+ * inside the group @p itemGroup. All items in there will be restored.
+ * The reading of every item is delegated to the readItem() method.
+ */
+ virtual void readConfig( KConfig *config, const QString& itemGroup );
+ /**
+ * Call this method to save the current configuration into @p config,
+ * inside the group @p iconGroup. The writeItem() method is used
+ * to save each item.
+ */
+ virtual void writeConfig( KConfig *config, const QString& itemGroup );
+
+ /**
+ * Called from readConfig() to read the i'th from @p config.
+ * After reading a KURLBarItem is created and initialized with the read
+ * values (as well as the given @p applicationLocal).
+ */
+ virtual void readItem( int i, KConfig *config, bool applicationLocal );
+ /**
+ * Called from writeConfig() to save the KURLBarItem @p item as the
+ * i'th entry in the config-object.
+ * @p global tell whether it should be saved in the global configuration
+ * or not (using KConfig::writeEntry( key, value, true, global ) ).
+ */
+ virtual void writeItem( KURLBarItem *item, int i, KConfig *, bool global );
+
+ /**
+ * @returns the current KURLBarItem, or 0L if none.
+ * @see setCurrentItem
+ * @see currentURL
+ */
+ KURLBarItem * currentItem() const;
+ /**
+ * @returns the url of the current item or an invalid url, if there is
+ * no current item.
+ * @see currentItem
+ * @see setCurrentItem
+ */
+ KURL currentURL() const;
+
+ /**
+ * @returns true when the urlbar was modified by the user (e.g. by
+ * editing/adding/removing one or more entries). Will be reset to false
+ * after calling writeConfig().
+ */
+ bool isModified() const { return m_isModified; }
+
+ /**
+ * @returns true when the urlbar may not be modified by the user
+ */
+ bool isImmutable() const { return m_isImmutable; }
+
+ /**
+ * @returns true if the bar is in vertical mode.
+ */
+ bool isVertical() const { return orientation() == Vertical; }
+
+public slots:
+ /**
+ * Makes the item with the url @p url the current item. Does nothing
+ * if no item with that url is available.
+ * @see currentItem
+ * @see currentURL
+ */
+ virtual void setCurrentItem( const KURL& url );
+
+signals:
+ /**
+ * This signal is emitted when the user activated an item, e.g., by
+ * clicking on it.
+ */
+ void activated( const KURL& url );
+
+protected:
+ /**
+ * Pops up a KURLBarItemDialog to let the user add a new item.
+ * Uses editItem() to do the job.
+ * @returns false if the user aborted the dialog and no item is added.
+ */
+ virtual bool addNewItem();
+ /**
+ * Pops up a KURLBarItemDialog to let the user edit the properties
+ * of @p item. Invoked e.g. by addNewItem(), when the user drops
+ * a url onto the bar or from the contextmenu.
+ * @returns false if the user aborted the dialog and @p item is not
+ * changed.
+ */
+ virtual bool editItem( KURLBarItem *item );
+
+ virtual void resizeEvent( QResizeEvent * );
+
+ virtual void paletteChange( const QPalette & );
+
+ /**
+ * The currently active item.
+ */
+ KURLBarItem * m_activeItem;
+ /**
+ * Whether we support global entries or just local ones.
+ */
+ bool m_useGlobal :1;
+
+ /**
+ * Whether the urlbar was modified by the user (e.g. by
+ * editing/adding/removing an item).
+ */
+ bool m_isModified :1;
+
+ /**
+ * Whether the urlbar may be modified by the user.
+ * If immutable is true, the urlbar can not be modified.
+ */
+ bool m_isImmutable :1;
+
+protected slots:
+ /**
+ * Reimplemented to show a contextmenu, allowing the user to add, edit
+ * or remove items, or change the iconsize.
+ */
+ virtual void slotContextMenuRequested( QListBoxItem *, const QPoint& pos );
+ /**
+ * Called when an item has been selected. Emits the activated()
+ * signal.
+ */
+ virtual void slotSelected( QListBoxItem * );
+
+ /**
+ * Called when a url was dropped onto the bar to show a
+ * KURLBarItemDialog.
+ */
+ virtual void slotDropped( QDropEvent * );
+
+private slots:
+ void slotSelected( int button, QListBoxItem * );
+
+private:
+ KURLBarListBox *m_listBox;
+ int m_iconSize;
+
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KURLBarPrivate;
+ KURLBarPrivate *d;
+};
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+class QDragObject;
+class KURLBarToolTip;
+
+/**
+ * This is the listbox used in KURLBar. It is a subclass of KListBox to support
+ * drag & drop and to set up the row / column mode.
+ *
+ * The widget has just one row or one column, depending on orientation().
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class KIO_EXPORT KURLBarListBox : public KListBox
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs a KURLBarListBox.
+ */
+ KURLBarListBox( QWidget *parent = 0, const char *name = 0 );
+ /**
+ * Destroys the box.
+ */
+ ~KURLBarListBox();
+
+ /**
+ * Sets the orientation of the widget. Horizontal means, all items are
+ * arranged in one row. Vertical means, all items are arranged in one
+ * column.
+ * @see orientation
+ */
+ virtual void setOrientation( Qt::Orientation orient );
+ /**
+ * @returns the current orientation.
+ * @see setOrientation
+ */
+ Qt::Orientation orientation() const { return m_orientation; }
+
+ bool isVertical() const { return m_orientation == Qt::Vertical; }
+
+signals:
+ /**
+ * Emitted when a drop-event happened.
+ */
+ void dropped( QDropEvent *e );
+
+protected:
+ /**
+ * @returns a suitable QDragObject when an item is dragged.
+ */
+ virtual QDragObject * dragObject();
+
+ virtual void contentsDragEnterEvent( QDragEnterEvent * );
+ virtual void contentsDropEvent( QDropEvent * );
+ virtual void contextMenuEvent( QContextMenuEvent * );
+ virtual void paintEvent( QPaintEvent* );
+
+private:
+ Qt::Orientation m_orientation;
+ KURLBarToolTip *m_toolTip;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KURLBarListBoxPrivate;
+ KURLBarListBoxPrivate *d;
+};
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+class QCheckBox;
+class KIconButton;
+class KLineEdit;
+class KURLRequester;
+
+/**
+ * A dialog that allows editing entries of a KURLBar ( KURLBarItem).
+ * The dialog offers to configure a given url, description and icon.
+ * See the class-method getInformation() for easy usage.
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class KIO_EXPORT KURLBarItemDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * A convenience method to show the dialog and retrieve all the
+ * properties via the given parameters. The parameters are used to
+ * initialize the dialog and then return the user-configured values.
+ *
+ * See the KURLBarItem constructor for the parameter description.
+ */
+ static bool getInformation( bool allowGlobal, KURL& url,
+ QString& description, QString& icon,
+ bool& appLocal, int iconSize,
+ QWidget *parent = 0 );
+
+ /**
+ * Constructs a KURLBarItemDialog.
+ *
+ * @p allowGlobal if you set this to true, the dialog will have a checkbox
+ * for the user to decide if he wants the entry to be
+ * available globally or just for the current application.
+ * @p url the url of the item
+ * @p description a short, translated description of the item
+ * @p icon an icon for the item
+ * @p appLocal tells whether the item should be local for this application
+ * or be available globally
+ * @p iconSize determines the size of the icon that is shown/selectable
+ * @p parent the parent-widget for the dialog
+ *
+ * If you leave the icon empty, the default icon for the given url will be
+ * used (KMimeType::pixmapForURL()).
+ */
+ KURLBarItemDialog( bool allowGlobal, const KURL& url,
+ const QString& description, QString icon,
+ bool appLocal = true,
+ int iconSize = KIcon::SizeMedium,
+ QWidget *parent = 0, const char *name = 0 );
+ /**
+ * Destroys the dialog.
+ */
+ ~KURLBarItemDialog();
+
+ /**
+ * @returns the configured url
+ */
+ KURL url() const;
+
+ /**
+ * @returns the configured description
+ */
+ QString description() const;
+
+ /**
+ * @returns the configured icon
+ */
+ QString icon() const;
+
+ /**
+ * @returns whether the item should be local to the application or global.
+ * If allowGlobal was set to false in the constructor, this will always
+ * return true.
+ */
+ bool applicationLocal() const;
+
+protected:
+ /**
+ * The KURLRequester used for editing the url
+ */
+ KURLRequester * m_urlEdit;
+ /**
+ * The KLineEdit used for editing the description
+ */
+ KLineEdit * m_edit;
+ /**
+ * The KIconButton to configure the icon
+ */
+ KIconButton * m_iconButton;
+ /**
+ * The QCheckBox to modify the local/global setting
+ */
+ QCheckBox * m_appLocal;
+
+public slots:
+ void urlChanged(const QString & );
+
+private:
+ class KURLBarItemDialogPrivate;
+ KURLBarItemDialogPrivate *d;
+};
+
+
+#endif // KURLBAR_H
diff --git a/kio/kfile/kurlcombobox.cpp b/kio/kfile/kurlcombobox.cpp
new file mode 100644
index 000000000..128e8a22c
--- /dev/null
+++ b/kio/kfile/kurlcombobox.cpp
@@ -0,0 +1,363 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdir.h>
+#include <qlistbox.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmimetype.h>
+
+#include <kurlcombobox.h>
+
+class KURLComboBox::KURLComboBoxPrivate
+{
+public:
+ KURLComboBoxPrivate() {
+ dirpix = SmallIcon(QString::fromLatin1("folder"));
+ }
+
+ QPixmap dirpix;
+};
+
+
+KURLComboBox::KURLComboBox( Mode mode, QWidget *parent, const char *name )
+ : KComboBox( parent, name )
+{
+ init( mode );
+}
+
+
+KURLComboBox::KURLComboBox( Mode mode, bool rw, QWidget *parent,
+ const char *name )
+ : KComboBox( rw, parent, name )
+{
+ init( mode );
+}
+
+
+KURLComboBox::~KURLComboBox()
+{
+ delete d;
+}
+
+
+void KURLComboBox::init( Mode mode )
+{
+ d = new KURLComboBoxPrivate();
+
+ myMode = mode;
+ urlAdded = false;
+ myMaximum = 10; // default
+ itemList.setAutoDelete( true );
+ defaultList.setAutoDelete( true );
+ setInsertionPolicy( NoInsertion );
+ setTrapReturnKey( true );
+ setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ));
+
+ opendirPix = SmallIcon(QString::fromLatin1("folder_open"));
+
+ connect( this, SIGNAL( activated( int )), SLOT( slotActivated( int )));
+}
+
+
+QStringList KURLComboBox::urls() const
+{
+ kdDebug(250) << "::urls()" << endl;
+ //static const QString &fileProt = KGlobal::staticQString("file:");
+ QStringList list;
+ QString url;
+ for ( int i = defaultList.count(); i < count(); i++ ) {
+ url = text( i );
+ if ( !url.isEmpty() ) {
+ //if ( url.at(0) == '/' )
+ // list.append( url.prepend( fileProt ) );
+ //else
+ list.append( url );
+ }
+ }
+
+ return list;
+}
+
+
+void KURLComboBox::addDefaultURL( const KURL& url, const QString& text )
+{
+ addDefaultURL( url, getPixmap( url ), text );
+}
+
+
+void KURLComboBox::addDefaultURL( const KURL& url, const QPixmap& pix,
+ const QString& text )
+{
+ KURLComboItem *item = new KURLComboItem;
+ item->url = url;
+ item->pixmap = pix;
+ if ( text.isEmpty() )
+ if ( url.isLocalFile() )
+ item->text = url.path( myMode );
+ else
+ item->text = url.prettyURL( myMode );
+ else
+ item->text = text;
+
+ defaultList.append( item );
+}
+
+
+void KURLComboBox::setDefaults()
+{
+ clear();
+ itemMapper.clear();
+
+ KURLComboItem *item;
+ for ( unsigned int id = 0; id < defaultList.count(); id++ ) {
+ item = defaultList.at( id );
+ insertURLItem( item );
+ }
+}
+
+void KURLComboBox::setURLs( QStringList urls )
+{
+ setURLs( urls, RemoveBottom );
+}
+
+void KURLComboBox::setURLs( QStringList urls, OverLoadResolving remove )
+{
+ setDefaults();
+ itemList.clear();
+
+ if ( urls.isEmpty() )
+ return;
+
+ QStringList::Iterator it = urls.begin();
+
+ // kill duplicates
+ QString text;
+ while ( it != urls.end() ) {
+ while ( urls.contains( *it ) > 1 ) {
+ it = urls.remove( it );
+ continue;
+ }
+ ++it;
+ }
+
+ // limit to myMaximum items
+ /* Note: overload is an (old) C++ keyword, some compilers (KCC) choke
+ on that, so call it Overload (capital 'O'). (matz) */
+ int Overload = urls.count() - myMaximum + defaultList.count();
+ while ( Overload > 0 ) {
+ urls.remove((remove == RemoveBottom) ? urls.fromLast() : urls.begin());
+ Overload--;
+ }
+
+ it = urls.begin();
+
+ KURLComboItem *item = 0L;
+ KURL u;
+
+ while ( it != urls.end() ) {
+ if ( (*it).isEmpty() ) {
+ ++it;
+ continue;
+ }
+ u = KURL::fromPathOrURL( *it );
+
+ // Don't restore if file doesn't exist anymore
+ if (u.isLocalFile() && !QFile::exists(u.path())) {
+ ++it;
+ continue;
+ }
+
+ item = new KURLComboItem;
+ item->url = u;
+ item->pixmap = getPixmap( u );
+
+ if ( u.isLocalFile() )
+ item->text = u.path( myMode ); // don't show file:/
+ else
+ item->text = *it;
+
+ insertURLItem( item );
+ itemList.append( item );
+ ++it;
+ }
+}
+
+
+void KURLComboBox::setURL( const KURL& url )
+{
+ if ( url.isEmpty() )
+ return;
+
+ blockSignals( true );
+
+ // check for duplicates
+ QMap<int,const KURLComboItem*>::ConstIterator mit = itemMapper.begin();
+ QString urlToInsert = url.url(-1);
+ while ( mit != itemMapper.end() ) {
+ if ( urlToInsert == mit.data()->url.url(-1) ) {
+ setCurrentItem( mit.key() );
+
+ if ( myMode == Directories )
+ updateItem( mit.data(), mit.key(), opendirPix );
+
+ blockSignals( false );
+ return;
+ }
+ ++mit;
+ }
+
+ // not in the combo yet -> create a new item and insert it
+
+ // first remove the old item
+ if ( urlAdded ) {
+ itemList.removeLast();
+ urlAdded = false;
+ }
+
+ setDefaults();
+
+ QPtrListIterator<KURLComboItem> it( itemList );
+ for( ; it.current(); ++it )
+ insertURLItem( it.current() );
+
+ KURLComboItem *item = new KURLComboItem;
+ item->url = url;
+ item->pixmap = getPixmap( url );
+ if ( url.isLocalFile() )
+ item->text = url.path( myMode );
+ else
+ item->text = url.prettyURL( myMode );
+ kdDebug(250) << "setURL: text=" << item->text << endl;
+
+ int id = count();
+ QString text = /*isEditable() ? item->url.prettyURL( myMode ) : */ item->text;
+
+ if ( myMode == Directories )
+ KComboBox::insertItem( opendirPix, text, id );
+ else
+ KComboBox::insertItem( item->pixmap, text, id );
+ itemMapper.insert( id, item );
+ itemList.append( item );
+
+ setCurrentItem( id );
+ urlAdded = true;
+ blockSignals( false );
+}
+
+
+void KURLComboBox::slotActivated( int index )
+{
+ const KURLComboItem *item = itemMapper[ index ];
+
+ if ( item ) {
+ setURL( item->url );
+ emit urlActivated( item->url );
+ }
+}
+
+
+void KURLComboBox::insertURLItem( const KURLComboItem *item )
+{
+// kdDebug(250) << "insertURLItem " << item->text << endl;
+ int id = count();
+ KComboBox::insertItem( item->pixmap, item->text, id );
+ itemMapper.insert( id, item );
+}
+
+
+void KURLComboBox::setMaxItems( int max )
+{
+ myMaximum = max;
+
+ if ( count() > myMaximum ) {
+ int oldCurrent = currentItem();
+
+ setDefaults();
+
+ QPtrListIterator<KURLComboItem> it( itemList );
+ int Overload = itemList.count() - myMaximum + defaultList.count();
+ for ( int i = 0; i <= Overload; i++ )
+ ++it;
+
+ for( ; it.current(); ++it )
+ insertURLItem( it.current() );
+
+ if ( count() > 0 ) { // restore the previous currentItem
+ if ( oldCurrent >= count() )
+ oldCurrent = count() -1;
+ setCurrentItem( oldCurrent );
+ }
+ }
+}
+
+
+void KURLComboBox::removeURL( const KURL& url, bool checkDefaultURLs )
+{
+ QMap<int,const KURLComboItem*>::ConstIterator mit = itemMapper.begin();
+ while ( mit != itemMapper.end() ) {
+ if ( url.url(-1) == mit.data()->url.url(-1) ) {
+ if ( !itemList.remove( mit.data() ) && checkDefaultURLs )
+ defaultList.remove( mit.data() );
+ }
+ ++mit;
+ }
+
+ blockSignals( true );
+ setDefaults();
+ QPtrListIterator<KURLComboItem> it( itemList );
+ while ( it.current() ) {
+ insertURLItem( *it );
+ ++it;
+ }
+ blockSignals( false );
+}
+
+
+QPixmap KURLComboBox::getPixmap( const KURL& url ) const
+{
+ if ( myMode == Directories )
+ return d->dirpix;
+ else
+ return KMimeType::pixmapForURL( url, 0, KIcon::Small );
+}
+
+
+// updates "item" with pixmap "pixmap" and sets the URL instead of text
+// works around a Qt bug.
+void KURLComboBox::updateItem( const KURLComboItem *item,
+ int index, const QPixmap& pixmap )
+{
+ // QComboBox::changeItem() doesn't honor the pixmap when
+ // using an editable combobox, so we just remove and insert
+ if ( editable() ) {
+ removeItem( index );
+ insertItem( pixmap,
+ item->url.isLocalFile() ? item->url.path( myMode ) :
+ item->url.prettyURL( myMode ),
+ index );
+ }
+ else
+ changeItem( pixmap, item->text, index );
+}
+
+
+#include "kurlcombobox.moc"
diff --git a/kio/kfile/kurlcombobox.h b/kio/kfile/kurlcombobox.h
new file mode 100644
index 000000000..7485bfed9
--- /dev/null
+++ b/kio/kfile/kurlcombobox.h
@@ -0,0 +1,229 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KURLCOMBOBOX_H
+#define KURLCOMBOBOX_H
+
+#include <qevent.h>
+#include <qptrlist.h>
+#include <qmap.h>
+#include <qpixmap.h>
+#include <qstringlist.h>
+
+#include <kcombobox.h>
+#include <kurl.h>
+
+/**
+ * This combobox shows a number of recent URLs/directories, as well as some
+ * default directories.
+ * It will manage the default dirs root-directory, home-directory and
+ * Desktop-directory, as well as a number of URLs set via setURLs()
+ * and one additional entry to be set via setURL().
+ *
+ * @short A combo box showing a number of recent URLs/directories
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class KIO_EXPORT KURLComboBox : public KComboBox
+{
+ Q_OBJECT
+ Q_PROPERTY(QStringList urls READ urls WRITE setURLs DESIGNABLE true)
+ Q_PROPERTY(int maxItems READ maxItems WRITE setMaxItems DESIGNABLE true)
+
+public:
+ /**
+ * This enum describes which kind of items is shown in the combo box.
+ */
+ enum Mode { Files = -1, Directories = 1, Both = 0 };
+ /**
+ * This Enumeration is used in setURL() to determine which items
+ * will be removed when the given list is larger than maxItems().
+ *
+ * @li RemoveTop means that items will be removed from top
+ * @li RemoveBottom means, that items will be removed from the bottom
+ */
+ enum OverLoadResolving { RemoveTop, RemoveBottom };
+
+ /**
+ * Constructs a KURLComboBox.
+ * @param mode is either Files, Directories or Both and controls the
+ * following behavior:
+ * @li Files all inserted URLs will be treated as files, therefore the
+ * url shown in the combo will never show a trailing /
+ * the icon will be the one associated with the file's mimetype.
+ * @li Directories all inserted URLs will be treated as directories, will
+ * have a trailing slash in the combobox. The current
+ * directory will show the "open folder" icon, other
+ * directories the "folder" icon.
+ * @li Both Don't mess with anything, just show the url as given.
+ * @param parent The parent object of this widget.
+ * @param name The name of this widget.
+ */
+ KURLComboBox( Mode mode, QWidget *parent=0, const char *name=0 );
+ KURLComboBox( Mode mode, bool rw, QWidget *parent=0, const char *name=0 );
+ /**
+ * Destructs the combo box.
+ */
+ ~KURLComboBox();
+
+ /**
+ * Sets the current url. This combo handles exactly one url additionally
+ * to the default items and those set via setURLs(). So you can call
+ * setURL() as often as you want, it will always replace the previous one
+ * set via setURL().
+ * If @p url is already in the combo, the last item will stay there
+ * and the existing item becomes the current item.
+ * The current item will always have the open-directory-pixmap as icon.
+ *
+ * Note that you won't receive any signals, e.g. textChanged(),
+ * returnPressed() or activated() upon calling this method.
+ */
+ void setURL( const KURL& url );
+
+ /**
+ * Inserts @p urls into the combobox below the "default urls" (see
+ * addDefaultURL).
+ *
+ * If the list of urls contains more items than maxItems, the first items
+ * will be stripped.
+ */
+ void setURLs( QStringList urls );
+
+ /**
+ * Inserts @p urls into the combobox below the "default urls" (see
+ * addDefaultURL).
+ *
+ * If the list of urls contains more items than maxItems, the @p remove
+ * parameter determines whether the first or last items will be stripped.
+ */
+ void setURLs( QStringList urls, OverLoadResolving remove );
+
+ /**
+ * @returns a list of all urls currently handled. The list contains at most
+ * maxItems() items.
+ * Use this to save the list of urls in a config-file and reinsert them
+ * via setURLs() next time.
+ * Note that all default urls set via addDefaultURL() are not
+ * returned, they will automatically be set via setURLs() or setURL().
+ * You will always get fully qualified urls, i.e. with protocol like
+ * file:/
+ */
+ QStringList urls() const;
+
+ /**
+ * Sets how many items should be handled and displayed by the combobox.
+ * @see maxItems
+ */
+ void setMaxItems( int );
+
+ /**
+ * @returns the maximum of items the combobox handles.
+ * @see setMaxItems
+ */
+ int maxItems() const { return myMaximum; }
+
+ /**
+ * Adds a url that will always be shown in the combobox, it can't be
+ * "rotated away". Default urls won't be returned in urls() and don't
+ * have to be set via setURLs().
+ * If you want to specify a special pixmap, use the overloaded method with
+ * the pixmap parameter.
+ * Default URLs will be inserted into the combobox by setDefaults()
+ */
+ void addDefaultURL( const KURL& url, const QString& text = QString::null );
+
+ /**
+ * Adds a url that will always be shown in the combobox, it can't be
+ * "rotated away". Default urls won't be returned in urls() and don't
+ * have to be set via setURLs().
+ * If you don't need to specify a pixmap, use the overloaded method without
+ * the pixmap parameter.
+ * Default URLs will be inserted into the combobox by setDefaults()
+ */
+ void addDefaultURL( const KURL& url, const QPixmap& pix,
+ const QString& text = QString::null );
+
+ /**
+ * Clears all items and inserts the default urls into the combo. Will be
+ * called implicitly upon the first call to setURLs() or setURL()
+ * @see addDefaultURL
+ */
+ void setDefaults();
+
+ /**
+ * Removes any occurrence of @p url. If @p checkDefaultURLs is false
+ * default-urls won't be removed.
+ */
+ void removeURL( const KURL& url, bool checkDefaultURLs = true );
+
+signals:
+ /**
+ * Emitted when an item was clicked at.
+ * @param url is the url of the now current item. If it is a local url,
+ * it won't have a protocol (file:/), otherwise it will.
+ */
+ void urlActivated( const KURL& url );
+
+
+protected slots:
+ void slotActivated( int );
+
+
+protected:
+ struct _KURLComboItem {
+ QString text;
+ KURL url;
+ QPixmap pixmap;
+ };
+ typedef _KURLComboItem KURLComboItem;
+ QPtrList<KURLComboItem> itemList;
+ QPtrList<KURLComboItem> defaultList;
+ QMap<int,const KURLComboItem*> itemMapper;
+
+ void init( Mode mode );
+ void insertURLItem( const KURLComboItem * );
+
+ /**
+ * Uses KMimeType::pixmapForURL() to return a proper pixmap for @p url.
+ * In directory mode, a folder icon is always returned.
+ */
+ QPixmap getPixmap( const KURL& url ) const;
+
+ /**
+ * Updates @p item with @p pixmap and sets the url instead of the text
+ * of the KURLComboItem.
+ * Also works around a Qt bug.
+ */
+ void updateItem( const KURLComboItem *item, int index, const QPixmap& pix);
+
+ QPixmap opendirPix;
+ int firstItemIndex;
+
+
+private:
+ bool urlAdded;
+ int myMaximum;
+ Mode myMode; // can be used as parameter to KUR::path( int ) or url( int )
+ // to specify if we want a trailing slash or not
+
+private:
+ class KURLComboBoxPrivate;
+ KURLComboBoxPrivate *d;
+};
+
+
+#endif // KURLCOMBOBOX_H
diff --git a/kio/kfile/kurlrequester.cpp b/kio/kfile/kurlrequester.cpp
new file mode 100644
index 000000000..0f4619fd8
--- /dev/null
+++ b/kio/kfile/kurlrequester.cpp
@@ -0,0 +1,430 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <qstring.h>
+#include <qtooltip.h>
+#include <qapplication.h>
+
+#include <kaccel.h>
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kdirselectdialog.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kurlcompletion.h>
+#include <kurldrag.h>
+#include <kprotocolinfo.h>
+
+#include "kurlrequester.h"
+
+
+class KURLDragPushButton : public KPushButton
+{
+public:
+ KURLDragPushButton( QWidget *parent, const char *name=0 )
+ : KPushButton( parent, name ) {
+ setDragEnabled( true );
+ }
+ ~KURLDragPushButton() {}
+
+ void setURL( const KURL& url ) {
+ m_urls.clear();
+ m_urls.append( url );
+ }
+
+ /* not needed so far
+ void setURLs( const KURL::List& urls ) {
+ m_urls = urls;
+ }
+ const KURL::List& urls() const { return m_urls; }
+ */
+
+protected:
+ virtual QDragObject *dragObject() {
+ if ( m_urls.isEmpty() )
+ return 0L;
+
+ QDragObject *drag = new KURLDrag( m_urls, this, "url drag" );
+ return drag;
+ }
+
+private:
+ KURL::List m_urls;
+
+};
+
+
+/*
+*************************************************************************
+*/
+
+class KURLRequester::KURLRequesterPrivate
+{
+public:
+ KURLRequesterPrivate() {
+ edit = 0L;
+ combo = 0L;
+ fileDialogMode = KFile::File | KFile::ExistingOnly | KFile::LocalOnly;
+ }
+
+ void setText( const QString& text ) {
+ if ( combo )
+ {
+ if (combo->editable())
+ {
+ combo->setEditText( text );
+ }
+ else
+ {
+ combo->insertItem( text );
+ combo->setCurrentItem( combo->count()-1 );
+ }
+ }
+ else
+ {
+ edit->setText( text );
+ }
+ }
+
+ void connectSignals( QObject *receiver ) {
+ QObject *sender;
+ if ( combo )
+ sender = combo;
+ else
+ sender = edit;
+
+ connect( sender, SIGNAL( textChanged( const QString& )),
+ receiver, SIGNAL( textChanged( const QString& )));
+ connect( sender, SIGNAL( returnPressed() ),
+ receiver, SIGNAL( returnPressed() ));
+ connect( sender, SIGNAL( returnPressed( const QString& ) ),
+ receiver, SIGNAL( returnPressed( const QString& ) ));
+ }
+
+ void setCompletionObject( KCompletion *comp ) {
+ if ( combo )
+ combo->setCompletionObject( comp );
+ else
+ edit->setCompletionObject( comp );
+ }
+
+ /**
+ * replaces ~user or $FOO, if necessary
+ */
+ QString url() {
+ QString txt = combo ? combo->currentText() : edit->text();
+ KURLCompletion *comp;
+ if ( combo )
+ comp = dynamic_cast<KURLCompletion*>(combo->completionObject());
+ else
+ comp = dynamic_cast<KURLCompletion*>(edit->completionObject());
+
+ if ( comp )
+ return comp->replacedPath( txt );
+ else
+ return txt;
+ }
+
+ KLineEdit *edit;
+ KComboBox *combo;
+ int fileDialogMode;
+ QString fileDialogFilter;
+};
+
+
+
+KURLRequester::KURLRequester( QWidget *editWidget, QWidget *parent,
+ const char *name )
+ : QHBox( parent, name )
+{
+ d = new KURLRequesterPrivate;
+
+ // must have this as parent
+ editWidget->reparent( this, 0, QPoint(0,0) );
+ d->edit = dynamic_cast<KLineEdit*>( editWidget );
+ d->combo = dynamic_cast<KComboBox*>( editWidget );
+
+ init();
+}
+
+
+KURLRequester::KURLRequester( QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+ d = new KURLRequesterPrivate;
+ init();
+}
+
+
+KURLRequester::KURLRequester( const QString& url, QWidget *parent,
+ const char *name )
+ : QHBox( parent, name )
+{
+ d = new KURLRequesterPrivate;
+ init();
+ setKURL( KURL::fromPathOrURL( url ) );
+}
+
+
+KURLRequester::~KURLRequester()
+{
+ delete myCompletion;
+ delete myFileDialog;
+ delete d;
+}
+
+
+void KURLRequester::init()
+{
+ myFileDialog = 0L;
+ myShowLocalProt = false;
+
+ if ( !d->combo && !d->edit )
+ d->edit = new KLineEdit( this, "line edit" );
+
+ myButton = new KURLDragPushButton( this, "kfile button");
+ QIconSet iconSet = SmallIconSet(QString::fromLatin1("fileopen"));
+ QPixmap pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal );
+ myButton->setIconSet( iconSet );
+ myButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
+ QToolTip::add(myButton, i18n("Open file dialog"));
+
+ connect( myButton, SIGNAL( pressed() ), SLOT( slotUpdateURL() ));
+
+ setSpacing( KDialog::spacingHint() );
+
+ QWidget *widget = d->combo ? (QWidget*) d->combo : (QWidget*) d->edit;
+ widget->installEventFilter( this );
+ setFocusProxy( widget );
+
+ d->connectSignals( this );
+ connect( myButton, SIGNAL( clicked() ), this, SLOT( slotOpenDialog() ));
+
+ myCompletion = new KURLCompletion();
+ d->setCompletionObject( myCompletion );
+
+ KAccel *accel = new KAccel( this );
+ accel->insert( KStdAccel::Open, this, SLOT( slotOpenDialog() ));
+ accel->readSettings();
+}
+
+
+void KURLRequester::setURL( const QString& url )
+{
+ if ( myShowLocalProt )
+ {
+ d->setText( url );
+ }
+ else
+ {
+ // ### This code is broken (e.g. for paths with '#')
+ if ( url.startsWith("file://") )
+ d->setText( url.mid( 7 ) );
+ else if ( url.startsWith("file:") )
+ d->setText( url.mid( 5 ) );
+ else
+ d->setText( url );
+ }
+}
+
+void KURLRequester::setKURL( const KURL& url )
+{
+ if ( myShowLocalProt )
+ d->setText( url.url() );
+ else
+ d->setText( url.pathOrURL() );
+}
+
+void KURLRequester::setCaption( const QString& caption )
+{
+ QWidget::setCaption( caption );
+ if (myFileDialog)
+ myFileDialog->setCaption( caption );
+}
+
+QString KURLRequester::url() const
+{
+ return d->url();
+}
+
+void KURLRequester::slotOpenDialog()
+{
+ KURL newurl;
+ if ( (d->fileDialogMode & KFile::Directory) && !(d->fileDialogMode & KFile::File) ||
+ /* catch possible fileDialog()->setMode( KFile::Directory ) changes */
+ (myFileDialog && ( (myFileDialog->mode() & KFile::Directory) &&
+ (myFileDialog->mode() & (KFile::File | KFile::Files)) == 0 ) ) )
+ {
+ newurl = KDirSelectDialog::selectDirectory(url(), d->fileDialogMode & KFile::LocalOnly);
+ if ( !newurl.isValid() )
+ {
+ return;
+ }
+ }
+ else
+ {
+ emit openFileDialog( this );
+
+ KFileDialog *dlg = fileDialog();
+ if ( !d->url().isEmpty() ) {
+ KURL u( url() );
+ // If we won't be able to list it (e.g. http), then don't try :)
+ if ( KProtocolInfo::supportsListing( u ) )
+ dlg->setSelection( u.url() );
+ }
+
+ if ( dlg->exec() != QDialog::Accepted )
+ {
+ return;
+ }
+
+ newurl = dlg->selectedURL();
+ }
+
+ setKURL( newurl );
+ emit urlSelected( d->url() );
+}
+
+void KURLRequester::setMode(uint mode)
+{
+ Q_ASSERT( (mode & KFile::Files) == 0 );
+ d->fileDialogMode = mode;
+ if ( (mode & KFile::Directory) && !(mode & KFile::File) )
+ myCompletion->setMode( KURLCompletion::DirCompletion );
+
+ if (myFileDialog)
+ myFileDialog->setMode( d->fileDialogMode );
+}
+
+unsigned int KURLRequester::mode() const
+{
+ return d->fileDialogMode;
+}
+
+void KURLRequester::setFilter(const QString &filter)
+{
+ d->fileDialogFilter = filter;
+ if (myFileDialog)
+ myFileDialog->setFilter( d->fileDialogFilter );
+}
+
+QString KURLRequester::filter( ) const
+{
+ return d->fileDialogFilter;
+}
+
+
+KFileDialog * KURLRequester::fileDialog() const
+{
+ if ( !myFileDialog ) {
+ QWidget *p = parentWidget();
+ myFileDialog = new KFileDialog( QString::null, d->fileDialogFilter, p,
+ "file dialog", true );
+
+ myFileDialog->setMode( d->fileDialogMode );
+ myFileDialog->setCaption( caption() );
+ }
+
+ return myFileDialog;
+}
+
+
+void KURLRequester::setShowLocalProtocol( bool b )
+{
+ if ( myShowLocalProt == b )
+ return;
+
+ myShowLocalProt = b;
+ setKURL( url() );
+}
+
+void KURLRequester::clear()
+{
+ d->setText( QString::null );
+}
+
+KLineEdit * KURLRequester::lineEdit() const
+{
+ return d->edit;
+}
+
+KComboBox * KURLRequester::comboBox() const
+{
+ return d->combo;
+}
+
+void KURLRequester::slotUpdateURL()
+{
+ // bin compat, myButton is declared as QPushButton
+ KURL u;
+ u = KURL( KURL( QDir::currentDirPath() + '/' ), url() );
+ (static_cast<KURLDragPushButton *>( myButton ))->setURL( u );
+}
+
+bool KURLRequester::eventFilter( QObject *obj, QEvent *ev )
+{
+ if ( ( d->edit == obj ) || ( d->combo == obj ) )
+ {
+ if (( ev->type() == QEvent::FocusIn ) || ( ev->type() == QEvent::FocusOut ))
+ // Forward focusin/focusout events to the urlrequester; needed by file form element in khtml
+ QApplication::sendEvent( this, ev );
+ }
+ return QWidget::eventFilter( obj, ev );
+}
+
+KPushButton * KURLRequester::button() const
+{
+ return myButton;
+}
+
+KEditListBox::CustomEditor KURLRequester::customEditor()
+{
+ setSizePolicy(QSizePolicy( QSizePolicy::Preferred,
+ QSizePolicy::Fixed));
+
+ KLineEdit *edit = d->edit;
+ if ( !edit && d->combo )
+ edit = dynamic_cast<KLineEdit*>( d->combo->lineEdit() );
+
+#ifndef NDEBUG
+ if ( !edit )
+ kdWarning() << "KURLRequester's lineedit is not a KLineEdit!??\n";
+#endif
+
+ KEditListBox::CustomEditor editor( this, edit );
+ return editor;
+}
+
+void KURLRequester::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+KURLComboRequester::KURLComboRequester( QWidget *parent,
+ const char *name )
+ : KURLRequester( new KComboBox(false), parent, name)
+{
+}
+
+#include "kurlrequester.moc"
diff --git a/kio/kfile/kurlrequester.h b/kio/kfile/kurlrequester.h
new file mode 100644
index 000000000..1a7016b24
--- /dev/null
+++ b/kio/kfile/kurlrequester.h
@@ -0,0 +1,301 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef KURLREQUESTER_H
+#define KURLREQUESTER_H
+
+#include <qhbox.h>
+
+#include <keditlistbox.h>
+#include <kfile.h>
+#include <kpushbutton.h>
+#include <kurl.h>
+
+class KComboBox;
+class KFileDialog;
+class KLineEdit;
+class KURLCompletion;
+class KURLDragPushButton;
+
+class QString;
+class QTimer;
+
+/**
+ * This class is a widget showing a lineedit and a button, which invokes a
+ * filedialog. File name completion is available in the lineedit.
+ *
+ * The defaults for the filedialog are to ask for one existing local file, i.e.
+ * KFileDialog::setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly )
+ * The default filter is "*", i.e. show all files, and the start directory is
+ * the current working directory, or the last directory where a file has been
+ * selected.
+ *
+ * You can change this behavior by using setMode() or setFilter().
+ *
+ * \image html kurlrequester.png "KDE URL Requester"
+ *
+ * @short A widget to request a filename/url from the user
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class KIO_EXPORT KURLRequester : public QHBox
+{
+ Q_OBJECT
+ Q_PROPERTY( QString url READ url WRITE setURL )
+ Q_PROPERTY( bool showLocalProtocol READ showLocalProtocol WRITE setShowLocalProtocol )
+ Q_PROPERTY( QString filter READ filter WRITE setFilter )
+ Q_PROPERTY( uint mode READ mode WRITE setMode )
+
+public:
+ /**
+ * Constructs a KURLRequester widget.
+ */
+ KURLRequester( QWidget *parent=0, const char *name=0 );
+
+ /**
+ * Constructs a KURLRequester widget with the initial URL @p url.
+ * // TODO KDE4: Use KURL instead
+ */
+ KURLRequester( const QString& url, QWidget *parent=0, const char *name=0 );
+
+ /**
+ * Special constructor, which creates a KURLRequester widget with a custom
+ * edit-widget. The edit-widget can be either a KComboBox or a KLineEdit
+ * (or inherited thereof). Note: for geometry management reasons, the
+ * edit-widget is reparented to have the KURLRequester as parent.
+ */
+ KURLRequester( QWidget *editWidget, QWidget *parent, const char *name=0 );
+ /**
+ * Destructs the KURLRequester.
+ */
+ ~KURLRequester();
+
+ /**
+ * @returns the current url in the lineedit. May be malformed, if the user
+ * entered something weird. ~user or environment variables are substituted
+ * for local files.
+ * // TODO KDE4: Use KURL so that the result is properly defined
+ */
+ QString url() const;
+
+ /**
+ * Enables/disables showing file:/ in the lineedit, when a local file has
+ * been selected in the filedialog or was set via setURL().
+ * Default is false, not showing file:/
+ * @see showLocalProtocol
+ */
+ void setShowLocalProtocol( bool b );
+
+ /**
+ * Sets the mode of the file dialog.
+ * Note: you can only select one file with the filedialog,
+ * so KFile::Files doesn't make much sense.
+ * @see KFileDialog::setMode()
+ */
+ void setMode( uint m );
+
+ /**
+ * Returns the current mode
+ * @see KFileDialog::mode()
+ * @since 3.3
+ */
+ uint mode() const;
+
+
+ /**
+ * Sets the filter for the file dialog.
+ * @see KFileDialog::setFilter()
+ */
+ void setFilter( const QString& filter );
+
+ /**
+ * Returns the current filter for the file dialog.
+ * @see KFileDialog::filter()
+ * @since 3.3
+ */
+ QString filter() const;
+
+ /**
+ * @returns whether local files will be prefixed with file:/ in the
+ * lineedit
+ * @see setShowLocalProtocol
+ */
+ bool showLocalProtocol() const { return myShowLocalProt; }
+ // ## KDE4: there's no reason to keep this, it should always be false
+
+ /**
+ * @returns a pointer to the filedialog
+ * You can use this to customize the dialog, e.g. to specify a filter.
+ * Never returns 0L.
+ *
+ * Remove in KDE4? KURLRequester should use KDirSelectDialog for
+ * (mode & KFile::Directory) && !(mode & KFile::File)
+ */
+ virtual KFileDialog * fileDialog() const;
+
+ /**
+ * @returns a pointer to the lineedit, either the default one, or the
+ * special one, if you used the special constructor.
+ *
+ * It is provided so that you can e.g. set an own completion object
+ * (e.g. KShellCompletion) into it.
+ */
+ KLineEdit * lineEdit() const;
+
+ /**
+ * @returns a pointer to the combobox, in case you have set one using the
+ * special constructor. Returns 0L otherwise.
+ */
+ KComboBox * comboBox() const;
+
+ /**
+ * @returns a pointer to the pushbutton. It is provided so that you can
+ * specify an own pixmap or a text, if you really need to.
+ */
+ KPushButton * button() const;
+
+ /**
+ * @returns the KURLCompletion object used in the lineedit/combobox.
+ */
+ KURLCompletion *completionObject() const { return myCompletion; }
+
+ /**
+ * @returns an object, suitable for use with KEditListBox. It allows you
+ * to put this KURLRequester into a KEditListBox.
+ * Basically, do it like this:
+ * \code
+ * KURLRequester *req = new KURLRequester( someWidget );
+ * [...]
+ * KEditListBox *editListBox = new KEditListBox( i18n("Some Title"), req->customEditor(), someWidget );
+ * \endcode
+ * @since 3.1
+ */
+ KEditListBox::CustomEditor customEditor();
+
+public slots:
+ /**
+ * Sets the url in the lineedit to @p url. Depending on the state of
+ * showLocalProtocol(), file:/ on local files will be shown or not.
+ * @since 3.1
+ * // TODO KDE4: Use KURL instead
+ */
+ void setURL( const QString& url );
+
+ /**
+ * Sets the url in the lineedit to @p url.
+ * @since 3.4
+ * // TODO KDE4: rename to setURL
+ */
+ void setKURL( const KURL& url );
+
+ /**
+ * Sets the caption of the file dialog.
+ * @since 3.1
+ */
+ virtual void setCaption( const QString& caption );
+
+ /**
+ * Clears the lineedit/combobox.
+ */
+ void clear();
+
+signals:
+ // forwards from LineEdit
+ /**
+ * Emitted when the text in the lineedit changes.
+ * The parameter contains the contents of the lineedit.
+ * @since 3.1
+ */
+ void textChanged( const QString& );
+
+ /**
+ * Emitted when return or enter was pressed in the lineedit.
+ */
+ void returnPressed();
+
+ /**
+ * Emitted when return or enter was pressed in the lineedit.
+ * The parameter contains the contents of the lineedit.
+ */
+ void returnPressed( const QString& );
+
+ /**
+ * Emitted before the filedialog is going to open. Connect
+ * to this signal to "configure" the filedialog, e.g. set the
+ * filefilter, the mode, a preview-widget, etc. It's usually
+ * not necessary to set a URL for the filedialog, as it will
+ * get set properly from the editfield contents.
+ *
+ * If you use multiple KURLRequesters, you can connect all of them
+ * to the same slot and use the given KURLRequester pointer to know
+ * which one is going to open.
+ */
+ void openFileDialog( KURLRequester * );
+
+ /**
+ * Emitted when the user changed the URL via the file dialog.
+ * The parameter contains the contents of the lineedit.
+ * // TODO KDE4: Use KURL instead
+ */
+ void urlSelected( const QString& );
+
+protected:
+ void init();
+
+ KURLCompletion * myCompletion;
+
+
+private:
+ KURLDragPushButton * myButton;
+ bool myShowLocalProt;
+ mutable KFileDialog * myFileDialog;
+
+
+protected slots:
+ /**
+ * Called when the button is pressed to open the filedialog.
+ * Also called when KStdAccel::Open (default is Ctrl-O) is pressed.
+ */
+ void slotOpenDialog();
+
+private slots:
+ void slotUpdateURL();
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+ bool eventFilter( QObject *obj, QEvent *ev );
+private:
+ class KURLRequesterPrivate;
+ KURLRequesterPrivate *d;
+};
+
+/**
+ * URL requester with a combo box, for use in Designer
+ */
+class KIO_EXPORT KURLComboRequester : public KURLRequester
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructs a KURLRequester widget with a combobox.
+ */
+ KURLComboRequester( QWidget *parent=0, const char *name=0 );
+};
+
+
+#endif // KURLREQUESTER_H
diff --git a/kio/kfile/kurlrequesterdlg.cpp b/kio/kfile/kurlrequesterdlg.cpp
new file mode 100644
index 000000000..ed89f599b
--- /dev/null
+++ b/kio/kfile/kurlrequesterdlg.cpp
@@ -0,0 +1,135 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Wilco Greven <greven@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qstring.h>
+#include <qtoolbutton.h>
+
+#include <kaccel.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <krecentdocument.h>
+#include <kurl.h>
+#include <kurlrequester.h>
+
+#include "kurlrequesterdlg.h"
+
+
+KURLRequesterDlg::KURLRequesterDlg( const QString& urlName, QWidget *parent,
+ const char *name, bool modal )
+ : KDialogBase( Plain, QString::null, Ok|Cancel|User1, Ok, parent, name,
+ modal, true, KStdGuiItem::clear() )
+{
+ initDialog(i18n( "Location:" ), urlName);
+}
+
+KURLRequesterDlg::KURLRequesterDlg( const QString& urlName, const QString& _text, QWidget *parent, const char *name, bool modal )
+ : KDialogBase( Plain, QString::null, Ok|Cancel|User1, Ok, parent, name,
+ modal, true, KStdGuiItem::clear() )
+{
+ initDialog(_text, urlName);
+}
+
+KURLRequesterDlg::~KURLRequesterDlg()
+{
+}
+
+void KURLRequesterDlg::initDialog(const QString &text,const QString &urlName)
+{
+ QVBoxLayout * topLayout = new QVBoxLayout( plainPage(), 0,
+ spacingHint() );
+
+ QLabel * label = new QLabel( text , plainPage() );
+ topLayout->addWidget( label );
+
+ urlRequester_ = new KURLRequester( urlName, plainPage(), "urlRequester" );
+ urlRequester_->setMinimumWidth( urlRequester_->sizeHint().width() * 3 );
+ topLayout->addWidget( urlRequester_ );
+ urlRequester_->setFocus();
+ connect( urlRequester_->lineEdit(), SIGNAL(textChanged(const QString&)),
+ SLOT(slotTextChanged(const QString&)) );
+ bool state = !urlName.isEmpty();
+ enableButtonOK( state );
+ enableButton( KDialogBase::User1, state );
+ /*
+ KFile::Mode mode = static_cast<KFile::Mode>( KFile::File |
+ KFile::ExistingOnly );
+ urlRequester_->setMode( mode );
+ */
+ connect( this, SIGNAL( user1Clicked() ), SLOT( slotClear() ) );
+}
+
+void KURLRequesterDlg::slotTextChanged(const QString & text)
+{
+ bool state = !text.stripWhiteSpace().isEmpty();
+ enableButtonOK( state );
+ enableButton( KDialogBase::User1, state );
+}
+
+void KURLRequesterDlg::slotClear()
+{
+ urlRequester_->clear();
+}
+
+KURL KURLRequesterDlg::selectedURL() const
+{
+ if ( result() == QDialog::Accepted )
+ return KURL::fromPathOrURL( urlRequester_->url() );
+ else
+ return KURL();
+}
+
+
+KURL KURLRequesterDlg::getURL(const QString& dir, QWidget *parent,
+ const QString& caption)
+{
+ KURLRequesterDlg dlg(dir, parent, "filedialog", true);
+
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+
+ dlg.exec();
+
+ const KURL& url = dlg.selectedURL();
+ if (url.isValid())
+ KRecentDocument::add(url);
+
+ return url;
+}
+
+KFileDialog * KURLRequesterDlg::fileDialog()
+{
+ return urlRequester_->fileDialog();
+}
+
+KURLRequester * KURLRequesterDlg::urlRequester()
+{
+ return urlRequester_;
+}
+
+#include "kurlrequesterdlg.moc"
+
+// vim:ts=4:sw=4:tw=78
diff --git a/kio/kfile/kurlrequesterdlg.h b/kio/kfile/kurlrequesterdlg.h
new file mode 100644
index 000000000..a4f2cf0f3
--- /dev/null
+++ b/kio/kfile/kurlrequesterdlg.h
@@ -0,0 +1,114 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Wilco Greven <greven@kde.org>
+
+ library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef KURLREQUESTERDIALOG_H
+#define KURLREQUESTERDIALOG_H
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+class KURLCompletion;
+class KURLRequester;
+class KFileDialog;
+/**
+ * Dialog in which a user can enter a filename or url. It is a dialog
+ * encapsulating KURLRequester. The API is derived from
+ * KFileDialog.
+ *
+ * @short Simple dialog to enter a filename/url.
+ * @author Wilco Greven <greven@kde.org>
+ */
+class KIO_EXPORT KURLRequesterDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs a KURLRequesterDlg.
+ *
+ * @param url The url of the directory to start in. Use QString::null
+ * to start in the current working directory, or the last
+ * directory where a file has been selected.
+ * @param parent The parent object of this widget.
+ * @param name The name of this widget.
+ * @param modal Specifies whether the dialog should be opened as modal
+ * or not.
+ */
+ KURLRequesterDlg( const QString& url, QWidget *parent,
+ const char *name, bool modal = true );
+
+ /**
+ * Constructs a KURLRequesterDlg.
+ *
+ * @param url The url of the directory to start in. Use QString::null
+ * to start in the current working directory, or the last
+ * directory where a file has been selected.
+ * @param text Text of the label
+ * @param parent The parent object of this widget.
+ * @param name The name of this widget.
+ * @param modal Specifies whether the dialog should be opened as modal
+ * or not.
+ */
+ KURLRequesterDlg( const QString& url, const QString& text,
+ QWidget *parent, const char *name, bool modal=true );
+ /**
+ * Destructs the dialog.
+ */
+ ~KURLRequesterDlg();
+
+ /**
+ * Returns the fully qualified filename.
+ */
+ KURL selectedURL() const;
+
+ /**
+ * Creates a modal dialog, executes it and returns the selected URL.
+ *
+ * @param url This specifies the initial path of the input line.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The caption to use for the dialog.
+ */
+ static KURL getURL(const QString& url = QString::null,
+ QWidget *parent= 0, const QString& caption = QString::null);
+
+ /**
+ * Returns a pointer to the file dialog used by the KURLRequester.
+ */
+ KFileDialog * fileDialog();
+ /**
+ * Returns a pointer to the KURLRequester.
+ */
+ KURLRequester *urlRequester();
+
+private slots:
+ void slotClear();
+ void slotTextChanged(const QString &);
+private:
+ void initDialog(const QString &text, const QString &url);
+ KURLRequester *urlRequester_;
+
+ class KURLRequesterDlgPrivate;
+ KURLRequesterDlgPrivate *d;
+
+};
+
+#endif // KURLREQUESTERDIALOG_H
+
+// vim:ts=4:sw=4:tw=78
diff --git a/kio/kfile/tests/Makefile.am b/kio/kfile/tests/Makefile.am
new file mode 100644
index 000000000..9689f7a27
--- /dev/null
+++ b/kio/kfile/tests/Makefile.am
@@ -0,0 +1,41 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1996-1997 Matthias Kalle Dalheimer (kalle@kde.org)
+# (C) 1997-1998 Stephan Kulow (coolo@kde.org)
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+INCLUDES = $(all_includes)
+
+AM_LDFLAGS = $(QT_LDFLAGS) $(X_LDFLAGS) $(KDE_RPATH)
+
+check_PROGRAMS = kfstest kurlrequestertest kfiletreeviewtest \
+ kopenwithtest kdirselectdialogtest kicondialogtest \
+ knotifytest kcustommenueditortest
+
+# noinst_HEADERS =
+
+METASOURCES = AUTO
+
+LDADD = $(LIB_KIO)
+kcustommenueditortest_SOURCES = kcustommenueditortest.cpp
+kurlrequestertest_SOURCES = kurlrequestertest.cpp
+kfstest_SOURCES = kfstest.cpp kfdtest.cpp
+kfiletreeviewtest_SOURCES = kfiletreeviewtest.cpp
+kopenwithtest_SOURCES = kopenwithtest.cpp
+kdirselectdialogtest_SOURCES = kdirselectdialogtest.cpp
+kicondialogtest_SOURCES = kicondialogtest.cpp
+knotifytest_SOURCES = knotifytest.cpp
+
diff --git a/kio/kfile/tests/kcustommenueditortest.cpp b/kio/kfile/tests/kcustommenueditortest.cpp
new file mode 100644
index 000000000..532297d0c
--- /dev/null
+++ b/kio/kfile/tests/kcustommenueditortest.cpp
@@ -0,0 +1,19 @@
+#include "kcustommenueditor.h"
+#include <kapplication.h>
+#include <klocale.h>
+#include <kconfig.h>
+
+int main(int argc, char** argv)
+{
+ KLocale::setMainCatalogue("kdelibs");
+ KApplication app(argc, argv, "KCustomMenuEditorTest");
+ KCustomMenuEditor editor(0);
+ KConfig *cfg = new KConfig("kdesktop_custom_menu2");
+ editor.load(cfg);
+ if (editor.exec())
+ {
+ editor.save(cfg);
+ cfg->sync();
+ }
+}
+
diff --git a/kio/kfile/tests/kdirselectdialogtest.cpp b/kio/kfile/tests/kdirselectdialogtest.cpp
new file mode 100644
index 000000000..e2eb52f1b
--- /dev/null
+++ b/kio/kfile/tests/kdirselectdialogtest.cpp
@@ -0,0 +1,17 @@
+#include <kapplication.h>
+#include <kdirselectdialog.h>
+#include <kmessagebox.h>
+#include <kurl.h>
+
+int main( int argc, char **argv )
+{
+ KApplication app(argc, argv, "kdirselectdialogtest");
+
+ KURL u = KDirSelectDialog::selectDirectory( (argc >= 1) ? argv[1] : QString::null );
+ if ( u.isValid() )
+ KMessageBox::information( 0L,
+ QString::fromLatin1("You selected the url: %1")
+ .arg( u.prettyURL() ), "Selected URL" );
+
+ return 0;
+}
diff --git a/kio/kfile/tests/kfdtest.cpp b/kio/kfile/tests/kfdtest.cpp
new file mode 100644
index 000000000..d9341a7ae
--- /dev/null
+++ b/kio/kfile/tests/kfdtest.cpp
@@ -0,0 +1,34 @@
+#include "kfdtest.h"
+
+#include <qstringlist.h>
+#include <kfiledialog.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <qtimer.h>
+
+KFDTest::KFDTest( const QString& startDir, QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_startDir( startDir )
+{
+ QTimer::singleShot( 1000, this, SLOT( doit() ));
+}
+
+void KFDTest::doit()
+{
+ KFileDialog *dlg = new KFileDialog( m_startDir, QString::null, 0L,
+ "file dialog", true );
+ dlg->setMode( KFile::File);
+ dlg->setOperationMode( KFileDialog::Saving );
+ QStringList filter;
+ filter << "all/allfiles" << "text/plain";
+ dlg->setMimeFilter( filter, "all/allfiles" );
+
+ if ( dlg->exec() == KDialog::Accepted )
+ {
+ KMessageBox::information(0, QString::fromLatin1("You selected the file: %1").arg( dlg->selectedURL().prettyURL() ));
+ }
+
+// qApp->quit();
+}
+
+#include "kfdtest.moc"
diff --git a/kio/kfile/tests/kfdtest.h b/kio/kfile/tests/kfdtest.h
new file mode 100644
index 000000000..0743bb96c
--- /dev/null
+++ b/kio/kfile/tests/kfdtest.h
@@ -0,0 +1,28 @@
+/****************************************************************************
+** $Id$
+**
+** Copyright (C) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef KFDTEST_H
+#define KFDTEST_H
+
+#include <qobject.h>
+
+class KFDTest : public QObject
+{
+ Q_OBJECT
+
+public:
+ KFDTest( const QString& startDir, QObject *parent = 0, const char *name = 0);
+
+public slots:
+ void doit();
+
+private:
+ QString m_startDir;
+};
+
+
+#endif // KFDTEST_H
diff --git a/kio/kfile/tests/kfiletreeviewtest.cpp b/kio/kfile/tests/kfiletreeviewtest.cpp
new file mode 100644
index 000000000..6a4ea719f
--- /dev/null
+++ b/kio/kfile/tests/kfiletreeviewtest.cpp
@@ -0,0 +1,165 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdir.h>
+
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kmainwindow.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <kstatusbar.h>
+
+#include <kfiletreeview.h>
+#include "kfiletreeviewtest.h"
+
+
+#include "kfiletreeviewtest.moc"
+
+testFrame::testFrame():KMainWindow(0,"Test FileTreeView"),
+ dirOnlyMode(false)
+
+{
+ treeView = new KFileTreeView( this );
+ treeView->setDragEnabled( true );
+ treeView->setAcceptDrops( true );
+ treeView->setDropVisualizer( true );
+
+
+ /* Connect to see the status bar */
+ KStatusBar* sta = statusBar();
+ connect( treeView, SIGNAL( onItem( const QString& )),
+ sta, SLOT( message( const QString& )));
+
+ connect( treeView, SIGNAL( dropped( QWidget*, QDropEvent*, KURL::List& )),
+ this, SLOT( urlsDropped( QWidget*, QDropEvent*, KURL::List& )));
+
+ connect( treeView, SIGNAL( dropped( KURL::List&, KURL& )), this,
+ SLOT( copyURLs( KURL::List&, KURL& )));
+
+ treeView->addColumn( "File" );
+ treeView->addColumn( "ChildCount" );
+ setCentralWidget( treeView );
+ resize( 600, 400 );
+
+ showPath( KURL::fromPathOrURL( QDir::homeDirPath() ));
+}
+
+void testFrame::showPath( const KURL &url )
+{
+ QString fname = "TestBranch"; // url.fileName ();
+ /* try a user icon */
+ KIconLoader *loader = KGlobal::iconLoader();
+ QPixmap pix = loader->loadIcon( "contents2", KIcon::Small );
+ QPixmap pixOpen = loader->loadIcon( "contents", KIcon::Small );
+
+ KFileTreeBranch *nb = treeView->addBranch( url, fname, pix );
+
+ if( nb )
+ {
+ if( dirOnlyMode ) treeView->setDirOnlyMode( nb, true );
+ nb->setOpenPixmap( pixOpen );
+
+ connect( nb, SIGNAL(populateFinished(KFileTreeViewItem*)),
+ this, SLOT(slotPopulateFinished(KFileTreeViewItem*)));
+ connect( nb, SIGNAL( directoryChildCount( KFileTreeViewItem *, int )),
+ this, SLOT( slotSetChildCount( KFileTreeViewItem*, int )));
+ // nb->setChildRecurse(false );
+
+ nb->setOpen(true);
+ }
+
+
+}
+
+void testFrame::urlsDropped( QWidget* , QDropEvent* , KURL::List& list )
+{
+ KURL::List::ConstIterator it = list.begin();
+ for ( ; it != list.end(); ++it ) {
+ kdDebug() << "Url dropped: " << (*it).prettyURL() << endl;
+ }
+}
+
+void testFrame::copyURLs( KURL::List& list, KURL& to )
+{
+ KURL::List::ConstIterator it = list.begin();
+ kdDebug() << "Copy to " << to.prettyURL() << endl;
+ for ( ; it != list.end(); ++it ) {
+ kdDebug() << "Url: " << (*it).prettyURL() << endl;
+ }
+
+}
+
+
+void testFrame::slotPopulateFinished(KFileTreeViewItem *item )
+{
+ if( item )
+ {
+#if 0
+ int cc = item->childCount();
+
+ kdDebug() << "setting column 2 of treeview with count " << cc << endl;
+
+ item->setText( 1, QString::number( cc ));
+#endif
+ }
+ else
+ {
+ kdDebug() << "slotPopFinished for uninitalised item" << endl;
+ }
+}
+
+void testFrame::slotSetChildCount( KFileTreeViewItem *item, int c )
+{
+ if( item )
+ item->setText(1, QString::number( c ));
+}
+
+int main(int argc, char **argv)
+{
+ KApplication a(argc, argv, "kfiletreeviewtest");
+ QString name1;
+ QStringList names;
+
+ QString argv1;
+ testFrame *tf;
+
+ tf = new testFrame();
+ a.setMainWidget( tf );
+
+ if (argc > 1)
+ {
+ for( int i = 1; i < argc; i++ )
+ {
+ argv1 = QString::fromLatin1(argv[i]);
+ kdDebug() << "Opening " << argv1 << endl;
+ if( argv1 == "-d" )
+ tf->setDirOnly();
+ else
+ {
+ KURL u( argv1 );
+ tf->showPath( u );
+ }
+ }
+ }
+ tf->show();
+ int ret = a.exec();
+ return( ret );
+}
diff --git a/kio/kfile/tests/kfiletreeviewtest.h b/kio/kfile/tests/kfiletreeviewtest.h
new file mode 100644
index 000000000..1286e1be2
--- /dev/null
+++ b/kio/kfile/tests/kfiletreeviewtest.h
@@ -0,0 +1,42 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KFILETREEVIEWTEST
+#define KFILETREEVIEWTEST
+
+class testFrame: public KMainWindow
+{
+ Q_OBJECT
+public:
+ testFrame();
+ void showPath( const KURL & );
+ void setDirOnly( ) { dirOnlyMode = true; }
+public slots:
+ void slotPopulateFinished(KFileTreeViewItem *);
+ void slotSetChildCount( KFileTreeViewItem *item, int c );
+
+ void urlsDropped( QWidget*, QDropEvent*, KURL::List& );
+ void copyURLs( KURL::List& list, KURL& to );
+private:
+ KFileTreeView *treeView;
+ bool dirOnlyMode;
+};
+
+
+#endif
diff --git a/kio/kfile/tests/kfstest.cpp b/kio/kfile/tests/kfstest.cpp
new file mode 100644
index 000000000..16d74cb0c
--- /dev/null
+++ b/kio/kfile/tests/kfstest.cpp
@@ -0,0 +1,183 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997, 1998 Richard Moore <rich@kde.org>
+ 1998 Stephan Kulow <coolo@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <qdir.h>
+#include <qlayout.h>
+#include <qstringlist.h>
+#include <qwidget.h>
+
+#include <kfiledialog.h>
+#include <kfileiconview.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kurlbar.h>
+#include <kdiroperator.h>
+#include <kfile.h>
+#include <kdebug.h>
+#include <kicondialog.h>
+
+#include "kfdtest.h"
+
+int main(int argc, char **argv)
+{
+ KApplication a(argc, argv, "kfstest");
+ QString name1;
+ QStringList names;
+
+ QString argv1;
+ QString startDir;
+ if (argc > 1)
+ argv1 = QString::fromLatin1(argv[1]);
+ if ( argc > 2 )
+ startDir = QString::fromLatin1( argv[2]);
+
+ if (argv1 == QString::fromLatin1("diroperator")) {
+ KDirOperator *op = new KDirOperator(startDir, 0, "operator");
+ op->setViewConfig( KGlobal::config(), "TestGroup" );
+ op->setView(KFile::Simple);
+ op->show();
+ a.setMainWidget(op);
+ a.exec();
+ }
+
+ else if (argv1 == QString::fromLatin1("justone")) {
+ QString name = KFileDialog::getOpenFileName(startDir);
+ qDebug("filename=%s",name.latin1());
+ }
+
+ else if (argv1 == QString::fromLatin1("existingURL")) {
+ KURL url = KFileDialog::getExistingURL();
+ qDebug("URL=%s",url.url().latin1());
+ name1 = url.url();
+ }
+
+ else if (argv1 == QString::fromLatin1("preview")) {
+ KURL u = KFileDialog::getImageOpenURL();
+ qDebug("filename=%s", u.url().latin1());
+ }
+
+ else if (argv1 == QString::fromLatin1("preselect")) {
+ names = KFileDialog::getOpenFileNames(QString::fromLatin1("/etc/passwd"));
+ QStringList::Iterator it = names.begin();
+ while ( it != names.end() ) {
+ qDebug("selected file: %s", (*it).latin1());
+ ++it;
+ }
+ }
+
+ else if (argv1 == QString::fromLatin1("dirs"))
+ name1 = KFileDialog::getExistingDirectory();
+
+ else if (argv1 == QString::fromLatin1("heap")) {
+ KFileDialog *dlg = new KFileDialog( startDir, QString::null, 0L,
+ "file dialog", true );
+ dlg->setMode( KFile::File);
+ dlg->setOperationMode( KFileDialog::Saving );
+ QStringList filter;
+ filter << "all/allfiles" << "text/plain";
+ dlg->setMimeFilter( filter, "all/allfiles" );
+ KURLBar *urlBar = dlg->speedBar();
+ if ( urlBar )
+ {
+ urlBar->insertDynamicItem( KURL("ftp://ftp.kde.org"),
+ QString::fromLatin1("KDE FTP Server") );
+ }
+
+ if ( dlg->exec() == KDialog::Accepted )
+ name1 = dlg->selectedURL().url();
+ }
+
+ else if ( argv1 == QString::fromLatin1("eventloop") )
+ {
+ KFDTest *test = new KFDTest( startDir );
+ return a.exec();
+ }
+
+ else if (argv1 == QString::fromLatin1("save")) {
+ KURL u = KFileDialog::getSaveURL();
+// QString(QDir::homeDirPath() + QString::fromLatin1("/testfile")),
+// QString::null, 0L);
+ name1 = u.url();
+ }
+
+ else if (argv1 == QString::fromLatin1("icon")) {
+ KIconDialog dlg;
+ QString icon = dlg.selectIcon();
+ kdDebug() << icon << endl;
+ }
+
+// else if ( argv1 == QString::fromLatin1("dirselect") ) {
+// KURL url;
+// url.setPath( "/" );
+// KURL selected = KDirSelectDialog::selectDirectory( url );
+// name1 = selected.url();
+// qDebug("*** selected: %s", selected.url().latin1());
+// }
+
+ else {
+ KFileDialog dlg(startDir,
+ QString::fromLatin1("*|All Files\n"
+ "*.lo *.o *.la|All libtool Files"),
+ 0, 0, true);
+// dlg.setFilter( "*.kdevelop" );
+ dlg.setMode( (KFile::Mode) (KFile::Files |
+ KFile::Directory |
+ KFile::ExistingOnly |
+ KFile::LocalOnly) );
+// QStringList filter;
+// filter << "text/plain" << "text/html" << "image/png";
+// dlg.setMimeFilter( filter );
+// KMimeType::List types;
+// types.append( KMimeType::mimeType( "text/plain" ) );
+// types.append( KMimeType::mimeType( "text/html" ) );
+// dlg.setFilterMimeType( "Filetypes:", types, types.first() );
+ if ( dlg.exec() == QDialog::Accepted ) {
+ KURL::List list = dlg.selectedURLs();
+ KURL::List::ConstIterator it = list.begin();
+ qDebug("*** selectedURLs(): ");
+ while ( it != list.end() ) {
+ name1 = (*it).url();
+ qDebug(" -> %s", name1.latin1());
+ ++it;
+ }
+ qDebug("*** selectedFile: %s", dlg.selectedFile().latin1());
+ qDebug("*** selectedURL: %s", dlg.selectedURL().url().latin1());
+ qDebug("*** selectedFiles: ");
+ QStringList l = dlg.selectedFiles();
+ QStringList::Iterator it2 = l.begin();
+ while ( it2 != l.end() ) {
+ qDebug(" -> %s", (*it2).latin1());
+ ++it2;
+ }
+ }
+ }
+
+ if (!(name1.isNull()))
+ KMessageBox::information(0, QString::fromLatin1("You selected the file " ) + name1,
+ QString::fromLatin1("Your Choice"));
+ return 0;
+}
diff --git a/kio/kfile/tests/kicondialogtest.cpp b/kio/kfile/tests/kicondialogtest.cpp
new file mode 100644
index 000000000..23301b752
--- /dev/null
+++ b/kio/kfile/tests/kicondialogtest.cpp
@@ -0,0 +1,19 @@
+#include <kapplication.h>
+#include <kicondialog.h>
+
+int main( int argc, char **argv )
+{
+ KApplication app( argc, argv, "kicondialogtest" );
+
+// KIconDialog::getIcon();
+
+ KIconButton button;
+ app.setMainWidget( &button );
+ button.show();
+
+
+ return app.exec();
+}
+
+/* vim: et sw=4
+ */
diff --git a/kio/kfile/tests/knotifytest.cpp b/kio/kfile/tests/knotifytest.cpp
new file mode 100644
index 000000000..e27893589
--- /dev/null
+++ b/kio/kfile/tests/knotifytest.cpp
@@ -0,0 +1,10 @@
+#include <kapplication.h>
+#include <knotifydialog.h>
+
+int main( int argc, char **argv )
+{
+ KApplication app( argc, argv, "knotifytest" );
+ KNotifyDialog *dlg = new KNotifyDialog();
+ dlg->addApplicationEvents( "kwin" );
+ return dlg->exec();
+}
diff --git a/kio/kfile/tests/kopenwithtest.cpp b/kio/kfile/tests/kopenwithtest.cpp
new file mode 100644
index 000000000..96e18bcc2
--- /dev/null
+++ b/kio/kfile/tests/kopenwithtest.cpp
@@ -0,0 +1,67 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2003 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kapplication.h>
+#include <qwidget.h>
+#include <qstringlist.h>
+#include <qdir.h>
+#include <kopenwith.h>
+#include <kurl.h>
+#include <kdebug.h>
+
+int main(int argc, char **argv)
+{
+ KApplication app(argc, argv, "kopenwithtest");
+ KURL::List list;
+
+ list += KURL("file:///tmp/testfile.txt");
+
+ // Test with one URL
+ KOpenWithDlg* dlg = new KOpenWithDlg(list, "OpenWith_Text", "OpenWith_Value", 0);
+ if(dlg->exec()) {
+ kdDebug() << "Dialog ended successfully\ntext: " << dlg->text() << endl;
+ }
+ else
+ kdDebug() << "Dialog was canceled." << endl;
+ delete dlg;
+
+ // Test with two URLs
+ list += KURL("http://www.kde.org/index.html");
+ dlg = new KOpenWithDlg(list, "OpenWith_Text", "OpenWith_Value", 0);
+ if(dlg->exec()) {
+ kdDebug() << "Dialog ended successfully\ntext: " << dlg->text() << endl;
+ }
+ else
+ kdDebug() << "Dialog was canceled." << endl;
+ delete dlg;
+
+ // Test with a mimetype
+ QString mimetype = "text/plain";
+ dlg = new KOpenWithDlg( mimetype, "kedit", 0);
+ if(dlg->exec()) {
+ kdDebug() << "Dialog ended successfully\ntext: " << dlg->text() << endl;
+ }
+ else
+ kdDebug() << "Dialog was canceled." << endl;
+ delete dlg;
+
+ return 0;
+}
+
diff --git a/kio/kfile/tests/kurlrequestertest.cpp b/kio/kfile/tests/kurlrequestertest.cpp
new file mode 100644
index 000000000..5601f4922
--- /dev/null
+++ b/kio/kfile/tests/kurlrequestertest.cpp
@@ -0,0 +1,16 @@
+#include <kapplication.h>
+#include <keditlistbox.h>
+#include <kurlrequester.h>
+#include <kurlrequesterdlg.h>
+
+int main( int argc, char **argv )
+{
+ KApplication app( argc, argv, "kurlrequestertest" );
+ KURL url = KURLRequesterDlg::getURL( "ftp://ftp.kde.org" );
+ qDebug( "Selected url: %s", url.url().latin1());
+
+ KURLRequester *req = new KURLRequester();
+ KEditListBox *el = new KEditListBox( QString::fromLatin1("Test"), req->customEditor() );
+ el->show();
+ return app.exec();
+}