KDirStat – a graphical disk usage utility
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kcleanup.cpp 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*
  2. * File name: kcleanup.cpp
  3. * Summary: Support classes for KDirStat
  4. * License: LGPL - See file COPYING.LIB for details.
  5. * Author: Stefan Hundhammer <sh@suse.de>
  6. *
  7. * Updated: 2004-11-23
  8. */
  9. #include <stdlib.h>
  10. #include <tqapplication.h>
  11. #include <tqregexp.h>
  12. #include <kapp.h>
  13. #include <kprocess.h>
  14. #include <kdebug.h>
  15. #include <tdemessagebox.h>
  16. #include <tdelocale.h>
  17. #include <tdeglobalsettings.h>
  18. #include "kcleanup.h"
  19. #include "kdirsaver.h"
  20. #define VERBOSE_RUN_COMMAND 1
  21. #define SIMULATE_COMMAND 0
  22. using namespace KDirStat;
  23. KCleanup::KCleanup( TQString id,
  24. TQString command,
  25. TQString title,
  26. TDEActionCollection * parent )
  27. : TDEAction( title,
  28. 0, // accel
  29. parent,
  30. id )
  31. , _id ( id )
  32. , _command ( command )
  33. , _title ( title )
  34. {
  35. _selection = 0;
  36. _enabled = true;
  37. _worksForDir = true;
  38. _worksForFile = false;
  39. _worksForDotEntry = false;
  40. _worksLocalOnly = true;
  41. _recurse = false;
  42. _askForConfirmation = false;
  43. _refreshPolicy = noRefresh;
  44. TDEAction::setEnabled( false );
  45. }
  46. KCleanup::KCleanup( const KCleanup &src )
  47. : TDEAction()
  48. {
  49. copy( src );
  50. }
  51. KCleanup &
  52. KCleanup::operator= ( const KCleanup &src )
  53. {
  54. copy( src );
  55. return *this;
  56. }
  57. void
  58. KCleanup::copy( const KCleanup &src )
  59. {
  60. setTitle( src.title() );
  61. _selection = src.selection();
  62. _id = src.id();
  63. _command = src.command();
  64. _enabled = src.enabled();
  65. _worksForDir = src.worksForDir();
  66. _worksForFile = src.worksForFile();
  67. _worksForDotEntry = src.worksForDotEntry();
  68. _worksLocalOnly = src.worksLocalOnly();
  69. _recurse = src.recurse();
  70. _askForConfirmation = src.askForConfirmation();
  71. _refreshPolicy = src.refreshPolicy();
  72. }
  73. void
  74. KCleanup::setTitle( const TQString &title )
  75. {
  76. _title = title;
  77. TDEAction::setText( _title );
  78. }
  79. bool
  80. KCleanup::worksFor( KFileInfo *item ) const
  81. {
  82. if ( ! _enabled || ! item )
  83. return false;
  84. if ( worksLocalOnly() && ! item->tree()->isFileProtocol() )
  85. return false;
  86. if ( item->isDotEntry() ) return worksForDotEntry();
  87. if ( item->isDir() ) return worksForDir();
  88. return worksForFile();
  89. }
  90. void
  91. KCleanup::selectionChanged( KFileInfo *selection )
  92. {
  93. bool enabled = false;
  94. _selection = selection;
  95. if ( selection )
  96. {
  97. enabled = worksFor( selection );
  98. if ( ! selection->isFinished() )
  99. {
  100. // This subtree isn't finished reading yet
  101. switch ( _refreshPolicy )
  102. {
  103. // Refresh policies that would cause this subtree to be deleted
  104. case refreshThis:
  105. case refreshParent:
  106. case assumeDeleted:
  107. // Prevent premature deletion of this tree - this would
  108. // cause a core dump for sure.
  109. enabled = false;
  110. break;
  111. default:
  112. break;
  113. }
  114. }
  115. }
  116. TDEAction::setEnabled( enabled );
  117. }
  118. void
  119. KCleanup::executeWithSelection()
  120. {
  121. if ( _selection )
  122. execute( _selection );
  123. }
  124. bool
  125. KCleanup::confirmation( KFileInfo * item )
  126. {
  127. TQString msg;
  128. if ( item->isDir() || item->isDotEntry() )
  129. {
  130. msg = i18n( "%1\nin directory %2" ).arg( cleanTitle() ).arg( item->url() );
  131. }
  132. else
  133. {
  134. msg = i18n( "%1\nfor file %2" ).arg( cleanTitle() ).arg( item->url() );
  135. }
  136. if ( KMessageBox::warningContinueCancel( 0, // parentWidget
  137. msg, // message
  138. i18n( "Please Confirm" ), // caption
  139. i18n( "Confirm" ) // confirmButtonLabel
  140. ) == KMessageBox::Continue )
  141. return true;
  142. else
  143. return false;
  144. }
  145. void
  146. KCleanup::execute( KFileInfo *item )
  147. {
  148. if ( worksFor( item ) )
  149. {
  150. if ( _askForConfirmation && ! confirmation( item ) )
  151. return;
  152. KDirTree * tree = item->tree();
  153. executeRecursive( item );
  154. switch ( _refreshPolicy )
  155. {
  156. case noRefresh:
  157. // Do nothing.
  158. break;
  159. case refreshThis:
  160. tree->refresh( item );
  161. break;
  162. case refreshParent:
  163. tree->refresh( item->parent() );
  164. break;
  165. case assumeDeleted:
  166. // Assume the cleanup action has deleted the item.
  167. // Modify the KDirTree accordingly.
  168. tree->deleteSubtree( item );
  169. // Don't try to figure out a reasonable next selection - the
  170. // views have to do that while handling the subtree
  171. // deletion. Only the views have any knowledge about a
  172. // reasonable strategy for choosing a next selection. Unlike
  173. // the view items, the KFileInfo items don't have an order that
  174. // makes any sense to the user.
  175. break;
  176. }
  177. }
  178. emit executed();
  179. }
  180. void
  181. KCleanup::executeRecursive( KFileInfo *item )
  182. {
  183. if ( worksFor( item ) )
  184. {
  185. if ( _recurse )
  186. {
  187. // Recurse into all subdirectories.
  188. KFileInfo * subdir = item->firstChild();
  189. while ( subdir )
  190. {
  191. if ( subdir->isDir() )
  192. {
  193. /**
  194. * Recursively execute in this subdirectory, but only if it
  195. * really is a directory: File children might have been
  196. * reparented to the directory (normally, they reside in
  197. * the dot entry) if there are no real subdirectories on
  198. * this directory level.
  199. **/
  200. executeRecursive( subdir );
  201. }
  202. subdir = subdir->next();
  203. }
  204. }
  205. // Perform cleanup for this directory.
  206. runCommand( item, _command );
  207. }
  208. }
  209. const TQString
  210. KCleanup::itemDir( const KFileInfo *item ) const
  211. {
  212. TQString dir = item->url();
  213. if ( ! item->isDir() && ! item->isDotEntry() )
  214. {
  215. dir.replace ( TQRegExp ( "/[^/]*$" ), "" );
  216. }
  217. return dir;
  218. }
  219. TQString
  220. KCleanup::cleanTitle() const
  221. {
  222. // Use the cleanup action's title, if possible.
  223. TQString title = _title;
  224. if ( title.isEmpty() )
  225. {
  226. title = _id;
  227. }
  228. // Get rid of any "&" characters in the text that denote keyboard
  229. // shortcuts in menus.
  230. title.replace( TQRegExp( "&" ), "" );
  231. return title;
  232. }
  233. TQString
  234. KCleanup::expandVariables( const KFileInfo * item,
  235. const TQString & unexpanded ) const
  236. {
  237. TQString expanded = unexpanded;
  238. expanded.replace( TQRegExp( "%p" ),
  239. "\"" + TQString::fromLocal8Bit( item->url() ) + "\"" );
  240. expanded.replace( TQRegExp( "%n" ),
  241. "\"" + TQString::fromLocal8Bit( item->name() ) + "\"" );
  242. if ( KDE::versionMajor() >= 3 && KDE::versionMinor() >= 4 )
  243. expanded.replace( TQRegExp( "%t" ), "trash:/" );
  244. else
  245. expanded.replace( TQRegExp( "%t" ), TDEGlobalSettings::trashPath() );
  246. return expanded;
  247. }
  248. #include <tqtextcodec.h>
  249. void
  250. KCleanup::runCommand ( const KFileInfo * item,
  251. const TQString & command ) const
  252. {
  253. TDEProcess proc;
  254. KDirSaver dir( itemDir( item ) );
  255. TQString cmd( expandVariables( item, command ));
  256. #if VERBOSE_RUN_COMMAND
  257. printf( "\ncd " );
  258. fflush( stdout );
  259. system( "pwd" );
  260. TQTextCodec * codec = TQTextCodec::codecForLocale();
  261. printf( "%s\n", (const char *) codec->fromUnicode( cmd ) );
  262. fflush( stdout );
  263. #endif
  264. #if ! SIMULATE_COMMAND
  265. proc << "sh";
  266. proc << "-c";
  267. proc << cmd;
  268. switch ( _refreshPolicy )
  269. {
  270. case noRefresh:
  271. case assumeDeleted:
  272. // In either case it is no use waiting for the command to
  273. // finish, so we are starting the command as a pure
  274. // background process.
  275. proc.start( TDEProcess::DontCare );
  276. break;
  277. case refreshThis:
  278. case refreshParent:
  279. // If a display refresh is due after the command, we need to
  280. // wait for the command to be finished in order to avoid
  281. // performing the update prematurely, so we are starting this
  282. // process in blocking mode.
  283. TQApplication::setOverrideCursor( waitCursor );
  284. proc.start( TDEProcess::Block );
  285. TQApplication::restoreOverrideCursor();
  286. break;
  287. }
  288. #endif
  289. }
  290. void
  291. KCleanup::readConfig()
  292. {
  293. TDEConfig *config = kapp->config();
  294. TDEConfigGroupSaver saver( config, _id );
  295. bool valid = config->readBoolEntry( "valid", false );
  296. // If the config section requested exists, it should contain a
  297. // "valid" field with a true value. If not, there is no such
  298. // section within the config file. In this case, just leave this
  299. // cleanup action undisturbed - we'd rather have a good default
  300. // value (as provided - hopefully - by our application upon
  301. // startup) than a generic empty cleanup action.
  302. if ( valid )
  303. {
  304. _command = config->readEntry ( "command" );
  305. _enabled = config->readBoolEntry ( "enabled" );
  306. _worksForDir = config->readBoolEntry ( "worksForDir" );
  307. _worksForFile = config->readBoolEntry ( "worksForFile" );
  308. _worksForDotEntry = config->readBoolEntry ( "worksForDotEntry" );
  309. _worksLocalOnly = config->readBoolEntry ( "worksLocalOnly" );
  310. _recurse = config->readBoolEntry ( "recurse" , false );
  311. _askForConfirmation = config->readBoolEntry ( "askForConfirmation" , false );
  312. _refreshPolicy = (KCleanup::RefreshPolicy) config->readNumEntry( "refreshPolicy" );
  313. setTitle( config->readEntry( "title" ) );
  314. }
  315. }
  316. void
  317. KCleanup::saveConfig() const
  318. {
  319. TDEConfig *config = kapp->config();
  320. TDEConfigGroupSaver saver( config, _id );
  321. config->writeEntry( "valid", true );
  322. config->writeEntry( "command", _command );
  323. config->writeEntry( "title", _title );
  324. config->writeEntry( "enabled", _enabled );
  325. config->writeEntry( "worksForDir", _worksForDir );
  326. config->writeEntry( "worksForFile", _worksForFile );
  327. config->writeEntry( "worksForDotEntry", _worksForDotEntry );
  328. config->writeEntry( "worksLocalOnly", _worksLocalOnly );
  329. config->writeEntry( "recurse", _recurse );
  330. config->writeEntry( "askForConfirmation", _askForConfirmation );
  331. config->writeEntry( "refreshPolicy", (int) _refreshPolicy );
  332. }
  333. #include "kcleanup.moc"
  334. // EOF