diff --git a/doc-extras/ChangeLog b/doc-extras/ChangeLog index 399b769e..67b9b53d 100644 --- a/doc-extras/ChangeLog +++ b/doc-extras/ChangeLog @@ -1,763 +1,763 @@ The Krusader Handbook ChangeLog ------------------------------- 2.x.x ========================= Date: 20xx-xx-xx CHANGED: Remove installation.docbook because in the majority of the cases, users install krusader as available in their distribution ADDED: Add documentation on the new options to move tabs left or right ADDED: Add a note on the new capabilities of the "Search for" combobox FIXED: Links on docs.kde.org - ADDED: Document new options to hide SquasFS entries and selected mountpoints from Media menu + ADDED: Document new options to hide SquashFS entries and selected mountpoints from Media menu 2.7.2 ========================= Date: 2019-08-25 CHANGED: Rename SVNNEWS into NEWS in docs FIXED: Updated links and used https:// where appropriate 2.7.1 "Peace of Mind" ========================== Date: 2018-08-12 ADDED: More documentation on the search bar, new shortcuts. FIXED: Synchronizer is not disabled by default anymore. CHANGED: Reorganized section on quick search in BookMan II 2.7.0 "Peace of Mind" ========================== Date: 2018-05-13 CHANGED: Updated release information in docs CHANGED: Updated ChangeLog, NEWS and Features page with v2.7 changes FIXED: Changes in several files because, by default, F2 renames and F9 opens a terminal window FIXED: Cleaned up old auxiliary files, updated references and fixed layout in docs ADDED: Add new icon theme option to Konfigurator docs CHANGED: Update the docs according to keybinding changes ADDED: bookmark quick search (type symbols in bookmark menu to activate) ADDED: Add docs for the new Konfigurator option 'Search in special items' CHANGED: Updated copyright years and release info in docs CHANGED: Updated and standardized FDL license headers CHANGED: Updated credits in docbook ADDED: Add the new option to Konfigurator docs ADDED: Document new features: tab pinning and the Open MountMan menu item ADDED: More updates to the search dialog docs ADDED: Add new search excluding options to the docs ADDED: Add new option for the Right arrow key to the docs CHANGED: Follow the renaming of popup panel in docs FIXED: Fix menu-command.docbook (patch by Christoph) FIXED: Fix shortcuts (inspired by Christoph's work) FIXED: Fix shortcuts (patch by Christoph) + minor cleanup CHANGED: Update man page CHANGED: Add missing docs for an option in Konfigurator ADDED: Add docs on the new 'Show Tab Bar on single tab' option ADDED: Add new Konfigurator 'Always show current item' item to the docs CHANGED: Minor updates for the man page 2.6.0 "Stiff Challenges" ========================== Date: 2017-04-12 FIXED: BUG #322915 (Sync the docs with katepart) FIXED: Fix terminology in the usage of KDE CHANGED: Remove Space for calculating dir sizes from docs CHANGED: Remove krusader-news ML from docs FIXED: fix gui strings (thanks to Burkhard Lück) FIXED: branding: for KDE -> by KDE CHANGED: Sync docs with code (1 screenshot still need to be replaced) CHANGED: Do not bother previous maintainer FIXED: Fix credits FIXED: The INSTALL file was updated after a Kubuntu 16.10 installation. The install.docbook was corrected to avoid seeing the text `krusader--profile` FIXED: Sync docs with new installation instructions CHANGED: Minor rebranding in docs ADDED: Add some documentation on the JobMan CHANGED: Replace kde-files.org with store.kde.org in docs CHANGED: Major cleanup from old links in docs FIXED: remove obsolete entities reporting.bugs + updating.documentation, commented and not used CHANGED: Update Konfigurator start page documentation FIXED: Fix minor typos in docs 2.5.0 "Clear Skies" ========================== Date: 2016-10-22 ADDED: Add information on removal of Synchronizer and on how to reenable it. FIXED: Bug #298346 2.4.0-beta3 "Single Step" ========================== Date: 2012-10-20 2.4.0-beta2 "Giant Steps" ========================== Date: 2012-10-12 ADDED: description for the new shortcut, pressing Ctrl+Return when media menu is open (un)mounts the highlighted device. ADDED: description for options on Panel > Media Menu tab ADDED: Description for options: Archives > krarc > Enable Write Support, Archives > Fine-Tuning > Test archives before unpacking ADDED: shortcut description for "Go to Other Panel's Directory" (Ctrl+=) ADDED: option: General > Viewer/Editor > Viewer > Use Okteta as Hex viewer CHANGED: revisited menu description (thanks to Burkhard Lück) FIXED: Many fixes by Pino Toscano. FIXED: Bugs #277151, #277152, #277491, #277557, #277901, #278129, #278135, #278136, #278139, #278142, #278143, #285547, #285558, #285565, #300912, #300923, #300926, #300928, #300929, #300932, #300978, #300982. FIXED: Bugs reported by Burkhard Lück ( http://groups.google.com/group/krusader-devel/browse_thread/thread/6751160dc4c94657?hl=en ) UPDATED: ActionMan description. 2.4.0-beta1 "Migration" ========================== ADDED: Quickfilter section in basic-functions ADDED: MountMan option: Show only removable devices ADDED: option: Panel > Operation > Filter dialog remembers settings ADDED: action: Move Current Tab to Other Side ADDED: updated man page ADDED: support for xz archives CHANGED: User Interface > Panels > Folder History (history is saved now) CHANGED: New layout of Konfigurator General page. CHANGED: kgstartup screenshot to follow Konfigurator changes CHANGED: new Konfigurator page (Panel), items are moved according to the interface change up to the 2.3.0-beta1+ CHANGED: Update the addresses according to the Git move CHANGED: option: Panel > Status/Totalsbar > Show space information FIXED: Bugs #261307, #261311, #261358, #261361, #261371, #261375, #261379, #261382, #261383, #263493, #263500, #267546, #267695, #267708, #267718, #268210, #268234, #268236, #268239, #270257, #270648, #270650. FIXED: Bugs reported to kde-doc-english by Alexander Potashev 2.3.0-beta1 "New Horizons" ========================== 2.1.0-beta1 "Rusty Clutch" ================================== Date: 2009-10-?? ADDED: lister: fast text/hex viewer for huge filesizes ADDED: file regular expressions in quick search ADDED: queued packing / unpacking ADDED: lock tabs, close inactive tabs, close duplicated tabs ADDED: Trash icon in Main Toolbar and Tools menu ADDED: Trash icon in Main Toolbar UPDATED: Main Toolbar image: toolbar.png UPDATED: installation instructions afer SVN move from Sourceforge to KDE Extragear 2.0.0 "Mars Pathfinder" ================================== Date: 2009-04-11 UPDATED: Architecture: re-indexed the menu UPDATED: File change: OLD: credits.docbook NEW: credits-and-license.docbook UPDATED: File change: OLD: mouse.docbook NEW: mouse-commands.docbook UPDATED: File change: OLD: keyboard.docbook NEW: keyboard-commands.docbook UPDATED: File change: OLD: commands.docbook NEW: menu-commands.docbook UPDATED: File change: OLD: more.docbook NEW: advanced-functions.docbook UPDATED: File change: OLD: using-krusader.docbook NEW: basic-functions.docbook UPDATED: Alt+letter shortcuts UPDATED: FAQ, removed KDE3 issues and added KDE4 updates UPDATED: shred is not longer supported by Krusader2 - KDE4 REMOVED: All text ENTITIES in index.docbook so that tha handbook becomes 100% translatable REMOVED: Klik install procedure, Klik doens't offer Krusader anymore 2.0.0-beta2 "Space Odyssey" ================================== Date: 2008-12-27 ADDED: Manage Useractions: "Run in embedded terminal emulator" ADDED: Manage Useractions: added checkbox "enabled" ADDED: Root mode Krusader configuration, use eg. gksu instead of kdesu ADDED: Mac OS-X installation instructions for KDE4 2.0.0-beta1 "Phoenix Egg" ================================== Date: 2008-07-06 ADDED: Windows installation instructions for KDE4 ADDED: KDE4.x installation instructions ADDED: synchronizer_keybindings ADDED: compilation requirements for KDE4 ADDED: credits for Václav Jůza UPDATED: Handbook update from CVS krusader_kde3 to SVN krusader_kde4 at 18 january 2008 ADDED: Howto executing jar files (and not enter the jar archive)? ADDED: FAQ How don't add ".part" suffix when copying files via ftp? ADDED: FAQ Where is Konfigurator? UPDATED: Howto diplay the complete filename in the Name column (by hiding ext column) FIXED: workaround for DBLATEX 0.2.5-1, it doesn't accept "&" to display "&" in the tag, so i changed it to "and" FIXED: removed all tags inside , no additional tags needed inside <title>, it looks bad in HTML version (stylesheet) 1.90.0 "Power Stone" ================================== Date: 2008-03-15 Handbook 1.80.0 + Useractions explenations of the Power Stone release. These Useractions are not shipped in the 2.0.0 series. 1.80.0 "Final 3rd Stone" ================================== Date: 2007-07-21 ADDED: Terminal Emulator, paste with SHIFT+INSERT and CTRL+V ADDED: Vaclav's checksum patches (added sha* tools, fixed bugs etc...) Nothing to add in the docs i guess for this feature. ADDED: Synchronizer: ignore hidden files option ADDED: Synchronizer-results: drag [left], SHIFT+drag [right], Copy left/right selected items to clipboard ADDED: Locate-results: dragging items, copy to clipboard (CTRL+C) ADDED: Searcher-results: dragging items, copy to clipboard (CTRL+C) ADDED: Terminal Emulator keybindings in a separate section UPDATED: MacOS install instructions and fink repository, thanks to Catalin Hritcu UPDATED: screenshots UPDATED: make the Synchronizer chapter more readable and more undertandable UPDATED: Command Line / Terminal Emulator chapter UPDATED: FAQ, Sourceforge patch tracker tool UPDATED: keybindings UPDATED: old urls of old releases FIXED: removed all '_' signs in the entities for the openjade parser 1.80.0-beta2 "Last Unstable Stone" ================================== Date: 2007-03-31 ADDED: Support for useraction placeholders in Krusader's commandline ADDED: New default user action "Backup current" ADDED: ALT+C as default shortcut for compare directories ADDED: GUI for configuring the atomic extensions in Konfigurator ADDED: quotation mark handling at search (ex. "Program Files") ---------------------------------------------------- Other todo items not related to Krusader's changelog: TODO: complete Keyboard Usage TODO: complete glossary TODO: complete Mouse Usage TODO: selection modes http://krusader.sourceforge.net/phpBB/viewtopic.php?p=8255#8255 ---------------------------------------------------- ADDED: Remote LAN Connections (zeroconf) ADDED: NewsLetter Forum ADDED: Quickstart Installation Tutorial ADDED: FAQ: What todo if an extenal tool doesn't seem to work? ADDED: FAQ: What todo if the KDEcrashhandler sends no usefull backtrace information? ADDED: FAQ: How can i send good debug or crash reports? ADDED: Brief view Documentation updates by the Technical Communication team of 2007, University of Oulu, Finland http://www.oulu.fi/english/ under the lead of Minna Hekanaho ADDED: FAQ: Does krusader supports the FXP protocol? ADDED: webdav and nfs url ADDED: FAQ: How can I set the look & Feel of 2 different users equal? REMOVED: Outdated and unused Italian handbook translation 1.80.0-beta1 "The Last Krusade" =============================== Date: 2007-01-07 ADDED: full support for ACL permissions (properties, preserve attrs, synchronizer) ADDED: actionman.png screenshot ADDED: i18n scripts update_docbook, update_pot, update_po They only should be used by the doc 18n coordinator Wrong usage of this script might result in outdated documentation files ADDED: Russian Handbook (translation is work in progress) thanks to Roman Batejkin ADDED: TerminalEmulator: Ctrl+F switches between full-widget TE, normal TE (thanks to Vaclav Juza) ADDED: Ctrl+Up from panel focuses the origin editbox, Ctrl+Down from origin editbox focuses the panel (thanks to Vaclav Juza) ADDED: TerminalEmulator: Ctrl+Shift+Up/Down always focus/unfocus TE independently whether the command line is shown or not ADDED: TerminalEmulator: if the command line is hidden, TE receives Ctrl+Up / Ctrl+Down (thanks to Vaclav Juza) ADDED: synchronizer: double click on a file calls the diff utility (kompare) ADDED: atomic extensions (see CVSNEWS) ADDED: renaming of just the filename, without extension ADDED: full screen terminal window (mc-style) ADDED: keeping the directory structures for virt folders at copy/move ADDED: synchronizer, parallel threads for slow FTP servers ADDED: Better quick navigation: first move mouse over subdir, then press ctrl + left mouse button (patch by Jiri Palecek) ------------- Docbook file splitting Design changes ------------------- UPDATED: split up krusader-tools.docbook in smaller files UPDATED: split up using-krusader.docbook in smaller files ADDED: more.docbook (formerly part of using-krusader.docbook) ADDED: diskusage.docbook (formerly part of krusader-tools.docbook) ADDED: java.docbook (formerly part of krusader-tools.docbook) ADDED: viewer-editor.docbook (formerly part of krusader-tools.docbook) ADDED: locate.docbook (formerly part of krusader-tools.docbook) ADDED: search.docbook (formerly part of krusader-tools.docbook) ADDED: bookmarks.docbook (formerly part of krusader-tools.docbook) ADDED: mount.docbook (formerly part of krusader-tools.docbook) ADDED: remote-connections.docbook (formerly part of krusader-tools.docbook) ADDED: archives.docbook (formerly part of using-krusader.docbook) ADDED: checksum.docbook (formerly part of using-krusader.docbook) ADDED: occupied-space.docbook (formerly part of using-krusader.docbook) ADDED: compare.docbook (formerly part of using-krusader.docbook) ADDED: splitter.docbook (formerly part of using-krusader.docbook) ADDED: vfs.docbook (formerly part of using-krusader.docbook) ADDED: profiles.docbook (formerly part of using-krusader.docbook) ADDED: useractions.docbook (formerly part of krusader-tools.docbook) ADDED: Mouse Commands, mouse.docbook (formerly part of using-krusader.docbook) ADDED: Keyboard Commands, keyboard.docbook (formerly part of using-krusader.docbook) ADDED: abc-index by using <indexterm> ADDED: List of Figures (index) <screenshot> -> <figure> ADDED: List of Tables (index) <informaltable> -> <table> ADDED: release-overview.docbook (formerly part of installation.docbook) ADDED: useraction-xml.docbook (formerly part of installation.docbook) ADDED: configuration-files.docbook (formerly part of installation.docbook) ADDED: help.docbook (formerly part of index.docbook) ADDED: editorsnote.docbook (formerly part of index.docbook) ADDED: features.docbook (formerly part of introduction.docbook) ADDED: glossary.docbook ---------------------------------------------------------- ADDED: ActionMan for useraction configuration ADDED: single instance mode (Konfigurator Startup) ADDED: start to system tray (Konfigurator Startup) ADDED: right click menu for bookmarks (context menu) ADDED: enable/disable special bookmarks by right clicking on them ADDED: an option for directories to be always sorted by name (Konfigurator L&F) ADDED: FAQ: Why "save last location" doesn't work? ADDED: Inactive panel color dimming ADDED: FAQ: How can I send a patch? ADDED: FAQ: Why does krusader-cvs shows an old version number in the about box? ADDED: kioslaves: trash:/ and ipod:/ ADDED: Subversion checkout ADDED: Profiles chapter ADDED: Media button, Ctrl+M, Ctrl+Shift+Left, Ctrl+Shift+Right UPDATED: Rename 'mark' to 'select' UPDATED: checksum creation/verification mechanism UPDATED: Command Reference -> Menu Commands UPDATED: moved the "Foreword" from index.docbbook to introduction.docbook UPDATED: Shortcut- and Toolbardialogs are removed from Konfigurator UPDATED: Heavily extended and reordered menubar, Updated commands.docbook (thanks to Dan Price) UPDATED: UserActions examples in the documentation appendix UPDATED: UserActions are now managed with ActionMan. In Konfigurator you can change settings _about_ useractions. UPDATED: Shortcuts are now exported in as plaintext, legacy import still works. UPDATED: Konfigurator UPDATED: Konfigurator: MouseMode got now it's own Tab in Look&Feel UPDATED: Bookman and passwords UPDATED: Copy/Move: preserve all attributes (time, owner, group) UPDATED: New cvs checkout url cvs.sourceforge -> krusader.cvs.sourceforge UPDATED: FAQ UPDATED: Command Reference UPDATED: Marking (Selecting) files and directories UPDATED: Virtual file systems (VFS) UPDATED: Archives UPDATED: Features list rewritten to make it more clear FIXED: KruSearcher 'ftp' group -> 'users', thanks to Roman Batejkin REMOVED: remoteman.png screenshot 1.70.0 "Round Robin" ==================== Date: 2006-01-23 ADDED: Help: Upload your extensions/plugins at kde.files.org ADDED: Help: Spread the Word Krusader ADDED: FAQ: Crashes in Krusader caused by Qt 3.3.5 ADDED: Newsfeeds ADDED: Krusader users mailinglist ADDED: Mouse Gestures ADDED: Ctrl+Alt+T to show/hide the terminal emulator UPDATED: F10 -> Ctrl+Q : Quit viewer/editor UPDATED: Ctrl+D -> Ctrl+Shift+B : Detach Tab UPDATED: Ctrl+E -> Ctrl+Shift+E : Text Viewer UPDATED: Ctrl+H -> Ctrl+Shift+H : Hex Viewer UPDATED: Ctrl+G -> Ctrl+Shift+G : Generic Viewer UPDATED: Ctrl+Alt+C -> Ctrl+W : Close Tab (panel) UPDATED: Keybindings (major update and clean up) FIXED: Proofread and fixed spelling, etc. - Thanks to Richard Holt 1.70.0-beta2 "Afterburner" ========================== Date: 2005-11-05 ADDED: New logo, thanks to Andrew Neupokoev (nwmod) ADDED: FAQ Why do i have some trouble with the media:// protocol? ADDED: FAQ How can i close a remote connection (⪚ a FTP connection) ? ADDED: Alt+Enter keybinding, File -> Properties ADDED: you can turn off sending CDs to the terminal emulator (general tab) ADDED: our own content category on kde-files.org ADDED: useraction: View placeholder ADDED: klik protocol ADDED: useraction: ColSort placeholder ADDED: FAQ Why krusader-1.60.0 does not compile with gcc4? screenshots: import -depth 8 -dither -delay 2000 -colors 128 -resize 60% -frame filename.png pngcrush --brute filename.png ./crush/filename.png 1.70.0-beta1 "Hellfire" ======================= Date: 2005-09-27 ADDED: JavaScript interface ADDED: Quick Navigation in the Location Toolbar ADDED: checksum creation/verification mechanism ADDED: ctrl-alt-s creates a new symlink ADDED: ctrl-h opens history on the active panel ADDED: 1.70.0 (Hellfire) ADDED: appendix: release overview ADDED: FAQ, Why does the handbook not work? ADDED: MacOS-X port installation instructions ADDED: Column Headers can be changed and saved individually to each panel ADDED: Commands -> Select Remote Charset ADDED: credit for Matej Urbancic, Marketing & Product Research ADDED: Accept URL's from clipboard through middle click ADDED: permissions column as octal numbers ADDED: clear-location-bar button, konfigurator->look'n'feel ADDED: calculate space on remote filesystems ADDED: when custom filter is set, the Totals label will show the filter. example: [*.cpp] ADDED: Open the current folder in a new tab + ctrl-alt-enter keybinding ADDED: Bookmarks as action buttons on the Toolbar, thanks Googie and Shie ADDED: FAQ, Is there a Windows version? ADDED: FAQ, Is there a MacOS X version? ADDED: preserve date for local targets at copy / move ADDED: new ./configure-switches: --without-konqueror and --without-javascript ADDED: Keyboard Usage ADDED: PopUp Panel (3rd Hand) -> Viewer Panel -> is a "Thumbnail viewer" on a folder ADDED: credits for Brazilian Portuguese translation for Doutor Zero ADDED: credits for Krusader packagers ADDED: A Safari-like Jump-Back feature (Ctrl-J and in the bookmark-menu) This feature is inspired by the Snap-Back feature of Apple's webbrowser Safari ADDED: i18n help (Help Krusader) UPDATED: Distro's who include distro urls UPDATED: Remote connections UPDATED: Bookman: in kde 3.4, devices:/ is now media:/ UPDATED: new i18n page url UPDATED: mailing lists UPDATED: installation $ find /usr /opt -name qtconfig -type f 2>/dev/null $ find /usr /opt -name kdeinit -type f 2>/dev/null thanks Dirk UPDATED: Commands, Settings -> Save Position UPDATED: kgstartup.png used $ import ... -resize 60% and $ pngcrush UPDATED: Konfigurator startup page UPDATED: FAQ, Why have i trouble with my FTP connection? thanks to Peter J. [ pecko {*} pecko {.} sk] at http://www.pecko.sk UPDATED: How to obtain Krusader UPDATED: changed locate-gui shortcut from ctrl-l to ctrl+shift+l FIXED: Some manpage issues, thanks S�ke Dibbern REMOVED: RemoteMan, the FTP/SMB connection manager RemoteMan has been replaced by our new bookmark manager since Krusader 1.25-beta1 RemoteMan is disabled since Krusader-1.60.0 REMOVED: remoteman.png (NOT YET DONE IN CVS, TODO) REMOVED: Ctrl+C: Commands -> Net Connections (RemoteMan) REMOVED: Ctrl+C+N Disconnect From Net (RemoteMan) 1.60.0 ====================== Date: 2005-04-15 Final handbook revision for "Krusader 1.60.0 stable" ADDED: credit for Sven Opitz, for the first donation ADDED: credit for http://usefularts.org/ ADDED: FAQ Why mimetype magic isn't sometimes working inside archives? ADDED: credit for Gabor Lehel (illissius) ADDED: FAQ Why does &krusader; freezes on a dead mountpoint? ADDED: Help Krusader: Maintainer for porting Krusader to Windows ADDED: Help Krusader: Maintainer for porting Krusader to MacOS X ADDED: Help Krusader: UserActions ADDED: Version scheme (installation.docbook) ADDED: ACE archive note (konfigurator.docbook) ADDED: Custom Selection Mode ADDED: useraction: new placeholder: %_ListFile()% ADDED: Ctrl+z (popular url's) ADDED: useraction placeholder %_Script(path/to/script.js)% ADDED: kguseractions.png and kgprotocols.png for the HTML/RTF/PDF version ADDED: Useractions menu entry ADDED: credit for Terry "Fudoki" Wilkinson, documentation ADDED: JavaScript console (incomplete description) ADDED: Remote-man FAQ, url Bookmark transfer procedure ADDED: Remote Connections ADDED: Bookmarks Password handling ADDED: Bookmarks can be placed into the Main Toolbar and the Actions Toolbars ADDED: Popular urls in Folder History ADDED: Ctrl+Alt+j keybinding for the JavaScript console ADDED: Help Krusader ADDED: Actions Toolbar ADDED: color scheme export/import ADDED: searcher, feed to listbox (with virtual folders) ADDED: useraction placeholder %_ask(..)% ADDED: PanelSize placeholder %_PanelSize% %aPanelSize("80")% ADDED: show/hide listpanel Columns by right clicking the Column Header ADDED: Disk Usage, Alt+D ADDED: Useraction placeholders %_Each% and %_Move(src, dest)% ADDED: PopUp Panel has now a Full Viewer ADDED: Shift+DEL will delete a file permanently ADDED: inport/export keybindings (konfigurator, look & feel) ADDED: kio_krarc.* "Protocol not supported by Krusader" (FAQ) ADDED: krusader-devel-ro mailing list ADDED: Ctrl+O keybinding ADDED: This handbook is available in several formats (HTML, TXT, RTF, PDF) ADDED: resize to a small size even with Fn keys showing (FAQ) ADDED: vertical-horizontal list panel, Alt+Ctrl+v ADDED: Ctrl+Up Arrow (from the panel) goes up to the Location Toolbar ADDED: New commandline option: --profile <panel-profile> ADDED: UserAction Forum (faq.docbook), thanks Dirk ADDED: 64 bit FAQ (faq.docbook), thanks Marc on our forum http://krusader.sourceforge.net/phpBB/viewtopic.php?t=951 UPDATED: Krusader KDE version Requirements UPDATED: DTD DocBook XML V4.2-Based Variant V1.1 (V4.1.2 was the previous version) UPDATED: Synchronizer, Thanks Csaba UPDATED: UserMenu usage UPDATED: UserActions description UPDATED: krusader1.png, kgstartup.png, mountman.png, search_general.png, search_advanced.png, syncdir.png, bookmanadd.png, bookmanedit.png all screenshots in "plastic' theme (the default kde 3.4 theme), made with Imagemagic $ import -depth 8 -dither -delay 2000 -colors 128 -resize 70% -frame search_advanced.png except bookmanadd.png with KSnapshot UPDATED: first Krusader-Tools and then Konfigurator (reversed the order) UPDATED: mark (obsolete) -> select UPDATED: date format mm/dd/yyyy -> yyyy/mm/dd UPDATED: Introduction and features separated into a new chapter UPDATED: Foreword, thanks to Terry "Fudoki" Wilkinson UPDATED: Toolbar -> Main Toolbar (due to the Actions Toolbar) UPDATED: remoteman was disabled. from now on, Bookmark Manager only UPDATED: Commands - New Net Connection: FTP, SMB, FISH or SFTP connection UPDATED: mouse selection mode UPDATED: Function (FN) Keys Bar - keybindings are now configurable UPDATED: Amarok useraction, thanks Dirk (installation.docbook) FIXED: Proofread and fixed spelling, etc. - Thanks to Terry "Fudoki" Wilkinson 1.51.00 ====================== Date: 2004-11-28 Richard Holt is now an official member of the documentation team. Welcome aboard Richard! FIXED: many typos fixed - Thanks to Richard Holt 1.50.04 ====================== Date: 2004-11-19 FIXED: Proofread and fixed spelling etc. - Thanks to Richard Holt FIXED: uncommented <?xml version="1.0" ?> in index.docbook FIXED: removed some acronym elements, the jade parser does not like them FIXED: <imagedata fileref="foo.eps" ...> -> foo.png REMOVED: bookmanuse.png not used anymore since hanbook 1.00.02 ADDED: useraction: Parameter-description for the placeholder 1.50.03 ====================== Date: 2004-11-04 FIXED: doc/pics/Makefile.am did not remove krusader_title.png & tabbed_browsing.png when running 'make uninstall' ADDED: syncdir.png REMOVED: kglookfeel.png kggeneral.png kgadvanced.png kgarchives.png in cvs but not in the html documentation ADDED: FAQ: Does Krusader need KDE? UPDATED: required KDElib versions UPDATED: User Actions, thanks for the feedback Jonas Bähr FIXED: Proofread and fixed spelling, etc. - Thanks to Mark Eatough UPDATED-FIXED: many small issues 1.50.02 ====================== Date: 2004-10-25 ADDED: useraction.xml ADDED: FAQ Nvdia/libGLcore.so.1 compile problem, Thanks Falo and Rafi UPDATED-FIXED: many small issues 1.50.01 CVS ====================== Date: 2004-10-08 ADDED: MacOS-X port, Thanks Jonas ADDED: Compare Directories, Thanks Csaba ADDED: Konfigurator: arj, lha, kget ADDED: Konfigurator: protocols, Thanks Csaba ADDED: Faster navigation in bookmarks, Thanks Shie ADDED: FAQ How can i disable the default sounds, Thanks thepieman UPDATED: Synchronizer, Thanks Csaba UPDATED: Usermenu - Useractions, Thanks Jonas UPDATED: New TODO forum and NEWS forum UPDATED-FIXED: many small issues 1.50.00 CVS ====================== Date: 2004-08-15 ADDED: Synchronizer: multiple include/exclude filter example ADDED: Dropping URL's onto the status bar / totals line, Thanks Csaba ADDED: FAQ IRC channel ADDED: FAQ Debian Qt issue, Thanks Eugen Albiker ADDED: Sync-browse mode, Thanks Jonas ADDED: Usermenu, Thanks Jonas ADDED: 3rd hand of krusader, Thanks Shie REMOVED: Tree Panel, Quick View Panel -> is now "3rd hand of krusader" REMOVED: <informalexample> docbook entity in installation.sgml (gives a double console rectangle in cobination with <screen> under KDE3.2) UPDATED-FIXED: many small issues 1.40.02 ====================== Date: 2004-07-21 Final handbook revision for "Krusader 1.40 stable" ADDED: Krusader Handbook logo for the HTML version UPDATED: Konfigurator UPDATED: Credits UPDATED: KIOSlave UPDATED: Screenshots UPDATED: some obsolete issues UPDATED: Origin Button -> Location Toolbar UPDATED: usage of more default KDE Docbook entities, often located in /usr/share/apps/ksgmltools2/customization/en/ /usr/share/apps/ksgmltools2/customization/entities/ UPDATED-FIXED: many small issues 1.40.01 Date: 2004-05-17 UPDATED: RPM FAQ ADDED: FAQ How can i translate Krusader to my native language? UPDATED-FIXED: many small issues 1.40.00 ====================== Date: 2004-04-22 FIXED: Proof read and fixed spelling etc. - Thanks to Mark Eatough 1.40.00-beta1 Date: 2004-03-29 ADDED: configuring the colors of the panel - Thanks to Heiner Eichmann ADDED: Quickmode for MountMan - Thanks to Shie Erlich UPDATED: Konfigurator screenschots 1.31.01 Date: 2004-03-04 ADDED: locate (using-krusader.sgml) - Thanks to Karai Csaba ADDED: Right click menu (using-krusader.sgml) UPDATED: FAQ's "krusaderui.rc" file issue, - Thanks to Karai Csaba UPDATED-FIXED: many small issues 1.31.00 ====================== Date: 2004-02-12 From now on the <releaseinfo> tag always matches the Krusader version number that is described in the documentation, e.g., "Krusader Handbook version 1.31.xx" describes "Krusader version 1.31" ADDED: New Quicksearch (using-krusader.sgml) - Thanks to Heiner Eichmann ADDED: Folder history (using-krusader.sgml) - Thanks to Hans Loffler ADDED: appendix: configuration files (installation.sgml) UPDATED: New Konfigurator (konfigurator.sgml) - Thanks to Karai Csaba UPDATED: I try to follow the guidelines in "The KDE DocBook Authors guide" but sometimes I don't do it. ;-) UPDATED: FAQ's (faq.sgml) UPDATED: Calculate occupied space (using-krusader.sgml) - Thanks to Heiner Eichmann UPDATED: Krviewer (krusader-tools.sgml) UPDATED: new package description - Thanks to Jonas Bähr UPDATED-FIXED: many small issues Date: 01.02.2004 FIXED: Proofread and fixed spelling, etc. - Thanks to Mark Eatough Date: 06.01.2004 ADDED: User Menu (commands.sgml) - Thanks to Shie Erlich UPDATED: manpage (krusader.1) UPDATED: directory synchronisation (moved to krusader-tools.sgml) - Thanks to Karai Csaba UPDATED: From: DocBook XML V4.1-Based Variant V1.0//EN To: DocBook XML V4.1.2-Based Variant V1.1//EN 1.00.05 ====================== Date: 2003-12-21 FIXED: added package entity for compilation under KDE3.2-beta2 (index.docbook) ADDED: file splitter (using-krusader.sgml) ADDED: directory synchronisation (using-krusader.sgml) UPDATED: Commands Reference (commands.sgml) UPDATED: install procedure (installation.sgml) UPDATED: Questions and Answers (faq.sgml) UPDATED: many small issues FIXED: many small issues FIXED: spelling mistakes/typos corrections proofreading, thanks to Mark Eatough 1.00.04 ====================== Date: 2003-11-26 UPDATED: Konfigurator (konfigurator.sgml) UPDATED: KruSearcher (krusader-tools.sgml) UPDATED: Questions and Answers (faq.sgml) krarc slave issue Thanks to Karai Csaba ADDED: Key Bindings (using-krusader.sgml) ADDED: Starting Krusader (installation.sgml) ADDED: Note from the Editors (installation.sgml) FIXED: spelling mistakes/typos corrections proofreading, thanks to Mark Eatough 1.00.03 ====================== Date: 2003-11-15 ADDED: Krviewer (krusader-tools.sgml), thanks to Rafi Yanai 1.00.02 ====================== Date: 2003-10-23 KRUSADER MANPAGE: ADDED: ~/.kde/share/apps/krusader/krbookmarks.xml UPDATED: cmdline.png, fnkeys.png, krusader1.png, listpanel.png mainwindow.png, terminalEmu.png, toolbar.png (using-krusader.sgml) UPDATED: BookMan, bookmanadd.png, bookmanedit.png (krusader-tools.sgml) REMOVED: bookmanuse.png (using-krusader.sgml) [actually, not till 1.50.04 :] UPDATED: Note: RemoteMan wil be removed (krusader-tools.sgml) ADDED: tabbed browsing, tabbed_browsing.png (using-krusader.sgml) UPDATED: Tree Panel, Quick View Panel, Note: temporarily disabled since Krusader 1.12-beta1 --will be rewritten, sorry. small issues, Compare mode (using-krusader.sgml) UPDATED: Chapter 3. Command Reference (commands.sgml) ADDED: Questions and Answers (faq.sgml) Samba codepage issue Thanks to Karai Csaba ADDED: krusader_title.png (introduction.sgml) UPDATED: Introduction (introduction.sgml) Krename, Bookmark, Tabbed Browsing, Root mode, screenshot krusader1.png 1.00.01 ====================== Date: 2003-10-05 UPDATED: installation (installation.sgml) UPDATED: Frequently Asked Questions and Answers (faq.sgml) UPDATED: Credits and License (credits.sgml) ADDED: NOTE: We are busy with updating the The Krusader Handbook. (index.docbook) UPDATED: small issues, eg., KDE2.x -> 3.x (index.docbook) The Krusader Handbook is now continued and maintained by Frank Schoolmeesters. 1.00.00 ================== Date: 2002-01-01 Initial version Written by Shie Erlich and Rafi Yanai. diff --git a/krusader/DiskUsage/filelightParts/fileTree.h b/krusader/DiskUsage/filelightParts/fileTree.h index 34650024..18fe3afa 100644 --- a/krusader/DiskUsage/filelightParts/fileTree.h +++ b/krusader/DiskUsage/filelightParts/fileTree.h @@ -1,385 +1,385 @@ /***************************************************************************** * Copyright (C) 2004 Max Howell <max.howell@methylblue.com> * * Copyright (C) 2004-2020 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #ifndef FILETREE_H #define FILETREE_H #include <QString> #include <KIO/Global> #include <time.h> #include <stdlib.h> #include <unistd.h> // TODO these are pointlessly general purpose now, make them incredibly specific typedef KIO::filesize_t FileSize; template <class T> class Iterator; template <class T> class ConstIterator; template <class T> class Chain; template <class T> class Link { public: explicit Link(T* const t) : prev(this), next(this), data(t) {} Link() : prev(this), next(this), data(0) {} //TODO unlinking is slow and you don't use it very much in this context. // ** Perhaps you can make a faster deletion system that doesn't bother tidying up first // ** and then you MUST call some kind of detach() function when you remove elements otherwise ~Link() { delete data; unlink(); } friend class Iterator<T>; friend class ConstIterator<T>; friend class Chain<T>; private: void unlink() { prev->next = next; next->prev = prev; prev = next = this; } Link<T>* prev; Link<T>* next; T* data; //ensure only iterators have access to this }; template <class T> class Iterator { public: Iterator() : link(0) { } //**** remove this, remove this REMOVE THIS!!! dangerous as your implementation doesn't test for null links, always assumes they can be dereferenced explicit Iterator(Link<T> *p) : link(p) { } bool operator==(const Iterator<T>& it) const { return link == it.link; } bool operator!=(const Iterator<T>& it) const { return link != it.link; } bool operator!=(const Link<T> *p) const { return p != link; } //here we have a choice, really I should make two classes one const the other not const T* operator*() const { return link->data; } T* operator*() { return link->data; } Iterator<T>& operator++() { link = link->next; return *this; } //**** does it waste time returning in places where we don't use the retval? bool isNull() const { return (link == 0); } //REMOVE WITH ABOVE REMOVAL you don't want null iterators to be possible void transferTo(Chain<T> &chain) { chain.append(remove()); } T* remove() { //remove from list, delete Link, data is returned NOT deleted T* const d = link->data; Link<T>* const p = link->prev; link->data = 0; delete link; link = p; //make iterator point to previous element, YOU must check this points to an element return d; } private: Link<T> *link; }; template <class T> class ConstIterator { public: explicit ConstIterator(Link<T> *p) : link(p) { } bool operator==(const Iterator<T>& it) const { return link == it.link; } bool operator!=(const Iterator<T>& it) const { return link != it.link; } bool operator!=(const Link<T> *p) const { return p != link; } const T* operator*() const { return link->data; } ConstIterator<T>& operator++() { link = link->next; return *this; } private: const Link<T> *link; }; //**** try to make a generic list class and then a brief full list template that inlines // thus reducing code bloat template <class T> class Chain { public: Chain() { } virtual ~Chain() { empty(); } void append(T* const data) { Link<T>* const link = new Link<T>(data); link->prev = head.prev; link->next = &head; head.prev->next = link; head.prev = link; } void transferTo(Chain &c) { if (isEmpty()) return; Link<T>* const first = head.next; Link<T>* const last = head.prev; head.unlink(); first->prev = c.head.prev; c.head.prev->next = first; last->next = &c.head; c.head.prev = last; } void empty() { while (head.next != &head) { delete head.next; } } Iterator<T> iterator() const { return Iterator<T>(head.next); } ConstIterator<T> constIterator() const { return ConstIterator<T>(head.next); } const Link<T> *end() const { return &head; } bool isEmpty() const { return (head.next == &head); } private: Link<T> head; void operator=(const Chain&) {} }; class Directory; class File { protected: - Directory *m_parent; //0 if this is treeRoot + Directory *m_parent; // 0 if this is treeRoot QString m_name; //< file name QString m_directory;//< the directory of the file FileSize m_size; //< size with subdirectories FileSize m_ownSize; //< size without subdirectories mode_t m_mode; //< file mode QString m_owner; //< file owner name QString m_group; //< file group name QString m_perm; //< file permissions string time_t m_time; //< file modification in time_t format bool m_symLink; //< true if the file is a symlink QString m_mimeType; //< file mimetype bool m_excluded; //< flag if the file is excluded from du int m_percent; //< percent flag public: File(Directory *parentIn, const QString &nameIn, const QString &dir, FileSize sizeIn, mode_t modeIn, const QString &ownerIn, const QString &groupIn, const QString &permIn, time_t timeIn, bool symLinkIn, const QString &mimeTypeIn) : m_parent(parentIn), m_name(nameIn), m_directory(dir), m_size(sizeIn), m_ownSize(sizeIn), m_mode(modeIn), m_owner(ownerIn), m_group(groupIn), m_perm(permIn), m_time(timeIn), m_symLink(symLinkIn), m_mimeType(mimeTypeIn), m_excluded(false), m_percent(-1) {} File(const QString &nameIn, FileSize sizeIn) : m_parent(0), m_name(nameIn), m_directory(QString()), m_size(sizeIn), m_ownSize(sizeIn), m_mode(0), m_owner(QString()), m_group(QString()), m_perm(QString()), m_time(-1), m_symLink(false), m_mimeType(QString()), m_excluded(false), m_percent(-1) { } virtual ~File() {} inline const QString & name() const { return m_name; } inline const QString & directory() const { return m_directory; } inline FileSize size() const { return m_excluded ? 0 : m_size; } inline FileSize ownSize() const { return m_excluded ? 0 : m_ownSize; } inline mode_t mode() const { return m_mode; } inline const QString & owner() const { return m_owner; } inline const QString & group() const { return m_group; } inline const QString & perm() const { return m_perm; } inline time_t time() const { return m_time; } inline const QString & mime() const { return m_mimeType; } inline bool isSymLink() const { return m_symLink; } virtual bool isDir() const { return false; } inline bool isExcluded() const { return m_excluded; } inline void exclude(bool flag) { m_excluded = flag; } inline int intPercent() const { return m_percent; } inline const QString percent() const { if (m_percent < 0) return "INV"; QString buf; buf.asprintf("%d.%02d%%", m_percent / 100, m_percent % 100); return buf; } inline void setPercent(int p) { m_percent = p; } inline const Directory* parent() const { return m_parent; } inline void setSizes(KIO::filesize_t totalSize, KIO::filesize_t ownSize) { m_ownSize = ownSize; m_size = totalSize; } enum UnitPrefix { kilo, mega, giga, tera }; static const FileSize DENOMINATOR[4]; static const char PREFIX[5][2]; QString fullPath(const Directory* = 0) const; QString humanReadableSize(UnitPrefix key = mega) const; static QString humanReadableSize(FileSize size, UnitPrefix Key = mega); friend class Directory; }; //TODO when you modify this to take into account hardlinks you should make the Chain layered not inherited class Directory : public Chain<File>, public File { public: Directory(Directory *parentIn, const QString &nameIn, const QString &dir, FileSize sizeIn, mode_t modeIn, const QString &ownerIn, const QString &groupIn, const QString &permIn, time_t timeIn, bool symLinkIn, const QString &mimeTypeIn) : File(parentIn, nameIn, dir, sizeIn, modeIn, ownerIn, groupIn, permIn, timeIn, symLinkIn, mimeTypeIn), m_fileCount(0) {} Directory(const QString &name, QString url) : File(name, 0), m_fileCount(0) { m_directory = url; } virtual ~Directory() {} virtual bool isDir() const override { return true; } void append(File *p) { ++m_fileCount; Directory *parent = m_parent; while (parent) { parent->m_fileCount++; parent = parent->m_parent; } Chain<File>::append(p); p->m_parent = this; } void remove(File *p) { for (Iterator<File> it = Chain<File>::iterator(); it != Chain<File>::end(); ++it) if ((*it) == p) { --m_fileCount; Directory *parent = m_parent; while (parent) { parent->m_fileCount--; parent = parent->m_parent; } it.remove(); break; } } uint fileCount() const { return m_fileCount; } private: Directory(const Directory&); void operator=(const Directory&); uint m_fileCount; }; #endif diff --git a/krusader/DiskUsage/radialMap/labels.cpp b/krusader/DiskUsage/radialMap/labels.cpp index fe6f1f45..33407b40 100644 --- a/krusader/DiskUsage/radialMap/labels.cpp +++ b/krusader/DiskUsage/radialMap/labels.cpp @@ -1,367 +1,367 @@ /***************************************************************************** * Copyright (C) 2003-2004 Max Howell <max.howell@methylblue.com> * * Copyright (C) 2004-2020 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ // QtCore #include <QList> // QtGui #include <QFont> #include <QFontMetrics> #include <QPainter> #include <KCoreAddons/KStringHandler> #include "Config.h" #include "fileTree.h" #include "radialMap.h" #include "sincos.h" #include "widget.h" #include "../compat.h" namespace RadialMap { struct Label { Label(const RadialMap::Segment *s, int l) : segment(s), lvl(l), a(segment->start() + (segment->length() / 2)) { } bool tooClose(const int &aa) const { return (a > aa - LABEL_ANGLE_MARGIN && a < aa + LABEL_ANGLE_MARGIN); } const RadialMap::Segment *segment; const unsigned int lvl; const int a; int x1, y1, x2, y2, x3; int tx, ty; QString qs; }; class LabelList : public QList<Label *> { public: ~LabelList() { QListIterator<Label *> it(*this); while (it.hasNext()) delete it.next(); } void inSort(Label * label1) { for (QList<Label *>::iterator it(begin()); it != end(); ++it) { Label * label2 = *it; bool ins = false; //you add 1440 to work round the fact that later you want the circle split vertically //and as it is you start at 3 o' clock. It's to do with rightPrevY, stops annoying bug int a1 = label1->a + 1440; int a2 = label2->a + 1440; if (a1 == a2) ins = true; if (a1 > 5760) a1 -= 5760; if (a2 > 5760) a2 -= 5760; if (a1 < a2) ins = true; if (ins) { insert(it, label1); return; } } append(label1); } }; } void RadialMap::Widget::paintExplodedLabels(QPainter &paint) const { //we are a friend of RadialMap::Map LabelList list; unsigned int startLevel = 0; - //1. Create list of labels sorted in the order they will be rendered + // 1. Create list of labels sorted in the order they will be rendered if (m_focus != nullptr && m_focus->file() != m_tree) { //separate behavior for selected vs unselected segments //don't bother with files if (m_focus->file() == nullptr || !m_focus->file()->isDir()) return; //find the range of levels we will be potentially drawing labels for for (const auto *p = dynamic_cast<const Directory *>(m_focus->file()); p != m_tree; ++startLevel) { //startLevel is the level above whatever m_focus is in p = p->parent(); } //range=2 means 2 levels to draw labels for unsigned int a1, a2, minAngle; a1 = m_focus->start(); a2 = m_focus->end(); // boundary angles minAngle = int(m_focus->length() * LABEL_MIN_ANGLE_FACTOR); #define segment (*it) #define ring (m_map.m_signature + i) //**** Levels should be on a scale starting with 0 //**** range is a useless parameter //**** keep a topblock var which is the lowestLevel OR startLevel for indentation purposes for (unsigned int i = startLevel; i <= m_map.m_visibleDepth; ++i) { for (Iterator<Segment> it = ring->iterator(); it != ring->end(); ++it) if (segment->start() >= a1 && segment->end() <= a2) if (segment->length() > minAngle) list.inSort(new Label(segment, i)); } #undef ring #undef segment } else { #define ring m_map.m_signature for (Iterator<Segment> it = ring->iterator(); it != ring->end(); ++it) if ((*it)->length() > 288) list.inSort(new Label((*it), 0)); #undef ring } - //2. Check to see if any adjacent labels are too close together + // 2. Check to see if any adjacent labels are too close together // if so, remove the least significant labels int itn = 0; int jtn = 1; while (jtn < list.count()) { //this method is fairly efficient if (list[ itn ]->tooClose(list[ jtn ]->a)) { if (list[ itn ]->lvl > list[ jtn ]->lvl) { delete list[ itn ]; list.removeAt(itn); jtn--; itn = jtn; } else { delete list[ jtn ]; list.removeAt(jtn); } } else ++itn; jtn = itn; ++jtn; } LabelList::iterator it = list.begin(); //used in next two steps bool varySizes; //**** should perhaps use doubles auto *sizes = new int [ m_map.m_visibleDepth + 1 ]; //**** make sizes an array of floats I think instead (or doubles) do { - //3. Calculate font sizes + // 3. Calculate font sizes { //determine current range of levels to draw for unsigned int range = 0; for (it = list.begin(); it != list.end(); ++it) { unsigned int lvl = (*it)->lvl; if (lvl > range) range = lvl; //**** better way would just be to assign if nothing is range } range -= startLevel; //range 0 means 1 level of labels varySizes = Config::varyLabelFontSizes && (range != 0); if (varySizes) { //create an array of font sizes for various levels //will exceed normal font pitch automatically if necessary, but not minPitch //**** this needs to be checked lots //**** what if this is negative (min size gtr than default size) unsigned int step = (paint.font().pointSize() - Config::minFontPitch) / range; if (step == 0) step = 1; for (unsigned int x = range + startLevel, y = Config::minFontPitch; x >= startLevel; y += step, --x) { sizes[x] = y; } } } - //4. determine label co-ordinates + // 4. determine label co-ordinates int x1, y1, x2, y2, x3, tx, ty; //coords double sinra, cosra, ra; //angles int cx = m_map.width() / 2 + m_offset.x(); //centre relative to canvas int cy = m_map.height() / 2 + m_offset.y(); int spacer, preSpacer = int(m_map.m_ringBreadth * 0.5) + m_map.m_innerRadius; int fullStrutLength = (m_map.width() - m_map.MAP_2MARGIN) / 2 + LABEL_MAP_SPACER; //full length of a strut from map center int prevLeftY = 0; int prevRightY = height(); bool rightSide; QFont font; for (it = list.begin(); it != list.end(); ++it) { //** bear in mind that text is drawn with QPoint param as BOTTOM left corner of text box if (varySizes) font.setPointSize(sizes[(*it)->lvl]); QFontMetrics fm(font); int fmh = fm.height(); //used to ensure label texts don't overlap int fmhD4 = fmh / 4; fmh += LABEL_TEXT_VMARGIN; rightSide = ((*it)->a < 1440 || (*it)->a > 4320); ra = M_PI / 2880 * (*it)->a; //convert to radians #if 0 sincos(ra, &sinra, &cosra); #endif sinra = sin(ra); cosra = cos(ra); spacer = preSpacer + m_map.m_ringBreadth * (*it)->lvl; x1 = cx + (int)(cosra * spacer); y1 = cy - (int)(sinra * spacer); y2 = y1 - (int)(sinra * (fullStrutLength - spacer)); if (rightSide) { //righthand side, going upwards if (y2 > prevRightY /*- fmh*/) //then it is too low, needs to be drawn higher y2 = prevRightY /*- fmh*/; } else { //lefthand side, going downwards if (y2 < prevLeftY/* + fmh*/) //then we're too high, need to be drawn lower y2 = prevLeftY /*+ fmh*/; } x2 = x1 - int(double(y2 - y1) / tan(ra)); ty = y2 + fmhD4; QString qs; if (rightSide) { if (x2 > width() || ty < fmh || x2 < x1) { //skip this strut //**** don't duplicate this code delete *it; it = list.erase(it); //will delete the label and set it to list.current() which _should_ be the next ptr break; } prevRightY = ty - fmh - fmhD4; //must be after above's "continue" qs = fm.elidedText((*it)->segment->file()->name(), Qt::ElideMiddle, width() - x2); x3 = width() - fm.QFONTMETRICS_WIDTH(qs) - LABEL_HMARGIN //outer margin - LABEL_TEXT_HMARGIN //margin between strut and text //- ((*it)->lvl - startLevel) * LABEL_HMARGIN //indentation ; if (x3 < x2) x3 = x2; tx = x3 + LABEL_TEXT_HMARGIN; } else { if (x2 < 0 || ty > height() || x2 > x1) { //skip this strut delete *it; it = list.erase(it); //will delete the label and set it to list.current() which _should_ be the next ptr break; } prevLeftY = ty + fmh - fmhD4; qs = fm.elidedText((*it)->segment->file()->name(), Qt::ElideMiddle, x2); //**** needs a little tweaking: tx = fm.QFONTMETRICS_WIDTH(qs) + LABEL_HMARGIN/* + ((*it)->lvl - startLevel) * LABEL_HMARGIN*/; if (tx > x2) { //text is too long tx = LABEL_HMARGIN + x2 - tx; //some text will be lost from sight x3 = x2; //no text margin (right side of text here) } else { x3 = tx + LABEL_TEXT_HMARGIN; tx = LABEL_HMARGIN /* + ((*it)->lvl - startLevel) * LABEL_HMARGIN*/; } } (*it)->x1 = x1; (*it)->y1 = y1; (*it)->x2 = x2; (*it)->y2 = y2; (*it)->x3 = x3; (*it)->tx = tx; (*it)->ty = ty; (*it)->qs = qs; } //if an element is deleted at this stage, we need to do this whole //iteration again, thus the following loop //**** in rare case that deleted label was last label in top level // and last in labelList too, this will not work as expected (not critical) } while (it != list.end()); - //5. Render labels + // 5. Render labels paint.setPen(QPen(Qt::black, 1)); for (it = list.begin(); it != list.end(); ++it) { if (varySizes) { //**** how much overhead in making new QFont each time? // (implicate sharing remember) QFont font = paint.font(); font.setPointSize(sizes[(*it)->lvl]); paint.setFont(font); } paint.drawEllipse((*it)->x1 - 3, (*it)->y1 - 3, 7, 7); //**** CPU intensive! better to use a pixmap paint.drawLine((*it)->x1, (*it)->y1, (*it)->x2, (*it)->y2); paint.drawLine((*it)->x2, (*it)->y2, (*it)->x3, (*it)->y2); paint.drawText((*it)->tx, (*it)->ty, (*it)->qs); } delete [] sizes; } diff --git a/krusader/DiskUsage/radialMap/map.cpp b/krusader/DiskUsage/radialMap/map.cpp index 4cb51a09..5bb9e45c 100644 --- a/krusader/DiskUsage/radialMap/map.cpp +++ b/krusader/DiskUsage/radialMap/map.cpp @@ -1,407 +1,407 @@ /***************************************************************************** * Copyright (C) 2003-2004 Max Howell <max.howell@methylblue.com> * * Copyright (C) 2004-2020 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ // QtGui #include <QImage> //make() & paint() #include <QFont> //ctor #include <QFontMetrics> //ctor #include <QPainter> #include <QPolygon> // QtWidgets #include <QApplication> //make() #include <KIconThemes/KIconEffect> //desaturate() #include <KWidgetsAddons/KCursor> //make() #include <KConfigWidgets/KColorScheme> #include "builder.h" #include "Config.h" #include "fileTree.h" #include "sincos.h" #include "widget.h" #define COLOR_GREY QColor::fromHsv( 0, 0, 140 ) RadialMap::Map::Map() : m_signature(nullptr) , m_ringBreadth(MIN_RING_BREADTH) , m_innerRadius(0) , m_visibleDepth(DEFAULT_RING_DEPTH) { //FIXME this is all broken. No longer is a maximum depth! const int fmh = QFontMetrics(QFont()).height(); const int fmhD4 = fmh / 4; MAP_2MARGIN = 2 * (fmh - (fmhD4 - LABEL_MAP_SPACER)); //margin is dependent on fitting in labels at top and bottom } RadialMap::Map::~Map() { delete [] m_signature; } void RadialMap::Map::invalidate(const bool desaturateTheImage) { delete [] m_signature; m_signature = nullptr; if (desaturateTheImage) { QImage img = this->toImage(); KIconEffect::deSaturate(img, 0.7); KIconEffect::toGray(img, true); this->QPixmap::operator=(fromImage(img, Qt::AutoColor)); } m_visibleDepth = Config::defaultRingDepth; } void RadialMap::Map::make(const Directory *tree, bool refresh) { //**** determineText seems pointless optimization // but is it good to keep the text consistent? // even if it makes it a lie? //slow operation so set the wait cursor QApplication::setOverrideCursor(Qt::WaitCursor); { //build a signature of visible components delete [] m_signature; Builder builder(this, tree, refresh); } //colour the segments colorise(); //determine centerText if (!refresh) { int i; for (i = 3; i > 0; --i) if (tree->size() > File::DENOMINATOR[i]) break; m_centerText = tree->humanReadableSize((File::UnitPrefix)i); } //paint the pixmap aaPaint(); QApplication::restoreOverrideCursor(); } void RadialMap::Map::setRingBreadth() { m_ringBreadth = (height() - MAP_2MARGIN) / (2 * m_visibleDepth + 4); if (m_ringBreadth < MIN_RING_BREADTH) m_ringBreadth = MIN_RING_BREADTH; else if (m_ringBreadth > MAX_RING_BREADTH) m_ringBreadth = MAX_RING_BREADTH; } bool RadialMap::Map::resize(const QRect &rect) { //there's a MAP_2MARGIN border #define mw width() #define mh height() #define cw rect.width() #define ch rect.height() if (cw < mw || ch < mh || (cw > mw && ch > mh)) { uint size = ((cw < ch) ? cw : ch) - MAP_2MARGIN; //this also causes uneven sizes to always resize when resizing but map is small in that dimension //size -= size % 2; //even sizes mean less staggered non-antialiased resizing { const uint minSize = MIN_RING_BREADTH * 2 * (m_visibleDepth + 2); const uint mD2 = MAP_2MARGIN / 2; if (size < minSize) size = minSize; //this QRect is used by paint() m_rect.setRect(mD2, mD2, size, size); } //resize the pixmap size += MAP_2MARGIN; this->QPixmap::operator=(QPixmap(size, size)); if (m_signature != nullptr) { setRingBreadth(); paint(); } else fill(); //FIXME I don't like having to do this.. return true; } #undef mw #undef mh #undef cw #undef ch return false; } void RadialMap::Map::colorise() { QColor cp, cb; double darkness = 1; double contrast = (double)Config::contrast / (double)100; int h, s1, s2, v1, v2; QColor kdeColour[2] = { KColorScheme(QPalette::Inactive, KColorScheme::Window).background().color(), KColorScheme(QPalette::Active, KColorScheme::Window).background(KColorScheme::ActiveBackground).color() }; - double deltaRed = (double)(kdeColour[0].red() - kdeColour[1].red()) / 2880; //2880 for semicircle + double deltaRed = (double)(kdeColour[0].red() - kdeColour[1].red()) / 2880; // 2880 for semicircle double deltaGreen = (double)(kdeColour[0].green() - kdeColour[1].green()) / 2880; double deltaBlue = (double)(kdeColour[0].blue() - kdeColour[1].blue()) / 2880; for (uint i = 0; i <= m_visibleDepth; ++i, darkness += 0.04) { for (Iterator<Segment> it = m_signature[i].iterator(); it != m_signature[i].end(); ++it) { switch (Config::scheme) { case Filelight::KDE: { //gradient will work by figuring out rgb delta values for 360 degrees //then each component is angle*delta int a = (*it)->start(); if (a > 2880) a = 2880 - (a - 2880); h = (int)(deltaRed * a) + kdeColour[1].red(); s1 = (int)(deltaGreen * a) + kdeColour[1].green(); v1 = (int)(deltaBlue * a) + kdeColour[1].blue(); cb.setRgb(h, s1, v1); cb.getHsv(&h, &s1, &v1); break; } case Filelight::HighContrast: cp.setHsv(0, 0, 0); //values of h, s and v are irrelevant cb.setHsv(180, 0, int(255.0 * contrast)); (*it)->setPalette(cp, cb); continue; default: h = int((*it)->start() / 16); s1 = 160; v1 = (int)(255.0 / darkness); //****doing this more often than once seems daft! } v2 = v1 - int(contrast * v1); s2 = s1 + int(contrast * (255 - s1)); if (s1 < 80) s1 = 80; //can fall too low and makes contrast between the files hard to discern if ((*it)->isFake()) { //multi-file cb.setHsv(h, s2, (v2 < 90) ? 90 : v2); //too dark if < 100 cp.setHsv(h, 17, v1); } else if (!(*it)->file()->isDir()) { //file cb.setHsv(h, 17, v1); cp.setHsv(h, 17, v2); } else { //directory cb.setHsv(h, s1, v1); //v was 225 cp.setHsv(h, s2, v2); //v was 225 - delta } (*it)->setPalette(cp, cb); //**** may be better to store KDE colours as H and S and vary V as others //**** perhaps make saturation difference for s2 dependent on contrast too //**** fake segments don't work with highContrast //**** may work better with cp = cb rather than Qt::white //**** you have to ensure the grey of files is sufficient, currently it works only with rainbow (perhaps use contrast there too) //**** change v1,v2 to vp, vb etc. //**** using percentages is not strictly correct as the eye doesn't work like that //**** darkness factor is not done for kde_colour scheme, and also value for files is incorrect really for files in this scheme as it is not set like rainbow one is } } } void RadialMap::Map::aaPaint() { //paint() is called during continuous processes //aaPaint() is not and is slower so set overidecursor (make sets it too) QApplication::setOverrideCursor(Qt::WaitCursor); paint(Config::antiAliasFactor); QApplication::restoreOverrideCursor(); } void RadialMap::Map::paint(unsigned int scaleFactor) { if (scaleFactor == 0) //just in case scaleFactor = 1; QPainter paint; QRect rect = m_rect; int step = m_ringBreadth; int excess = -1; //scale the pixmap, or do intelligent distribution of excess to prevent nasty resizing if (scaleFactor > 1) { int x1, y1, x2, y2; rect.getCoords(&x1, &y1, &x2, &y2); x1 *= scaleFactor; y1 *= scaleFactor; x2 *= scaleFactor; y2 *= scaleFactor; rect.setCoords(x1, y1, x2, y2); step *= scaleFactor; QPixmap::operator=(QPixmap(this->size() * (int)scaleFactor)); } else if (m_ringBreadth != MAX_RING_BREADTH && m_ringBreadth != MIN_RING_BREADTH) { excess = rect.width() % m_ringBreadth; ++step; } //**** best option you can think of is to make the circles slightly less perfect, // ** i.e. slightly elliptic when resizing inbetween paint.begin(this); fill(); //erase background for (int x = m_visibleDepth; x >= 0; --x) { int width = rect.width() / 2; //clever geometric trick to find largest angle that will give biggest arrow head auto a_max = int(acos((double)width / double((width + 5) * scaleFactor)) * (180 * 16 / M_PI)); for (ConstIterator<Segment> it = m_signature[x].constIterator(); it != m_signature[x].end(); ++it) { //draw the pie segments, most of this code is concerned with drawing the little //arrows on the ends of segments when they have hidden files paint.setPen((*it)->pen()); if ((*it)->hasHiddenChildren()) { //draw arrow head to indicate undisplayed files/directories QPolygon pts(3); QPoint pos, cpos = rect.center(); int a[3] = {static_cast<int>((*it)->start()), static_cast<int>((*it)->length()), 0 }; a[2] = a[0] + (a[1] / 2); //assign to halfway between if (a[1] > a_max) { a[1] = a_max; a[0] = a[2] - a_max / 2; } a[1] += a[0]; for (int i = 0, radius = width; i < 3; ++i) { double ra = M_PI / (180 * 16) * a[i], sinra, cosra; if (i == 2) radius += 5 * scaleFactor; #if 0 sincos(ra, &sinra, &cosra); #endif sinra = sin(ra); cosra = cos(ra); pos.rx() = cpos.x() + static_cast<int>(cosra * radius); pos.ry() = cpos.y() - static_cast<int>(sinra * radius); pts.setPoint(i, pos); } paint.setBrush((*it)->pen()); paint.drawPolygon(pts); } paint.setBrush((*it)->brush()); paint.drawPie(rect, (*it)->start(), (*it)->length()); if ((*it)->hasHiddenChildren()) { //**** code is bloated! paint.save(); QPen pen = paint.pen(); int width = 2 * scaleFactor; pen.setWidth(width); paint.setPen(pen); QRect rect2 = rect; width /= 2; rect2.adjust(width, width, -width, -width); paint.drawArc(rect2, (*it)->start(), (*it)->length()); paint.restore(); } } if (excess >= 0) { //excess allows us to resize more smoothly (still crud tho) if (excess < 2) //only decrease rect by more if even number of excesses left --step; excess -= 2; } rect.adjust(step, step, -step, -step); } // if( excess > 0 ) rect.adjust( excess, excess, 0, 0 ); //ugly paint.setPen(COLOR_GREY); paint.setBrush(Qt::white); paint.drawEllipse(rect); if (scaleFactor > 1) { //have to end in order to smoothscale() paint.end(); int x1, y1, x2, y2; rect.getCoords(&x1, &y1, &x2, &y2); x1 /= scaleFactor; y1 /= scaleFactor; x2 /= scaleFactor; y2 /= scaleFactor; rect.setCoords(x1, y1, x2, y2); QImage img = this->toImage(); img = img.scaled(this->size() / (int)scaleFactor, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); this->QPixmap::operator=(fromImage(img, Qt::AutoColor)); paint.begin(this); paint.setPen(COLOR_GREY); paint.setBrush(Qt::white); } paint.drawText(rect, Qt::AlignCenter, m_centerText); m_innerRadius = rect.width() / 2; //rect.width should be multiple of 2 paint.end(); } #if 0 #if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 void sincos(double angleRadians, double *Sin, double *Cos) { *Sin = sin(angleRadians); *Cos = cos(angleRadians); } #endif #endif diff --git a/krusader/DiskUsage/radialMap/widget.h b/krusader/DiskUsage/radialMap/widget.h index eedd2010..fc9992df 100644 --- a/krusader/DiskUsage/radialMap/widget.h +++ b/krusader/DiskUsage/radialMap/widget.h @@ -1,140 +1,140 @@ /***************************************************************************** * Copyright (C) 2004 Max Howell <max.howell@methylblue.com> * * Copyright (C) 2004-2020 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #ifndef WIDGET_H #define WIDGET_H // QtCore #include <QTimer> #include <QUrl> // QtGui #include <QMouseEvent> #include <QResizeEvent> #include <QPaintEvent> #include "segmentTip.h" template <class T> class Chain; class Directory; class File; class KJob; namespace RadialMap { class Segment; class Map : public QPixmap { public: Map(); ~Map() override; void make(const Directory *, bool = false); bool resize(const QRect&); bool isNull() const { return (m_signature == nullptr); } void invalidate(const bool); friend class Builder; friend class Widget; private: void paint(uint = 1); void aaPaint(); void colorise(); void setRingBreadth(); Chain<Segment> *m_signature; QRect m_rect; uint m_ringBreadth; ///ring breadth uint m_innerRadius; ///radius of inner circle uint m_visibleDepth; ///visible level depth of system QString m_centerText; uint MAP_2MARGIN; }; class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget* = nullptr); QString path() const; QUrl url(File const * const = nullptr) const; bool isValid() const { return m_tree != nullptr; } friend struct Label; //FIXME badness public slots: void zoomIn(); void zoomOut(); void create(const Directory*); void invalidate(const bool = true); void refresh(int); private slots: void resizeTimeout(); void sendFakeMouseEvent(); void deleteJobFinished(KJob*); void createFromCache(const Directory*); signals: void activated(const QUrl&); void invalidated(const QUrl&); void created(const Directory*); void mouseHover(const QString&); protected: void paintEvent(QPaintEvent*) override; void resizeEvent(QResizeEvent*) override; void mouseMoveEvent(QMouseEvent*) override; void mousePressEvent(QMouseEvent*) override; protected: const Segment *segmentAt(QPoint&) const; //FIXME const reference for a library others can use const Segment *rootSegment() const { return m_rootSegment; - } ///never == 0 + } /// never == 0 const Segment *focusSegment() const { return m_focus; - } ///0 == nothing in focus + } /// 0 == nothing in focus private: void paintExplodedLabels(QPainter&) const; const Directory *m_tree; const Segment *m_focus; QPoint m_offset; QTimer m_timer; Map m_map; SegmentTip m_tip; Segment *m_rootSegment; }; } #endif diff --git a/krusader/DiskUsage/radialMap/widgetEvents.cpp b/krusader/DiskUsage/radialMap/widgetEvents.cpp index 35f1a7af..965e3f89 100644 --- a/krusader/DiskUsage/radialMap/widgetEvents.cpp +++ b/krusader/DiskUsage/radialMap/widgetEvents.cpp @@ -1,252 +1,252 @@ /***************************************************************************** * Copyright (C) 2003-2004 Max Howell <max.howell@methylblue.com> * * Copyright (C) 2004-2020 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "fileTree.h" #include "radialMap.h" //class Segment #include "widget.h" #include "../../icon.h" #include <cmath> // QtCore #include <QTimer> //::resizeEvent() // QtGui #include <QMouseEvent> #include <QPainter> #include <QPaintEvent> #include <QResizeEvent> // QtWidgets #include <QApplication> //QApplication::setOverrideCursor() #include <QMenu> #include <KI18n/KLocalizedString> #include <KIconThemes/KIconEffect> #include <KIO/DeleteJob> #include <KIO/JobUiDelegate> #include <KIOWidgets/KRun> #include <KWidgetsAddons/KCursor> #include <KWidgetsAddons/KMessageBox> void RadialMap::Widget::resizeEvent(QResizeEvent*) { if (m_map.resize(rect())) { m_timer.setSingleShot(true); m_timer.start(500); //will cause signature to rebuild for new size } //always do these as they need to be initialised on creation m_offset.rx() = (width() - m_map.width()) / 2; m_offset.ry() = (height() - m_map.height()) / 2; } void RadialMap::Widget::paintEvent(QPaintEvent*) { //bltBit for some Qt setups will bitBlt _after_ the labels are painted. Which buggers things up! //shame as bitBlt is faster, possibly Qt bug? Should report the bug? - seems to be race condition //bitBlt( this, m_offset, &m_map ); QPainter paint(this); paint.drawPixmap(m_offset, m_map); //vertical strips if (m_map.width() < width()) { paint.eraseRect(0, 0, m_offset.x(), height()); paint.eraseRect(m_map.width() + m_offset.x(), 0, m_offset.x() + 1, height()); } //horizontal strips if (m_map.height() < height()) { paint.eraseRect(0, 0, width(), m_offset.y()); paint.eraseRect(0, m_map.height() + m_offset.y(), width(), m_offset.y() + 1); } //exploded labels if (!m_map.isNull() && !m_timer.isActive()) paintExplodedLabels(paint); } const RadialMap::Segment* RadialMap::Widget::segmentAt(QPoint &e) const { //determine which segment QPoint e is above e -= m_offset; if (e.x() <= m_map.width() && e.y() <= m_map.height()) { //transform to cartesian coords e.rx() -= m_map.width() / 2; //should be an int e.ry() = m_map.height() / 2 - e.y(); double length = std::hypot(e.x(), e.y()); if (length >= m_map.m_innerRadius) { //not hovering over inner circle uint depth = ((int)length - m_map.m_innerRadius) / m_map.m_ringBreadth; if (depth <= m_map.m_visibleDepth) { //**** do earlier since you can //** check not outside of range //vector calculation, reduces to simple trigonometry //cos angle = (aibi + ajbj) / albl //ai = x, bi=1, aj=y, bj=0 //cos angle = x / (length) - auto a = (uint)(acos((double)e.x() / length) * 916.736); //916.7324722 = #radians in circle * 16 + auto a = (uint)(acos((double)e.x() / length) * 916.736); // 916.7324722 = #radians in circle * 16 //acos only understands 0-180 degrees if (e.y() < 0) a = 5760 - a; #define ring (m_map.m_signature + depth) for (ConstIterator<Segment> it = ring->constIterator(); it != ring->end(); ++it) if ((*it)->intersects(a)) return *it; #undef ring } } else return m_rootSegment; //hovering over inner circle } return nullptr; } void RadialMap::Widget::mouseMoveEvent(QMouseEvent *e) { //set m_focus to what we hover over, update UI if it's a new segment Segment const * const oldFocus = m_focus; QPoint p = e->pos(); m_focus = segmentAt(p); //NOTE p is passed by non-const reference if (m_focus && m_focus->file() != m_tree) { if (m_focus != oldFocus) { //if not same as last time setCursor(QCursor(Qt::PointingHandCursor)); m_tip.updateTip(m_focus->file(), m_tree); emit mouseHover(m_focus->file()->fullPath()); //repaint required to update labels now before transparency is generated repaint(); } // updates tooltip pseudo-transparent background m_tip.moveto(e->globalPos(), *this, (p.y() < 0)); } else if (oldFocus && oldFocus->file() != m_tree) { unsetCursor(); m_tip.hide(); update(); emit mouseHover(QString()); } } void RadialMap::Widget::mousePressEvent(QMouseEvent *e) { //m_tip is hidden already by event filter //m_focus is set correctly (I've been strict, I assure you it is correct!) if (m_focus && !m_focus->isFake()) { const QUrl url = Widget::url(m_focus->file()); const bool isDir = m_focus->file()->isDir(); if (e->button() == Qt::RightButton) { QMenu popup; popup.setTitle(m_focus->file()->fullPath(m_tree)); QAction * actKonq = nullptr, * actKonsole = nullptr, *actViewMag = nullptr, * actFileOpen = nullptr, * actEditDel = nullptr; if (isDir) { actKonq = popup.addAction(Icon("system-file-manager"), i18n("Open File Manager Here")); if (url.scheme() == "file") actKonsole = popup.addAction(Icon("utilities-terminal"), i18n("Open Terminal Here")); if (m_focus->file() != m_tree) { popup.addSeparator(); actViewMag = popup.addAction(Icon("zoom-original"), i18n("&Center Map Here")); } } else actFileOpen = popup.addAction(Icon("document-open"), i18n("&Open")); popup.addSeparator(); actEditDel = popup.addAction(Icon("edit-delete"), i18n("&Delete")); QAction * result = popup.exec(e->globalPos()); if (result == nullptr) result = (QAction *) - 1; // sanity if (result == actKonq) //KRun::runCommand will show an error message if there was trouble KRun::runCommand(QString("kfmclient openURL '%1'").arg(url.url()), this); else if (result == actKonsole) KRun::runCommand(QString("konsole --workdir '%1'").arg(url.url()), this); else if (result == actViewMag || result == actFileOpen) goto sectionTwo; else if (result == actEditDel) { const QUrl url = Widget::url(m_focus->file()); const QString message = (m_focus->file()->isDir() ? i18n("<qt>The folder at <i>'%1'</i> will be <b>recursively</b> and <b>permanently</b> deleted.</qt>", url.toDisplayString()) : i18n("<qt><i>'%1'</i> will be <b>permanently</b> deleted.</qt>", url.toDisplayString())); const int userIntention = KMessageBox::warningContinueCancel(this, message, QString(), KStandardGuiItem::del()); if (userIntention == KMessageBox::Continue) { KIO::Job *job = KIO::del(url); auto *ui = dynamic_cast<KIO::JobUiDelegate*>(job->uiDelegate()); ui->setWindow(this); connect(job, &KIO::Job::result, this, &Widget::deleteJobFinished); QApplication::setOverrideCursor(Qt::BusyCursor); } } else //ensure m_focus is set for new mouse position sendFakeMouseEvent(); } else { sectionTwo: const QRect rect(e->x() - 20, e->y() - 20, 40, 40); m_tip.hide(); //user expects this if (!isDir || e->button() == Qt::MidButton) { #if 0 // TODO: PORTME KIconEffect::visualActivate(this, rect); #endif new KRun(url, this, true); //FIXME see above } else if (m_focus->file() != m_tree) { //is left mouse button #if 0 // TODO: PORTME KIconEffect::visualActivate(this, rect); #endif emit activated(url); //activate first, this will cause UI to prepare itself if (m_focus) createFromCache(dynamic_cast<const Directory*>(m_focus->file())); } } } } void RadialMap::Widget::deleteJobFinished(KJob *job) { QApplication::restoreOverrideCursor(); if (!job->error()) invalidate(); else job->uiDelegate()->showErrorMessage(); } diff --git a/krusader/FileSystem/krquery.cpp b/krusader/FileSystem/krquery.cpp index ff6a8d25..56c813ed 100644 --- a/krusader/FileSystem/krquery.cpp +++ b/krusader/FileSystem/krquery.cpp @@ -1,778 +1,779 @@ /***************************************************************************** * Copyright (C) 2001 Shie Erlich <krusader@users.sourceforge.net> * * Copyright (C) 2001 Rafi Yanai <krusader@users.sourceforge.net> * * Copyright (C) 2004-2020 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "krquery.h" // QtCore #include <QFile> #include <QMetaMethod> #include <QRegExp> #include <QTextCodec> #include <KI18n/KLocalizedString> #include <KIO/Job> #include <KIOCore/KFileItem> #include <KIOWidgets/KUrlCompletion> #include <utility> #include "../Archive/krarchandler.h" #include "fileitem.h" #include "filesystem.h" #include "krpermhandler.h" #define STATUS_SEND_DELAY 250 #define MAX_LINE_LEN 1000 // set the defaults KrQuery::KrQuery() : matchesCaseSensitive(true), bNull(true), contain(QString()), containCaseSensetive(true), containWholeWord(false), containRegExp(false), minSize(0), maxSize(0), newerThen(0), olderThen(0), owner(QString()), group(QString()), perm(QString()), type(QString()), inArchive(false), recurse(true), followLinksP(true), receivedBuffer(nullptr), receivedBufferLen(0), processEventsConnected(0), codec(QTextCodec::codecForLocale()) { QChar ch = '\n'; QTextCodec::ConverterState state(QTextCodec::IgnoreHeader); encodedEnterArray = codec->fromUnicode(&ch, 1, &state); encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); } // set the defaults KrQuery::KrQuery(const QString &name, bool matchCase) : bNull(true), contain(QString()), containCaseSensetive(true), containWholeWord(false), containRegExp(false), minSize(0), maxSize(0), newerThen(0), olderThen(0), owner(QString()), group(QString()), perm(QString()), type(QString()), inArchive(false), recurse(true), followLinksP(true), receivedBuffer(nullptr), receivedBufferLen(0), processEventsConnected(0), codec(QTextCodec::codecForLocale()) { QChar ch = '\n'; QTextCodec::ConverterState state(QTextCodec::IgnoreHeader); encodedEnterArray = codec->fromUnicode(&ch, 1, &state); encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); setNameFilter(name, matchCase); } KrQuery::KrQuery(const KrQuery &that) : QObject(), receivedBuffer(nullptr), receivedBufferLen(0), processEventsConnected(0) { *this = that; } KrQuery::~KrQuery() { if (receivedBuffer) delete[] receivedBuffer; receivedBuffer = nullptr; } KrQuery &KrQuery::operator=(const KrQuery &old) { matches = old.matches; excludes = old.excludes; includedDirs = old.includedDirs; excludedDirs = old.excludedDirs; matchesCaseSensitive = old.matchesCaseSensitive; bNull = old.bNull; contain = old.contain; containCaseSensetive = old.containCaseSensetive; containWholeWord = old.containWholeWord; containRegExp = old.containRegExp; minSize = old.minSize; maxSize = old.maxSize; newerThen = old.newerThen; olderThen = old.olderThen; owner = old.owner; group = old.group; perm = old.perm; type = old.type; customType = old.customType; inArchive = old.inArchive; recurse = old.recurse; followLinksP = old.followLinksP; whereToSearch = old.whereToSearch; excludedFolderNames = old.excludedFolderNames; whereNotToSearch = old.whereNotToSearch; origFilter = old.origFilter; codec = old.codec; encodedEnterArray = old.encodedEnterArray; encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); return *this; } void KrQuery::load(const KConfigGroup& cfg) { *this = KrQuery(); // reset parameters first if (cfg.readEntry("IsNull", true)) return; #define LOAD(key, var) (var = cfg.readEntry(key, var)) LOAD("Matches", matches); LOAD("Excludes", excludes); LOAD("IncludedDirs", includedDirs); LOAD("ExcludedDirs", excludedDirs); LOAD("MatchesCaseSensitive", matchesCaseSensitive); LOAD("Contain", contain); LOAD("ContainCaseSensetive", containCaseSensetive); LOAD("ContainWholeWord", containWholeWord); LOAD("ContainRegExp", containRegExp); LOAD("MinSize", minSize); LOAD("MaxSize", maxSize); newerThen = QDateTime::fromString( cfg.readEntry("NewerThan", QDateTime::fromTime_t(newerThen).toString())) .toTime_t(); olderThen = QDateTime::fromString( cfg.readEntry("OlderThan", QDateTime::fromTime_t(olderThen).toString())) .toTime_t(); LOAD("Owner", owner); LOAD("Group", group); LOAD("Perm", perm); LOAD("Type", type); LOAD("CustomType", customType); LOAD("InArchive", inArchive); LOAD("Recurse", recurse); LOAD("FollowLinks", followLinksP); // KF5 TODO? // LOAD("WhereToSearch", whereToSearch); // LOAD("WhereNotToSearch", whereNotToSearch); LOAD("OrigFilter", origFilter); codec = QTextCodec::codecForName(cfg.readEntry("Codec", codec->name())); if (!codec) codec = QTextCodec::codecForLocale(); LOAD("EncodedEnterArray", encodedEnterArray); encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); #undef LOAD bNull = false; } void KrQuery::save(KConfigGroup cfg) { cfg.writeEntry("IsNull", bNull); if (bNull) return; cfg.writeEntry("Matches", matches); cfg.writeEntry("Excludes", excludes); cfg.writeEntry("IncludedDirs", includedDirs); cfg.writeEntry("ExcludedDirs", excludedDirs); cfg.writeEntry("MatchesCaseSensitive", matchesCaseSensitive); cfg.writeEntry("Contain", contain); cfg.writeEntry("ContainCaseSensetive", containCaseSensetive); cfg.writeEntry("ContainWholeWord", containWholeWord); cfg.writeEntry("ContainRegExp", containRegExp); cfg.writeEntry("MinSize", minSize); cfg.writeEntry("MaxSize", maxSize); cfg.writeEntry("NewerThan", QDateTime::fromTime_t(newerThen).toString()); cfg.writeEntry("OlderThan", QDateTime::fromTime_t(olderThen).toString()); cfg.writeEntry("Owner", owner); cfg.writeEntry("Group", group); cfg.writeEntry("Perm", perm); cfg.writeEntry("Type", type); cfg.writeEntry("CustomType", customType); cfg.writeEntry("InArchive", inArchive); cfg.writeEntry("Recurse", recurse); cfg.writeEntry("FollowLinks", followLinksP); // KF5 TODO? // cfg.writeEntry("WhereToSearch", whereToSearch); // cfg.writeEntry("WhereNotToSearch", whereNotToSearch); cfg.writeEntry("OrigFilter", origFilter); cfg.writeEntry("Codec", codec->name()); cfg.writeEntry("EncodedEnterArray", encodedEnterArray); cfg.writeEntry("EncodedEnter", encodedEnter); cfg.writeEntry("EncodedEnterLen", encodedEnterLen); } void KrQuery::connectNotify(const QMetaMethod &signal) { if (signal == QMetaMethod::fromSignal(&KrQuery::processEvents)) processEventsConnected++; } void KrQuery::disconnectNotify(const QMetaMethod &signal) { if (signal == QMetaMethod::fromSignal(&KrQuery::processEvents)) processEventsConnected--; } bool KrQuery::checkPerm(QString filePerm) const { for (int i = 0; i < 9; ++i) if (perm[i] != '?' && perm[i] != filePerm[i + 1]) return false; return true; } bool KrQuery::checkType(const QString& mime) const { if (type == mime) return true; if (type == i18n("Archives")) return KrArcHandler::arcSupported(mime); if (type == i18n("Folders")) return mime.contains("directory"); if (type == i18n("Image Files")) return mime.contains("image/"); if (type == i18n("Text Files")) return mime.contains("text/"); if (type == i18n("Video Files")) return mime.contains("video/"); if (type == i18n("Audio Files")) return mime.contains("audio/"); if (type == i18n("Custom")) return customType.contains(mime); return false; } bool KrQuery::match(const QString &name) const { return matchCommon(name, matches, excludes); } bool KrQuery::matchDirName(const QString &name) const { return matchCommon(name, includedDirs, excludedDirs); } bool KrQuery::matchCommon(const QString &nameIn, const QStringList &matchList, const QStringList &excludeList) const { if (excludeList.count() == 0 && matchList.count() == 0) /* true if there's no match condition */ return true; QString name(nameIn); int ndx = nameIn.lastIndexOf('/'); // virtual filenames may contain '/' if (ndx != -1) // but the end of the filename is OK name = nameIn.mid(ndx + 1); for (int i = 0; i < excludeList.count(); ++i) { if (QRegExp(excludeList[i], matchesCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard) .exactMatch(name)) return false; } if (matchList.count() == 0) return true; for (int i = 0; i < matchList.count(); ++i) { if (QRegExp(matchList[i], matchesCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard) .exactMatch(name)) return true; } return false; } bool KrQuery::match(FileItem *item) const { if (item->isDir() && !matchDirName(item->getName())) return false; // see if the name matches if (!match(item->getName())) return false; // checking the mime if (!type.isEmpty() && !checkType(item->getMime())) return false; // check that the size fit KIO::filesize_t size = item->getSize(); if (minSize && size < minSize) return false; if (maxSize && size > maxSize) return false; // check the time frame time_t mtime = item->getModificationTime(); if (olderThen && mtime > olderThen) return false; if (newerThen && mtime < newerThen) return false; // check owner name if (!owner.isEmpty() && item->getOwner() != owner) return false; // check group name if (!group.isEmpty() && item->getGroup() != group) return false; // check permission if (!perm.isEmpty() && !checkPerm(item->getPerm())) return false; if (!contain.isEmpty()) { if ((totalBytes = item->getSize()) == 0) totalBytes++; // sanity receivedBytes = 0; if (receivedBuffer) delete receivedBuffer; receivedBuffer = nullptr; receivedBufferLen = 0; fileName = item->getName(); timer.start(); // search locally if (item->getUrl().isLocalFile()) { return containsContent(item->getUrl().path()); } // search remotely if (processEventsConnected == 0) { return false; } return containsContent(item->getUrl()); } return true; } // takes the string and adds BOLD to it, so that when it is displayed, // the grepped text will be bold void fixFoundTextForDisplay(QString &haystack, int start, int length) { QString before = haystack.left(start); QString text = haystack.mid(start, length); QString after = haystack.mid(start + length); before.replace('&', "&"); before.replace('<', "<"); before.replace('>', ">"); text.replace('&', "&"); text.replace('<', "<"); text.replace('>', ">"); after.replace('&', "&"); after.replace('<', "<"); after.replace('>', ">"); haystack = ("<qt>" + before + "<b>" + text + "</b>" + after + "</qt>"); } bool KrQuery::checkBuffer(const char *data, int len) const { bool result = false; auto *mergedBuffer = new char[len + receivedBufferLen]; if (receivedBufferLen) memcpy(mergedBuffer, receivedBuffer, receivedBufferLen); if (len) memcpy(mergedBuffer + receivedBufferLen, data, len); int maxLen = len + receivedBufferLen; int maxBuffer = maxLen - encodedEnterLen; int lastLinePosition = 0; for (int enterIndex = 0; enterIndex < maxBuffer; enterIndex++) { if (memcmp(mergedBuffer + enterIndex, encodedEnter, encodedEnterLen) == 0) { QString str = codec->toUnicode(mergedBuffer + lastLinePosition, enterIndex + encodedEnterLen - lastLinePosition); if (str.endsWith('\n')) { str.chop(1); result = result || checkLine(str); lastLinePosition = enterIndex + encodedEnterLen; enterIndex = lastLinePosition; continue; } } } if (maxLen - lastLinePosition > MAX_LINE_LEN || len == 0) { QString str = codec->toUnicode(mergedBuffer + lastLinePosition, maxLen - lastLinePosition); result = result || checkLine(str); lastLinePosition = maxLen; } delete[] receivedBuffer; receivedBuffer = nullptr; receivedBufferLen = maxLen - lastLinePosition; if (receivedBufferLen) { receivedBuffer = new char[receivedBufferLen]; memcpy(receivedBuffer, mergedBuffer + lastLinePosition, receivedBufferLen); } delete[] mergedBuffer; return result; } bool KrQuery::checkLine(const QString &line, bool backwards) const { if (containRegExp) { QRegExp rexp(contain, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::RegExp); int ndx = backwards ? rexp.lastIndexIn(line) : rexp.indexIn(line); bool result = ndx >= 0; if (result) fixFoundTextForDisplay(lastSuccessfulGrep = line, lastSuccessfulGrepMatchIndex = ndx, lastSuccessfulGrepMatchLength = rexp.matchedLength()); return result; } int ndx = backwards ? -1 : 0; if (line.isNull()) return false; if (containWholeWord) { while ((ndx = (backwards) ? line.lastIndexOf(contain, ndx, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive) : line.indexOf(contain, ndx, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive)) != -1) { QChar before = '\n'; QChar after = '\n'; if (ndx > 0) before = line.at(ndx - 1); if (ndx + contain.length() < line.length()) after = line.at(ndx + contain.length()); if (!before.isLetterOrNumber() && !after.isLetterOrNumber() && after != '_' && before != '_') { lastSuccessfulGrep = line; fixFoundTextForDisplay(lastSuccessfulGrep, lastSuccessfulGrepMatchIndex = ndx, lastSuccessfulGrepMatchLength = contain.length()); return true; } if (backwards) ndx -= line.length() + 1; else ndx++; } } else if ((ndx = (backwards) ? line.lastIndexOf(contain, -1, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive) : line.indexOf(contain, 0, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive)) != -1) { lastSuccessfulGrep = line; fixFoundTextForDisplay(lastSuccessfulGrep, lastSuccessfulGrepMatchIndex = ndx, lastSuccessfulGrepMatchLength = contain.length()); return true; } return false; } bool KrQuery::containsContent(const QString& file) const { QFile qf(file); if (!qf.open(QIODevice::ReadOnly)) return false; char buffer[1440]; // 2k buffer while (!qf.atEnd()) { int bytes = qf.read(buffer, sizeof(buffer)); if (bytes <= 0) break; receivedBytes += bytes; if (checkBuffer(buffer, bytes)) return true; if (checkTimer()) { bool stopped = false; emit((KrQuery *)this)->processEvents(stopped); if (stopped) return false; } } if (checkBuffer(buffer, 0)) return true; lastSuccessfulGrep.clear(); // nothing was found return false; } bool KrQuery::containsContent(const QUrl& url) const { KIO::TransferJob *contentReader = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo); connect(contentReader, &KIO::TransferJob::data, this, &KrQuery::containsContentData); connect(contentReader, &KIO::Job::result, this, &KrQuery::containsContentFinished); busy = true; containsContentResult = false; bool stopped = false; while (busy && !stopped) { checkTimer(); emit((KrQuery *)this)->processEvents(stopped); } if (busy) { contentReader->kill(KJob::EmitResult); busy = false; } return containsContentResult; } void KrQuery::containsContentData(KIO::Job *job, const QByteArray &array) { receivedBytes += array.size(); if (checkBuffer(array.data(), array.size())) { containsContentResult = true; containsContentFinished(job); job->kill(KJob::EmitResult); return; } checkTimer(); } void KrQuery::containsContentFinished(KJob *) { busy = false; } bool KrQuery::checkTimer() const { if (timer.elapsed() >= STATUS_SEND_DELAY) { auto pcnt = (int)(100. * (double)receivedBytes / (double)totalBytes + .5); QString message = i18nc("%1=filename, %2=percentage", "Searching content of '%1' (%2%)", fileName, pcnt); timer.start(); emit((KrQuery *)this)->status(message); return true; } return false; } QStringList KrQuery::split(QString str) { QStringList list; int splitNdx = 0; int startNdx = 0; bool quotation = false; while (splitNdx < str.length()) { if (str[splitNdx] == '"') quotation = !quotation; if (!quotation && str[splitNdx] == ' ') { QString section = str.mid(startNdx, splitNdx - startNdx); startNdx = splitNdx + 1; if (section.startsWith('\"') && section.endsWith('\"') && section.length() >= 2) section = section.mid(1, section.length() - 2); if (!section.isEmpty()) list.append(section); } splitNdx++; } if (startNdx < splitNdx) { QString section = str.mid(startNdx, splitNdx - startNdx); if (section.startsWith('\"') && section.endsWith('\"') && section.length() >= 2) section = section.mid(1, section.length() - 2); if (!section.isEmpty()) list.append(section); } return list; } void KrQuery::setNameFilter(const QString &text, bool cs) { bNull = false; matchesCaseSensitive = cs; origFilter = text; QString matchText = text; QString excludeText; int excludeNdx = 0; bool quotationMark = 0; while (excludeNdx < matchText.length()) { if (matchText[excludeNdx] == '"') quotationMark = !quotationMark; if (!quotationMark) { if (matchText[excludeNdx] == '|') break; } excludeNdx++; } if (excludeNdx < matchText.length()) { excludeText = matchText.mid(excludeNdx + 1).trimmed(); matchText.truncate(excludeNdx); matchText = matchText.trimmed(); if (matchText.isEmpty()) matchText = '*'; } int i; matches = split(matchText); includedDirs.clear(); for (i = 0; i < matches.count();) { if (matches[i].endsWith('/')) { includedDirs.push_back(matches[i].left(matches[i].length() - 1)); matches.removeAll(matches.at(i)); continue; } if (!matches[i].contains("*") && !matches[i].contains("?")) matches[i] = '*' + matches[i] + '*'; i++; } excludes = split(excludeText); excludedDirs.clear(); for (i = 0; i < excludes.count();) { if (excludes[i].endsWith('/')) { excludedDirs.push_back(excludes[i].left(excludes[i].length() - 1)); excludes.removeAll(excludes.at(i)); continue; } if (!excludes[i].contains("*") && !excludes[i].contains("?")) excludes[i] = '*' + excludes[i] + '*'; i++; } } void KrQuery::setContent(const QString &content, bool cs, bool wholeWord, const QString& encoding, bool regExp) { bNull = false; contain = content; containCaseSensetive = cs; containWholeWord = wholeWord; containRegExp = regExp; if (encoding.isEmpty()) codec = QTextCodec::codecForLocale(); else { codec = QTextCodec::codecForName(encoding.toLatin1()); if (codec == nullptr) codec = QTextCodec::codecForLocale(); } QChar ch = '\n'; QTextCodec::ConverterState state(QTextCodec::IgnoreHeader); encodedEnterArray = codec->fromUnicode(&ch, 1, &state); encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); } void KrQuery::setMinimumFileSize(KIO::filesize_t minimumSize) { bNull = false; minSize = minimumSize; } void KrQuery::setMaximumFileSize(KIO::filesize_t maximumSize) { bNull = false; maxSize = maximumSize; } void KrQuery::setNewerThan(time_t time) { bNull = false; newerThen = time; } void KrQuery::setOlderThan(time_t time) { bNull = false; olderThen = time; } void KrQuery::setOwner(const QString &ownerIn) { bNull = false; owner = ownerIn; } void KrQuery::setGroup(const QString &groupIn) { bNull = false; group = groupIn; } void KrQuery::setPermissions(const QString &permIn) { bNull = false; perm = permIn; } void KrQuery::setMimeType(const QString &typeIn, QStringList customList) { bNull = false; type = typeIn; customType = std::move(customList); } bool KrQuery::isExcluded(const QUrl &url) { for (QUrl &item : whereNotToSearch) if (item.isParentOf(url) || url.matches(item, QUrl::StripTrailingSlash)) return true; // Exclude folder names that are configured in settings QString filename = url.fileName(); for (QString &item : excludedFolderNames) if (filename == item) return true; if (!matchDirName(filename)) return true; return false; } void KrQuery::setSearchInDirs(const QList<QUrl> &urls) { whereToSearch.clear(); for (int i = 0; i < urls.count(); ++i) { QString url = urls[i].url(); QUrl completed = QUrl::fromUserInput(KUrlCompletion::replacedPath(url, true, true), QString(), QUrl::AssumeLocalFile); whereToSearch.append(completed); } } void KrQuery::setDontSearchInDirs(const QList<QUrl> &urls) { whereNotToSearch.clear(); for (int i = 0; i < urls.count(); ++i) { QString url = urls[i].url(); QUrl completed = QUrl::fromUserInput(KUrlCompletion::replacedPath(url, true, true), QString(), QUrl::AssumeLocalFile); whereNotToSearch.append(completed); } } + void KrQuery::setExcludeFolderNames(const QStringList &paths) { excludedFolderNames.clear(); excludedFolderNames.append(paths); } diff --git a/krusader/Filter/generalfilter.h b/krusader/Filter/generalfilter.h index b68f3ed4..28d7ed13 100644 --- a/krusader/Filter/generalfilter.h +++ b/krusader/Filter/generalfilter.h @@ -1,118 +1,118 @@ /***************************************************************************** * Copyright (C) 2003 Csaba Karai <krusader@users.sourceforge.net> * * Copyright (C) 2004-2020 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #ifndef GENERALFILTER_H #define GENERALFILTER_H // QtWidgets #include <QWidget> #include <QLayout> #include <QGroupBox> #include <QCheckBox> #include <QLabel> #include <QHBoxLayout> #include <KCompletion/KComboBox> #include <KShellCompletion> #include "filterbase.h" #include "../Dialogs/kurllistrequester.h" #include "../GUI/profilemanager.h" #include "../GUI/krlistwidget.h" #include "../GUI/krhistorycombobox.h" class GeneralFilter : public QWidget, public FilterBase { Q_OBJECT public: GeneralFilter(FilterTabs *tabs, int properties, QWidget *parent = nullptr, QStringList extraOptions = QStringList()); ~GeneralFilter() override; void queryAccepted() override; QString name() override { return "GeneralFilter"; } FilterTabs * filterTabs() override { return fltTabs; } bool getSettings(FilterSettings&) override; void applySettings(const FilterSettings&) override; bool isExtraOptionChecked(const QString& name); void checkExtraOption(const QString& name, bool check); public slots: void slotAddBtnClicked(); void slotLoadBtnClicked(); void slotOverwriteBtnClicked(); void slotRemoveBtnClicked(); void slotDisable(); void slotRegExpTriggered(QAction * act); void slotProfileDoubleClicked(QListWidgetItem *); void refreshProfileListBox(); public: KComboBox* contentEncoding; QCheckBox* searchForCase; QCheckBox* containsTextCase; QCheckBox* containsWholeWord; QCheckBox* useExcludeFolderNames; QCheckBox* searchInDirs; QCheckBox* searchInArchives; QCheckBox* followLinks; QHash<QString, QCheckBox*> extraOptions; KURLListRequester *searchIn; KURLListRequester *dontSearchIn; QLayout *middleLayout; - KrHistoryComboBox* searchFor; + KrHistoryComboBox *searchFor; KrHistoryComboBox *containsText; KrHistoryComboBox *excludeFolderNames; - QToolButton* containsRegExp; + QToolButton *containsRegExp; - KComboBox* ofType; + KComboBox *ofType; QLabel *encLabel; QLabel *containsLabel; KShellCompletion completion; KrListWidget *profileListBox; QPushButton *profileAddBtn; QPushButton *profileLoadBtn; QPushButton *profileOverwriteBtn; QPushButton *profileRemoveBtn; ProfileManager *profileManager; int properties; FilterTabs *fltTabs; private: QCheckBox *createExcludeCheckBox(const KConfigGroup &group); KrHistoryComboBox *createExcludeComboBox(const KConfigGroup &group); }; #endif /* GENERALFILTER_H */