PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/gnome-commander-1.2.8.15/src/gnome-cmd-file-list.cc

#
C++ | 2286 lines | 1644 code | 559 blank | 83 comment | 323 complexity | 27cae00865c551ce32bdea3728aef19c MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. GNOME Commander - A GNOME based file manager
  3. Copyright (C) 2001-2006 Marcus Bjurman
  4. Copyright (C) 2007-2011 Piotr Eljasiak
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  16. */
  17. #include <config.h>
  18. #include <regex.h>
  19. #include "gnome-cmd-includes.h"
  20. #include "gnome-cmd-file-selector.h"
  21. #include "gnome-cmd-file-list.h"
  22. #include "gnome-cmd-file.h"
  23. #include "gnome-cmd-main-win.h"
  24. #include "utils.h"
  25. #include "gnome-cmd-data.h"
  26. #include "gnome-cmd-patternsel-dialog.h"
  27. #include "imageloader.h"
  28. #include "cap.h"
  29. #include "gnome-cmd-style.h"
  30. #include "gnome-cmd-file-popmenu.h"
  31. #include "gnome-cmd-rename-dialog.h"
  32. #include "gnome-cmd-chown-dialog.h"
  33. #include "gnome-cmd-chmod-dialog.h"
  34. #include "gnome-cmd-delete-dialog.h"
  35. #include "gnome-cmd-quicksearch-popup.h"
  36. #include "gnome-cmd-file-collection.h"
  37. #include "gnome-cmd-user-actions.h"
  38. #include "ls_colors.h"
  39. using namespace std;
  40. /* Controls if file-uris should be escaped for local files when drag-N-dropping
  41. * Setting this seems be more portable when dropping on old file-managers as gmc etc.
  42. */
  43. #define UNESCAPE_LOCAL_FILES
  44. /* The time (in ms) it takes from that the right mouse button is clicked on a file until
  45. * the popup menu appears when the right btn is used to select files.
  46. */
  47. #define POPUP_TIMEOUT 750
  48. enum
  49. {
  50. FILE_CLICKED, // A file in the list was clicked
  51. FILE_RELEASED, // A file in the list has been clicked and mouse button has been released
  52. LIST_CLICKED, // The file list widget was clicked
  53. EMPTY_SPACE_CLICKED, // The file list was clicked but not on a file
  54. FILES_CHANGED, // The visible content of the file list has changed (files have been: selected, created, deleted or modified)
  55. DIR_CHANGED, // The current directory has been changed
  56. LAST_SIGNAL
  57. };
  58. GtkTargetEntry drag_types [] = {
  59. { TARGET_URI_LIST_TYPE, 0, TARGET_URI_LIST },
  60. { TARGET_TEXT_PLAIN_TYPE, 0, TARGET_TEXT_PLAIN },
  61. { TARGET_URL_TYPE, 0, TARGET_URL }
  62. };
  63. static GnomeCmdCListClass *parent_class = NULL;
  64. static guint file_list_signals[LAST_SIGNAL] = { 0 };
  65. struct GnomeCmdFileListColumn
  66. {
  67. guint id;
  68. const gchar *title;
  69. guint default_width;
  70. GtkJustification justification;
  71. GtkSortType default_sort_direction;
  72. GCompareDataFunc sort_func;
  73. };
  74. static gint sort_by_name (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl);
  75. static gint sort_by_ext (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl);
  76. static gint sort_by_dir (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl);
  77. static gint sort_by_size (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl);
  78. static gint sort_by_date (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl);
  79. static gint sort_by_perm (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl);
  80. static gint sort_by_owner (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl);
  81. static gint sort_by_group (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl);
  82. GnomeCmdFileListColumn file_list_column[GnomeCmdFileList::NUM_COLUMNS] =
  83. {{GnomeCmdFileList::COLUMN_ICON,"",16,GTK_JUSTIFY_CENTER,GTK_SORT_ASCENDING, NULL},
  84. {GnomeCmdFileList::COLUMN_NAME, N_("name"), 140, GTK_JUSTIFY_LEFT, GTK_SORT_ASCENDING, (GCompareDataFunc) sort_by_name},
  85. {GnomeCmdFileList::COLUMN_EXT, N_("ext"), 40, GTK_JUSTIFY_LEFT, GTK_SORT_ASCENDING, (GCompareDataFunc) sort_by_ext},
  86. {GnomeCmdFileList::COLUMN_DIR, N_("dir"), 240, GTK_JUSTIFY_LEFT, GTK_SORT_ASCENDING, (GCompareDataFunc) sort_by_dir},
  87. {GnomeCmdFileList::COLUMN_SIZE, N_("size"), 70, GTK_JUSTIFY_RIGHT, GTK_SORT_DESCENDING, (GCompareDataFunc) sort_by_size},
  88. {GnomeCmdFileList::COLUMN_DATE, N_("date"), 150, GTK_JUSTIFY_LEFT, GTK_SORT_DESCENDING, (GCompareDataFunc) sort_by_date},
  89. {GnomeCmdFileList::COLUMN_PERM, N_("perm"), 70, GTK_JUSTIFY_LEFT, GTK_SORT_ASCENDING, (GCompareDataFunc) sort_by_perm},
  90. {GnomeCmdFileList::COLUMN_OWNER, N_("uid"), 50, GTK_JUSTIFY_LEFT, GTK_SORT_ASCENDING, (GCompareDataFunc) sort_by_owner},
  91. {GnomeCmdFileList::COLUMN_GROUP, N_("gid"), 50, GTK_JUSTIFY_LEFT, GTK_SORT_ASCENDING, (GCompareDataFunc) sort_by_group}};
  92. class GnomeCmdFileList::Private
  93. {
  94. public:
  95. GtkWidget *column_pixmaps[GnomeCmdFileList::NUM_COLUMNS];
  96. GtkWidget *column_labels[GnomeCmdFileList::NUM_COLUMNS];
  97. GtkWidget *popup_menu;
  98. gint cur_file;
  99. GnomeCmdFileCollection visible_files;
  100. GList *selected_files; // contains GnomeCmdFile pointers
  101. GCompareDataFunc sort_func;
  102. gint current_col;
  103. gboolean sort_raising[GnomeCmdFileList::NUM_COLUMNS];
  104. gboolean shift_down;
  105. gint shift_down_row;
  106. GnomeCmdFile *right_mb_down_file;
  107. gboolean right_mb_sel_state;
  108. guint right_mb_timeout_id;
  109. GtkWidget *selpat_dialog;
  110. GtkWidget *quicksearch_popup;
  111. gchar *focus_later;
  112. Private(GnomeCmdFileList *fl);
  113. ~Private();
  114. };
  115. GnomeCmdFileList::Private::Private(GnomeCmdFileList *fl)
  116. {
  117. selected_files = NULL;
  118. memset(column_pixmaps, NULL, sizeof(column_pixmaps));
  119. memset(column_labels, NULL, sizeof(column_labels));
  120. popup_menu = NULL;
  121. quicksearch_popup = NULL;
  122. selpat_dialog = NULL;
  123. focus_later = NULL;
  124. shift_down = FALSE;
  125. shift_down_row = 0;
  126. right_mb_sel_state = FALSE;
  127. right_mb_down_file = NULL;
  128. right_mb_timeout_id = 0;
  129. memset(sort_raising, FALSE, sizeof(sort_raising));
  130. gint col = COLUMN_NAME; // defaults,
  131. gboolean b = GTK_SORT_ASCENDING; // used when not set by gnome_cmd_data_get_sort_params()
  132. gnome_cmd_data_get_sort_params (fl, col, b);
  133. current_col = col;
  134. sort_raising[col] = b;
  135. sort_func = file_list_column[col].sort_func;
  136. for (gint i=0; i<NUM_COLUMNS; i++)
  137. gtk_clist_set_column_resizeable (*fl, i, TRUE);
  138. }
  139. GnomeCmdFileList::Private::~Private()
  140. {
  141. gnome_cmd_file_list_free (selected_files);
  142. }
  143. inline gchar *strip_extension (const gchar *fname)
  144. {
  145. gchar *s = g_strdup (fname);
  146. gchar *p = g_strrstr (s, ".");
  147. if (p && p != s)
  148. *p = '\0';
  149. return s;
  150. }
  151. struct FileFormatData
  152. {
  153. gchar *text[GnomeCmdFileList::NUM_COLUMNS];
  154. gchar *dpath;
  155. gchar *fname;
  156. gchar *fext;
  157. static gchar empty_string[];
  158. FileFormatData(GnomeCmdFile *f, gboolean tree_size);
  159. ~FileFormatData();
  160. };
  161. gchar FileFormatData::empty_string[] = "";
  162. inline FileFormatData::FileFormatData(GnomeCmdFile *f, gboolean tree_size)
  163. {
  164. // If the user wants a character instead of icon for filetype set it now
  165. if (gnome_cmd_data.layout == GNOME_CMD_LAYOUT_TEXT)
  166. text[GnomeCmdFileList::COLUMN_ICON] = (gchar *) gnome_cmd_file_get_type_string (f);
  167. else
  168. text[GnomeCmdFileList::COLUMN_ICON] = NULL;
  169. // Prepare the strings to show
  170. gchar *t1 = gnome_cmd_file_get_path (f);
  171. gchar *t2 = g_path_get_dirname (t1);
  172. dpath = get_utf8 (t2);
  173. g_free (t1);
  174. g_free (t2);
  175. if (gnome_cmd_data.ext_disp_mode == GNOME_CMD_EXT_DISP_STRIPPED
  176. && f->info->type == GNOME_VFS_FILE_TYPE_REGULAR)
  177. {
  178. gchar *t = strip_extension (gnome_cmd_file_get_name (f));
  179. fname = get_utf8 (t);
  180. g_free (t);
  181. }
  182. else
  183. fname = get_utf8 (gnome_cmd_file_get_name (f));
  184. if (gnome_cmd_data.ext_disp_mode != GNOME_CMD_EXT_DISP_WITH_FNAME)
  185. fext = get_utf8 (gnome_cmd_file_get_extension (f));
  186. else
  187. fext = NULL;
  188. //Set other file information
  189. text[GnomeCmdFileList::COLUMN_NAME] = fname;
  190. text[GnomeCmdFileList::COLUMN_EXT] = fext;
  191. text[GnomeCmdFileList::COLUMN_DIR] = dpath;
  192. text[GnomeCmdFileList::COLUMN_SIZE] = tree_size ? (gchar *) gnome_cmd_file_get_tree_size_as_str (f) :
  193. (gchar *) gnome_cmd_file_get_size (f);
  194. if (f->info->type != GNOME_VFS_FILE_TYPE_DIRECTORY || !f->is_dotdot)
  195. {
  196. text[GnomeCmdFileList::COLUMN_DATE] = (gchar *) gnome_cmd_file_get_mdate (f, FALSE);
  197. text[GnomeCmdFileList::COLUMN_PERM] = (gchar *) gnome_cmd_file_get_perm (f);
  198. text[GnomeCmdFileList::COLUMN_OWNER] = (gchar *) gnome_cmd_file_get_owner (f);
  199. text[GnomeCmdFileList::COLUMN_GROUP] = (gchar *) gnome_cmd_file_get_group (f);
  200. }
  201. else
  202. {
  203. text[GnomeCmdFileList::COLUMN_DATE] = empty_string;
  204. text[GnomeCmdFileList::COLUMN_PERM] = empty_string;
  205. text[GnomeCmdFileList::COLUMN_OWNER] = empty_string;
  206. text[GnomeCmdFileList::COLUMN_GROUP] = empty_string;
  207. }
  208. }
  209. inline FileFormatData::~FileFormatData()
  210. {
  211. g_free (dpath);
  212. g_free (fname);
  213. g_free (fext);
  214. }
  215. static void on_selpat_hide (GtkWidget *dialog, GnomeCmdFileList *fl)
  216. {
  217. fl->priv->selpat_dialog = NULL;
  218. }
  219. inline void show_selpat_dialog (GnomeCmdFileList *fl, gboolean mode)
  220. {
  221. if (fl->priv->selpat_dialog) return;
  222. GtkWidget *dialog = gnome_cmd_patternsel_dialog_new (fl, mode);
  223. gtk_widget_ref (dialog);
  224. gtk_signal_connect (GTK_OBJECT (dialog), "hide", GTK_SIGNAL_FUNC (on_selpat_hide), fl);
  225. gtk_widget_show (dialog);
  226. fl->priv->selpat_dialog = dialog;
  227. }
  228. // Given a GnomeFileList, returns the upper-left corner of the selected file
  229. static void get_focus_row_coordinates (GnomeCmdFileList *fl, gint &x, gint &y, gint &width, gint &height)
  230. {
  231. #define CELL_SPACING 1
  232. #define COLUMN_INSET 3
  233. gint x0, y0;
  234. gdk_window_get_origin (GTK_CLIST (fl)->clist_window, &x0, &y0);
  235. gint row = GTK_CLIST (fl)->focus_row;
  236. gint rowh = GTK_CLIST (fl)->row_height + CELL_SPACING;
  237. gint colx = GTK_CLIST (fl)->column[GnomeCmdFileList::COLUMN_NAME].area.x - COLUMN_INSET - CELL_SPACING;
  238. x = x0 + colx;
  239. y = y0 + row*rowh + GTK_CLIST (fl)->voffset;
  240. width = GTK_CLIST (fl)->column[GnomeCmdFileList::COLUMN_NAME].area.width + 2*COLUMN_INSET;
  241. if (gnome_cmd_data.ext_disp_mode != GNOME_CMD_EXT_DISP_BOTH)
  242. width += GTK_CLIST (fl)->column[GnomeCmdFileList::COLUMN_EXT].area.width + 2*COLUMN_INSET + CELL_SPACING;
  243. height = rowh + 2*CELL_SPACING;
  244. }
  245. inline void focus_file_at_row (GnomeCmdFileList *fl, gint row)
  246. {
  247. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  248. GTK_CLIST (fl)->focus_row = row;
  249. gtk_clist_select_row (*fl, row, 0);
  250. fl->priv->cur_file = GTK_CLIST (fl)->focus_row;
  251. }
  252. static void on_quicksearch_popup_hide (GtkWidget *quicksearch_popup, GnomeCmdFileList *fl)
  253. {
  254. fl->priv->quicksearch_popup = NULL;
  255. }
  256. static void select_file (GnomeCmdFileList *fl, GnomeCmdFile *f)
  257. {
  258. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  259. g_return_if_fail (f != NULL);
  260. g_return_if_fail (f->info != NULL);
  261. if (f->is_dotdot)
  262. return;
  263. gint row = fl->get_row_from_file(f);
  264. if (row == -1)
  265. return;
  266. if (!gnome_cmd_data.use_ls_colors)
  267. gtk_clist_set_row_style (*fl, row, row%2 ? alt_sel_list_style : sel_list_style);
  268. else
  269. {
  270. GnomeCmdColorTheme *colors = gnome_cmd_data_get_current_color_theme ();
  271. if (!colors->respect_theme)
  272. {
  273. gtk_clist_set_foreground (*fl, row, colors->sel_fg);
  274. gtk_clist_set_background (*fl, row, colors->sel_bg);
  275. }
  276. }
  277. if (g_list_index (fl->priv->selected_files, f) != -1)
  278. return;
  279. gnome_cmd_file_ref (f);
  280. fl->priv->selected_files = g_list_append (fl->priv->selected_files, f);
  281. gtk_signal_emit (*fl, file_list_signals[FILES_CHANGED]);
  282. }
  283. static void unselect_file (GnomeCmdFileList *fl, GnomeCmdFile *f)
  284. {
  285. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  286. g_return_if_fail (f != NULL);
  287. gint row = fl->get_row_from_file(f);
  288. if (row == -1)
  289. return;
  290. if (g_list_index (fl->priv->selected_files, f) == -1)
  291. return;
  292. gnome_cmd_file_unref (f);
  293. fl->priv->selected_files = g_list_remove (fl->priv->selected_files, f);
  294. if (!gnome_cmd_data.use_ls_colors)
  295. gtk_clist_set_row_style (*fl, row, row%2 ? alt_list_style : list_style);
  296. else
  297. if (LsColor *col = ls_colors_get (f))
  298. {
  299. GnomeCmdColorTheme *colors = gnome_cmd_data_get_current_color_theme ();
  300. GdkColor *fg = col->fg ? col->fg : colors->norm_fg;
  301. GdkColor *bg = col->bg ? col->bg : colors->norm_bg;
  302. if (bg) gtk_clist_set_background (*fl, row, bg);
  303. if (fg) gtk_clist_set_foreground (*fl, row, fg);
  304. }
  305. gtk_signal_emit (*fl, file_list_signals[FILES_CHANGED]);
  306. }
  307. inline void toggle_file (GnomeCmdFileList *fl, GnomeCmdFile *f)
  308. {
  309. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  310. g_return_if_fail (f != NULL);
  311. gint row = fl->get_row_from_file(f);
  312. if (row == -1)
  313. return;
  314. if (row < fl->priv->visible_files.size())
  315. if (g_list_index (fl->priv->selected_files, f) == -1)
  316. select_file (fl, f);
  317. else
  318. unselect_file (fl, f);
  319. }
  320. inline void select_file_at_row (GnomeCmdFileList *fl, gint row)
  321. {
  322. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  323. fl->priv->cur_file = row;
  324. GnomeCmdFile *f = fl->get_file_at_row(row);
  325. if (f)
  326. select_file (fl, f);
  327. }
  328. inline void select_file_range (GnomeCmdFileList *fl, gint start_row, gint end_row)
  329. {
  330. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  331. if (start_row > end_row)
  332. {
  333. gint i = start_row;
  334. start_row = end_row;
  335. end_row = i;
  336. }
  337. for (gint i=start_row; i<=end_row; i++)
  338. select_file_at_row (fl, i);
  339. }
  340. inline void toggle_file_at_row (GnomeCmdFileList *fl, gint row)
  341. {
  342. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  343. fl->priv->cur_file = row;
  344. GnomeCmdFile *f = fl->get_file_at_row(row);
  345. if (f)
  346. toggle_file (fl, f);
  347. }
  348. inline void toggle_file_range (GnomeCmdFileList *fl, gint start_row, gint end_row)
  349. {
  350. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  351. if (start_row > end_row)
  352. {
  353. gint i = start_row;
  354. start_row = end_row;
  355. end_row = i;
  356. }
  357. for (gint i=start_row; i<=end_row; i++)
  358. toggle_file_at_row (fl, i);
  359. }
  360. static void toggle_files_with_same_extension (GnomeCmdFileList *fl, gboolean select)
  361. {
  362. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  363. GnomeCmdFile *f = fl->get_selected_file();
  364. if (!f) return;
  365. const gchar *ext1 = gnome_cmd_file_get_extension (f);
  366. if (!ext1) return;
  367. for (GList *tmp=fl->get_visible_files(); tmp; tmp=tmp->next)
  368. {
  369. GnomeCmdFile *f = (GnomeCmdFile *) tmp->data;
  370. if (f && f->info)
  371. {
  372. const gchar *ext2 = gnome_cmd_file_get_extension (f);
  373. if (ext2 && strcmp (ext1, ext2) == 0)
  374. {
  375. if (select)
  376. select_file (fl, f);
  377. else
  378. unselect_file (fl, f);
  379. }
  380. }
  381. }
  382. }
  383. inline void toggle_with_pattern (GnomeCmdFileList *fl, const gchar *pattern, gboolean case_sens, gboolean mode)
  384. {
  385. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  386. Filter filter(pattern, case_sens, gnome_cmd_data.filter_type);
  387. for (GList *tmp=fl->get_visible_files(); tmp; tmp=tmp->next)
  388. {
  389. GnomeCmdFile *f = (GnomeCmdFile *) tmp->data;
  390. if (f && f->info)
  391. if (filter.match(f->info->name))
  392. {
  393. if (mode)
  394. select_file (fl, f);
  395. else
  396. unselect_file (fl, f);
  397. }
  398. }
  399. }
  400. void GnomeCmdFileList::create_column_titles()
  401. {
  402. gtk_clist_column_title_passive (*this, COLUMN_ICON);
  403. for (gint i=COLUMN_NAME; i<NUM_COLUMNS; i++)
  404. {
  405. GtkWidget *hbox, *pixmap;
  406. GdkPixmap *pm = IMAGE_get_pixmap (PIXMAP_FLIST_ARROW_BLANK);
  407. GdkBitmap *bm = IMAGE_get_mask (PIXMAP_FLIST_ARROW_BLANK);
  408. hbox = gtk_hbox_new (FALSE, 1);
  409. gtk_widget_ref (hbox);
  410. gtk_object_set_data_full (*this, "column-hbox", hbox, (GtkDestroyNotify) gtk_widget_unref);
  411. gtk_widget_show (hbox);
  412. priv->column_labels[i] = gtk_label_new (_(file_list_column[i].title));
  413. gtk_widget_ref (priv->column_labels[i]);
  414. gtk_object_set_data_full (*this, "column-label", priv->column_labels[i], (GtkDestroyNotify) gtk_widget_unref);
  415. gtk_widget_show (priv->column_labels[i]);
  416. gtk_box_pack_start (GTK_BOX (hbox), priv->column_labels[i], TRUE, TRUE, 0);
  417. pixmap = gtk_pixmap_new (pm, bm);
  418. gtk_widget_ref (pixmap);
  419. gtk_object_set_data_full (*this, "column-pixmap", pixmap, (GtkDestroyNotify) gtk_widget_unref);
  420. gtk_widget_show (pixmap);
  421. gtk_box_pack_start (GTK_BOX (hbox), pixmap, FALSE, FALSE, 0);
  422. priv->column_pixmaps[i] = pixmap;
  423. gtk_clist_set_column_widget (*this, i, hbox);
  424. }
  425. for (gint i=COLUMN_ICON; i<NUM_COLUMNS; i++)
  426. {
  427. gtk_clist_set_column_width (*this, i, gnome_cmd_data.fs_col_width[i]);
  428. gtk_clist_set_column_justification (*this, i, file_list_column[i].justification);
  429. }
  430. gtk_clist_column_titles_show (*this);
  431. }
  432. static void update_column_sort_arrows (GnomeCmdFileList *fl)
  433. {
  434. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  435. for (gint i=GnomeCmdFileList::COLUMN_NAME; i<GnomeCmdFileList::NUM_COLUMNS; i++)
  436. {
  437. if (i != fl->priv->current_col)
  438. gtk_pixmap_set (GTK_PIXMAP (fl->priv->column_pixmaps[i]),
  439. IMAGE_get_pixmap (PIXMAP_FLIST_ARROW_BLANK),
  440. IMAGE_get_mask (PIXMAP_FLIST_ARROW_BLANK));
  441. else
  442. if (fl->priv->sort_raising[i])
  443. gtk_pixmap_set (GTK_PIXMAP (fl->priv->column_pixmaps[i]),
  444. IMAGE_get_pixmap (PIXMAP_FLIST_ARROW_UP),
  445. IMAGE_get_mask (PIXMAP_FLIST_ARROW_UP));
  446. else
  447. gtk_pixmap_set (GTK_PIXMAP (fl->priv->column_pixmaps[i]),
  448. IMAGE_get_pixmap (PIXMAP_FLIST_ARROW_DOWN),
  449. IMAGE_get_mask (PIXMAP_FLIST_ARROW_DOWN));
  450. }
  451. }
  452. /******************************************************
  453. * DnD functions
  454. **/
  455. static char *build_selected_file_list (GnomeCmdFileList *fl, int *file_list_len)
  456. {
  457. GList *sel_files = fl->get_selected_files();
  458. int listlen = g_list_length (sel_files);
  459. if (listlen > 1)
  460. {
  461. int total_len = 0;
  462. GList *uri_str_list = NULL;
  463. // create a list with the uri's of the selected files and calculate the total_length needed
  464. for (GList *tmp=sel_files; tmp; tmp=tmp->next)
  465. {
  466. GnomeCmdFile *f = (GnomeCmdFile *) tmp->data;
  467. const gchar *fn = NULL;
  468. gchar *uri_str;
  469. if (gnome_vfs_uri_is_local (gnome_cmd_file_get_uri (f)))
  470. {
  471. #ifdef UNESCAPE_LOCAL_FILES
  472. fn = gnome_vfs_unescape_string (gnome_cmd_file_get_uri_str (f), 0);
  473. #endif
  474. }
  475. if (!fn)
  476. fn = gnome_cmd_file_get_uri_str (f);
  477. uri_str = g_strdup_printf ("%s\r\n", fn);
  478. uri_str_list = g_list_append (uri_str_list, uri_str);
  479. total_len += strlen (uri_str);
  480. }
  481. // allocate memory
  482. total_len++;
  483. char *data, *copy;
  484. data = copy = (gchar *) g_malloc (total_len+1);
  485. // put the uri_str_list in the allocated memory
  486. for (GList *tmp=uri_str_list; tmp; tmp=tmp->next)
  487. {
  488. gchar *uri_str = (gchar *) tmp->data;
  489. strcpy (copy, uri_str);
  490. copy += strlen (uri_str);
  491. }
  492. g_list_foreach (uri_str_list, (GFunc) g_free, NULL);
  493. g_list_free (uri_str_list);
  494. data [total_len] = '\0';
  495. *file_list_len = total_len;
  496. return data;
  497. }
  498. else
  499. if (listlen == 1)
  500. {
  501. GnomeCmdFile *f = (GnomeCmdFile *) sel_files->data;
  502. char *uri_str = g_strdup (gnome_cmd_file_get_uri_str (f));
  503. *file_list_len = strlen (uri_str) + 1;
  504. return uri_str;
  505. }
  506. *file_list_len = 0;
  507. g_list_free (sel_files);
  508. return NULL;
  509. }
  510. static void drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint32 time, GnomeCmdFileList *fl)
  511. {
  512. int len;
  513. GList *files;
  514. gchar *data = (gchar *) build_selected_file_list (fl, &len);
  515. if (!data) return;
  516. switch (info)
  517. {
  518. case TARGET_URI_LIST:
  519. case TARGET_TEXT_PLAIN:
  520. gtk_selection_data_set (selection_data, selection_data->target, 8, (const guchar *) data, len);
  521. break;
  522. case TARGET_URL:
  523. files = gnome_vfs_uri_list_parse (data);
  524. if (files)
  525. gtk_selection_data_set (selection_data, selection_data->target, 8, (const guchar *) files->data, strlen ((const char *) files->data));
  526. g_list_foreach (files, (GFunc) g_free, NULL);
  527. break;
  528. default:
  529. g_assert_not_reached ();
  530. }
  531. g_free (data);
  532. }
  533. inline void init_dnd (GnomeCmdFileList *fl)
  534. {
  535. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  536. gtk_drag_source_set (*fl, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS (drag_types),
  537. (GdkDragAction) (GDK_ACTION_LINK | GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_DEFAULT));
  538. gtk_signal_connect (*fl, "drag-data-get", GTK_SIGNAL_FUNC (drag_data_get), fl);
  539. }
  540. static void popup_position_function (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
  541. {
  542. GnomeCmdFileList *fl = GNOME_CMD_FILE_LIST (user_data);
  543. gint unused_x, unused_w, unused_h;
  544. get_focus_row_coordinates (fl, unused_x, *y, unused_w, unused_h);
  545. }
  546. static void show_file_popup (GnomeCmdFileList *fl, GdkEventButton *event)
  547. {
  548. // create the popup menu
  549. GtkWidget *menu = gnome_cmd_file_popmenu_new (fl);
  550. if (!menu) return;
  551. gtk_widget_ref (menu);
  552. gtk_object_set_data_full (*fl, "file_popup_menu", menu, (GtkDestroyNotify) gtk_widget_unref);
  553. gnome_popup_menu_do_popup (menu, (GtkMenuPositionFunc) popup_position_function, fl, event, fl, NULL);
  554. }
  555. inline void show_file_popup_with_warp (GnomeCmdFileList *fl)
  556. {
  557. gint x, y, w, h;
  558. get_focus_row_coordinates (fl, x, y, w, h);
  559. //FIXME: Warp the pointer to x, y here
  560. show_file_popup (fl, NULL);
  561. }
  562. static gboolean on_right_mb_timeout (GnomeCmdFileList *fl)
  563. {
  564. GnomeCmdFile *focus_file = fl->get_focused_file();
  565. if (fl->priv->right_mb_down_file == focus_file)
  566. {
  567. select_file (fl, focus_file);
  568. show_file_popup (fl, NULL);
  569. return FALSE;
  570. }
  571. fl->priv->right_mb_down_file = focus_file;
  572. return TRUE;
  573. }
  574. /******************************************************
  575. * File sorting functions
  576. **/
  577. inline gint my_strcmp (const gchar *s1, const gchar *s2, gboolean raising)
  578. {
  579. int ret = strcmp (s1, s2);
  580. if (ret > 0)
  581. return raising ? -1 : 1;
  582. if (ret < 0)
  583. return raising ? 1 : -1;
  584. return ret;
  585. }
  586. inline gint my_intcmp (gint i1, gint i2, gboolean raising)
  587. {
  588. if (i1 > i2)
  589. return raising ? -1 : 1;
  590. if (i2 > i1)
  591. return raising ? 1 : -1;
  592. return 0;
  593. }
  594. inline gint my_filesizecmp (GnomeVFSFileSize i1, GnomeVFSFileSize i2, gboolean raising)
  595. {
  596. if (i1 > i2)
  597. return raising ? -1 : 1;
  598. if (i2 > i1)
  599. return raising ? 1 : -1;
  600. return 0;
  601. }
  602. static gint sort_by_name (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl)
  603. {
  604. if (f1->is_dotdot)
  605. return -1;
  606. if (f2->is_dotdot)
  607. return 1;
  608. if (f1->info->type > f2->info->type)
  609. return -1;
  610. if (f1->info->type < f2->info->type)
  611. return 1;
  612. gboolean raising = fl->priv->sort_raising[fl->priv->current_col];
  613. return my_strcmp (gnome_cmd_file_get_collation_fname (f1), gnome_cmd_file_get_collation_fname (f2), raising);
  614. }
  615. static gint sort_by_ext (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl)
  616. {
  617. if (f1->is_dotdot)
  618. return -1;
  619. if (f2->is_dotdot)
  620. return 1;
  621. if (f1->info->type > f2->info->type)
  622. return -1;
  623. if (f1->info->type < f2->info->type)
  624. return 1;
  625. gboolean raising = fl->priv->sort_raising[fl->priv->current_col];
  626. if (!gnome_cmd_file_get_extension (f1) && !gnome_cmd_file_get_extension (f2))
  627. return my_strcmp (gnome_cmd_file_get_collation_fname (f1), gnome_cmd_file_get_collation_fname (f2), fl->priv->sort_raising[1]);
  628. if (!gnome_cmd_file_get_extension (f1))
  629. return raising?1:-1;
  630. if (!gnome_cmd_file_get_extension (f2))
  631. return raising?-1:1;
  632. gint ret = my_strcmp (gnome_cmd_file_get_extension (f1), gnome_cmd_file_get_extension (f2), raising);
  633. return ret ? ret : my_strcmp (gnome_cmd_file_get_collation_fname (f1), gnome_cmd_file_get_collation_fname (f2), fl->priv->sort_raising[1]);
  634. }
  635. static gint sort_by_dir (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl)
  636. {
  637. if (f1->is_dotdot)
  638. return -1;
  639. if (f2->is_dotdot)
  640. return 1;
  641. if (f1->info->type > f2->info->type)
  642. return -1;
  643. if (f1->info->type < f2->info->type)
  644. return 1;
  645. // gchar *t1 = gnome_cmd_file_get_path (f1);
  646. // gchar *t2 = gnome_cmd_file_get_path (f2);
  647. // gchar *d1 = g_path_get_dirname (t1);
  648. // gchar *d2 = g_path_get_dirname (t2);
  649. gboolean raising = fl->priv->sort_raising[fl->priv->current_col];
  650. // gint ret = my_strcmp (d1, d2, raising);
  651. // g_free (t1);
  652. // g_free (t2);
  653. // g_free (d1);
  654. // g_free (d2);
  655. // return ret;
  656. return my_strcmp (gnome_cmd_file_get_collation_fname (f1), gnome_cmd_file_get_collation_fname (f2), raising);
  657. }
  658. static gint sort_by_size (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl)
  659. {
  660. if (f1->is_dotdot)
  661. return -1;
  662. if (f2->is_dotdot)
  663. return 1;
  664. gboolean raising = fl->priv->sort_raising[fl->priv->current_col];
  665. gboolean file_raising = fl->priv->sort_raising[1];
  666. gint ret = my_intcmp (f1->info->type, f2->info->type, TRUE);
  667. if (!ret)
  668. {
  669. ret = my_filesizecmp (f1->info->size, f2->info->size, raising);
  670. if (!ret)
  671. ret = my_strcmp (gnome_cmd_file_get_collation_fname (f1), gnome_cmd_file_get_collation_fname (f2), file_raising);
  672. }
  673. return ret;
  674. }
  675. static gint sort_by_perm (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl)
  676. {
  677. if (f1->is_dotdot)
  678. return -1;
  679. if (f2->is_dotdot)
  680. return 1;
  681. gboolean raising = fl->priv->sort_raising[fl->priv->current_col];
  682. gboolean file_raising = fl->priv->sort_raising[1];
  683. gint ret = my_intcmp (f1->info->type, f2->info->type, TRUE);
  684. if (!ret)
  685. {
  686. ret = my_intcmp (f1->info->permissions, f2->info->permissions, raising);
  687. if (!ret)
  688. ret = my_strcmp (gnome_cmd_file_get_collation_fname (f1), gnome_cmd_file_get_collation_fname (f2), file_raising);
  689. }
  690. return ret;
  691. }
  692. static gint sort_by_date (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl)
  693. {
  694. if (f1->is_dotdot)
  695. return -1;
  696. if (f2->is_dotdot)
  697. return 1;
  698. gboolean raising = fl->priv->sort_raising[fl->priv->current_col];
  699. gboolean file_raising = fl->priv->sort_raising[1];
  700. gint ret = my_intcmp (f1->info->type, f2->info->type, TRUE);
  701. if (!ret)
  702. {
  703. ret = my_intcmp (f1->info->mtime, f2->info->mtime, raising);
  704. if (!ret)
  705. ret = my_strcmp (gnome_cmd_file_get_collation_fname (f1), gnome_cmd_file_get_collation_fname (f2), file_raising);
  706. }
  707. return ret;
  708. }
  709. static gint sort_by_owner (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl)
  710. {
  711. if (f1->is_dotdot)
  712. return -1;
  713. if (f2->is_dotdot)
  714. return 1;
  715. gboolean raising = fl->priv->sort_raising[fl->priv->current_col];
  716. gboolean file_raising = fl->priv->sort_raising[1];
  717. gint ret = my_intcmp (f1->info->type, f2->info->type, TRUE);
  718. if (!ret)
  719. {
  720. ret = my_intcmp (f1->info->uid, f2->info->uid, raising);
  721. if (!ret)
  722. ret = my_strcmp (gnome_cmd_file_get_collation_fname (f1), gnome_cmd_file_get_collation_fname (f2), file_raising);
  723. }
  724. return ret;
  725. }
  726. static gint sort_by_group (GnomeCmdFile *f1, GnomeCmdFile *f2, GnomeCmdFileList *fl)
  727. {
  728. if (f1->is_dotdot)
  729. return -1;
  730. if (f2->is_dotdot)
  731. return 1;
  732. gboolean raising = fl->priv->sort_raising[fl->priv->current_col];
  733. gboolean file_raising = fl->priv->sort_raising[1];
  734. gint ret = my_intcmp (f1->info->type, f2->info->type, TRUE);
  735. if (!ret)
  736. {
  737. ret = my_intcmp (f1->info->gid, f2->info->gid, raising);
  738. if (!ret)
  739. ret = my_strcmp (gnome_cmd_file_get_collation_fname (f1), gnome_cmd_file_get_collation_fname (f2), file_raising);
  740. }
  741. return ret;
  742. }
  743. /*******************************
  744. * Callbacks
  745. *******************************/
  746. static void on_column_clicked (GtkCList *list, gint col, GnomeCmdFileList *fl)
  747. {
  748. g_return_if_fail (GTK_IS_CLIST (list));
  749. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  750. fl->priv->sort_raising[col] = fl->priv->current_col == col ? !fl->priv->sort_raising[col] :
  751. file_list_column[col].default_sort_direction;
  752. fl->priv->sort_func = file_list_column[col].sort_func;
  753. fl->priv->current_col = col;
  754. update_column_sort_arrows (fl);
  755. fl->sort();
  756. gnome_cmd_data_set_sort_params (fl, col, fl->priv->sort_raising[col]);
  757. }
  758. static void on_scroll_vertical (GtkCList *clist, GtkScrollType scroll_type, gfloat position, GnomeCmdFileList *fl)
  759. {
  760. g_return_if_fail (GTK_IS_CLIST (clist));
  761. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  762. gint num_files = fl->size();
  763. if (fl->priv->shift_down)
  764. {
  765. int start_row = fl->priv->cur_file;
  766. int end_row = clist->focus_row;
  767. fl->priv->shift_down = FALSE;
  768. if (start_row < 0 || end_row < 0)
  769. return;
  770. switch (scroll_type)
  771. {
  772. case GTK_SCROLL_STEP_BACKWARD:
  773. case GTK_SCROLL_STEP_FORWARD:
  774. toggle_file_at_row (fl, start_row);
  775. break;
  776. case GTK_SCROLL_PAGE_BACKWARD:
  777. toggle_file_range (fl, start_row, end_row);
  778. if (clist->focus_row > 0)
  779. focus_file_at_row (fl, --clist->focus_row);
  780. break;
  781. case GTK_SCROLL_PAGE_FORWARD:
  782. toggle_file_range (fl, start_row, end_row);
  783. if (clist->focus_row < num_files - 1)
  784. focus_file_at_row (fl, ++clist->focus_row);
  785. break;
  786. default:
  787. toggle_file_range (fl, start_row, end_row);
  788. break;
  789. }
  790. }
  791. fl->priv->cur_file = clist->focus_row;
  792. }
  793. static gboolean on_button_press (GtkCList *clist, GdkEventButton *event, GnomeCmdFileList *fl)
  794. {
  795. g_return_val_if_fail (clist != NULL, FALSE);
  796. g_return_val_if_fail (event != NULL, FALSE);
  797. g_return_val_if_fail (GNOME_CMD_IS_FILE_LIST (fl), FALSE);
  798. if (GTK_CLIST (fl)->clist_window != event->window)
  799. return FALSE;
  800. gtk_signal_emit (*fl, file_list_signals[LIST_CLICKED], event);
  801. gint row = gnome_cmd_clist_get_row (*fl, event->x, event->y);
  802. if (row < 0)
  803. {
  804. gtk_signal_emit (*fl, file_list_signals[EMPTY_SPACE_CLICKED], event);
  805. return FALSE;
  806. }
  807. GnomeCmdFile *f = fl->get_file_at_row(row);
  808. gtk_signal_emit (*fl, file_list_signals[FILE_CLICKED], f, event);
  809. gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "button-press-event");
  810. return TRUE;
  811. }
  812. inline gboolean mime_exec_file (GnomeCmdFile *f)
  813. {
  814. g_return_val_if_fail (GNOME_CMD_IS_FILE (f), FALSE);
  815. if (f->info->type == GNOME_VFS_FILE_TYPE_REGULAR)
  816. {
  817. mime_exec_single (f);
  818. return TRUE;
  819. }
  820. return FALSE;
  821. }
  822. static void on_file_clicked (GnomeCmdFileList *fl, GnomeCmdFile *f, GdkEventButton *event, gpointer data)
  823. {
  824. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  825. g_return_if_fail (f != NULL);
  826. g_return_if_fail (event != NULL);
  827. fl->modifier_click = event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK);
  828. if (event->type == GDK_2BUTTON_PRESS && event->button == 1 && gnome_cmd_data.left_mouse_button_mode == GnomeCmdData::LEFT_BUTTON_OPENS_WITH_DOUBLE_CLICK)
  829. {
  830. mime_exec_file (f);
  831. }
  832. else
  833. if (event->type == GDK_BUTTON_PRESS && (event->button == 1 || event->button == 3))
  834. {
  835. gint prev_row = fl->priv->cur_file;
  836. gint row = fl->get_row_from_file(f);
  837. fl->select_row(row);
  838. gtk_widget_grab_focus (*fl);
  839. if (event->button == 1)
  840. {
  841. if (event->state & GDK_SHIFT_MASK)
  842. {
  843. select_file_range (fl, fl->priv->shift_down_row, row);
  844. }
  845. else
  846. if (event->state & GDK_CONTROL_MASK)
  847. {
  848. if (fl->priv->selected_files || gnome_cmd_data.left_mouse_button_mode == GnomeCmdData::LEFT_BUTTON_OPENS_WITH_SINGLE_CLICK)
  849. toggle_file_at_row (fl, row);
  850. else
  851. {
  852. if (prev_row!=row)
  853. select_file (fl, fl->get_file_at_row(prev_row));
  854. select_file_at_row (fl, row);
  855. }
  856. }
  857. }
  858. else
  859. if (event->button == 3)
  860. if (!f->is_dotdot)
  861. {
  862. if (gnome_cmd_data.right_mouse_button_mode == GnomeCmdData::RIGHT_BUTTON_SELECTS)
  863. {
  864. if (g_list_index (fl->priv->selected_files, f) == -1)
  865. {
  866. select_file (fl, f);
  867. fl->priv->right_mb_sel_state = 1;
  868. }
  869. else
  870. {
  871. unselect_file (fl, f);
  872. fl->priv->right_mb_sel_state = 0;
  873. }
  874. fl->priv->right_mb_down_file = f;
  875. fl->priv->right_mb_timeout_id =
  876. g_timeout_add (POPUP_TIMEOUT, (GSourceFunc) on_right_mb_timeout, fl);
  877. }
  878. else
  879. show_file_popup (fl, event);
  880. }
  881. }
  882. }
  883. static void on_file_released (GnomeCmdFileList *fl, GnomeCmdFile *f, GdkEventButton *event, gpointer data)
  884. {
  885. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  886. g_return_if_fail (f != NULL);
  887. g_return_if_fail (event != NULL);
  888. if (event->type == GDK_BUTTON_RELEASE && event->button == 1 && !fl->modifier_click && gnome_cmd_data.left_mouse_button_mode == GnomeCmdData::LEFT_BUTTON_OPENS_WITH_SINGLE_CLICK)
  889. mime_exec_file (f);
  890. }
  891. static void on_motion_notify (GtkCList *clist, GdkEventMotion *event, GnomeCmdFileList *fl)
  892. {
  893. g_return_if_fail (event != NULL);
  894. if (event->state & GDK_BUTTON3_MASK)
  895. {
  896. gint row;
  897. gint y;
  898. y = event->y;
  899. y -= (clist->column_title_area.height - GTK_CONTAINER (clist)->border_width);
  900. row = gnome_cmd_clist_get_row (*fl, event->x, y);
  901. if (row != -1)
  902. {
  903. GnomeCmdFile *f = fl->get_file_at_row(row+1);
  904. if (f)
  905. {
  906. fl->select_row(row+1);
  907. if (fl->priv->right_mb_sel_state)
  908. select_file (fl, f);
  909. else
  910. unselect_file (fl, f);
  911. }
  912. }
  913. }
  914. }
  915. static gint on_button_release (GtkWidget *widget, GdkEventButton *event, GnomeCmdFileList *fl)
  916. {
  917. g_return_val_if_fail (widget != NULL, FALSE);
  918. g_return_val_if_fail (event != NULL, FALSE);
  919. g_return_val_if_fail (GNOME_CMD_IS_FILE_LIST (fl), FALSE);
  920. if (GTK_CLIST (fl)->clist_window != event->window)
  921. return FALSE;
  922. gint row = gnome_cmd_clist_get_row (*fl, event->x, event->y);
  923. if (row < 0)
  924. return FALSE;
  925. GnomeCmdFile *f = fl->get_file_at_row(row);
  926. gtk_signal_emit (*fl, file_list_signals[FILE_RELEASED], f, event);
  927. if (event->type == GDK_BUTTON_RELEASE)
  928. {
  929. if (event->button == 1 && state_is_blank (event->state))
  930. {
  931. if (f && g_list_index (fl->priv->selected_files, f)==-1 && gnome_cmd_data.left_mouse_button_unselects)
  932. fl->unselect_all();
  933. return TRUE;
  934. }
  935. else
  936. if (event->button == 3)
  937. g_source_remove (fl->priv->right_mb_timeout_id);
  938. }
  939. return FALSE;
  940. }
  941. static void on_realize (GnomeCmdFileList *fl, gpointer user_data)
  942. {
  943. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  944. update_column_sort_arrows (fl);
  945. fl->realized = TRUE;
  946. }
  947. /*******************************
  948. * Gtk class implementation
  949. *******************************/
  950. static void destroy (GtkObject *object)
  951. {
  952. GnomeCmdFileList *fl = GNOME_CMD_FILE_LIST (object);
  953. delete fl->priv;
  954. if (GTK_OBJECT_CLASS (parent_class)->destroy)
  955. (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
  956. }
  957. static void map (GtkWidget *widget)
  958. {
  959. if (GTK_WIDGET_CLASS (parent_class)->map != NULL)
  960. GTK_WIDGET_CLASS (parent_class)->map (widget);
  961. }
  962. static void class_init (GnomeCmdFileListClass *klass)
  963. {
  964. GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
  965. GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  966. parent_class = (GnomeCmdCListClass *) gtk_type_class (gnome_cmd_clist_get_type ());
  967. file_list_signals[FILE_CLICKED] =
  968. gtk_signal_new ("file-clicked",
  969. GTK_RUN_LAST,
  970. G_OBJECT_CLASS_TYPE (object_class),
  971. GTK_SIGNAL_OFFSET (GnomeCmdFileListClass, file_clicked),
  972. gtk_marshal_NONE__POINTER_POINTER,
  973. GTK_TYPE_NONE,
  974. 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
  975. file_list_signals[FILE_RELEASED] =
  976. gtk_signal_new ("file-released",
  977. GTK_RUN_LAST,
  978. G_OBJECT_CLASS_TYPE (object_class),
  979. GTK_SIGNAL_OFFSET (GnomeCmdFileListClass, file_released),
  980. gtk_marshal_NONE__POINTER_POINTER,
  981. GTK_TYPE_NONE,
  982. 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER);
  983. file_list_signals[LIST_CLICKED] =
  984. gtk_signal_new ("list-clicked",
  985. GTK_RUN_LAST,
  986. G_OBJECT_CLASS_TYPE (object_class),
  987. GTK_SIGNAL_OFFSET (GnomeCmdFileListClass, list_clicked),
  988. gtk_marshal_NONE__POINTER,
  989. GTK_TYPE_NONE,
  990. 1,
  991. GTK_TYPE_POINTER);
  992. file_list_signals[EMPTY_SPACE_CLICKED] =
  993. gtk_signal_new ("empty-space-clicked",
  994. GTK_RUN_LAST,
  995. G_OBJECT_CLASS_TYPE (object_class),
  996. GTK_SIGNAL_OFFSET (GnomeCmdFileListClass, empty_space_clicked),
  997. gtk_marshal_NONE__POINTER,
  998. GTK_TYPE_NONE,
  999. 1, GTK_TYPE_POINTER);
  1000. file_list_signals[FILES_CHANGED] =
  1001. gtk_signal_new ("files-changed",
  1002. GTK_RUN_LAST,
  1003. G_OBJECT_CLASS_TYPE (object_class),
  1004. GTK_SIGNAL_OFFSET (GnomeCmdFileListClass, files_changed),
  1005. gtk_marshal_NONE__NONE,
  1006. GTK_TYPE_NONE,
  1007. 0);
  1008. file_list_signals[DIR_CHANGED] =
  1009. gtk_signal_new ("dir-changed",
  1010. GTK_RUN_LAST,
  1011. G_OBJECT_CLASS_TYPE (object_class),
  1012. GTK_SIGNAL_OFFSET (GnomeCmdFileListClass, dir_changed),
  1013. gtk_marshal_NONE__POINTER,
  1014. GTK_TYPE_NONE,
  1015. 1, GTK_TYPE_POINTER);
  1016. object_class->destroy = destroy;
  1017. widget_class->map = ::map;
  1018. klass->file_clicked = NULL;
  1019. klass->file_released = NULL;
  1020. klass->list_clicked = NULL;
  1021. klass->files_changed = NULL;
  1022. klass->dir_changed = NULL;
  1023. }
  1024. static void init (GnomeCmdFileList *fl)
  1025. {
  1026. fl->priv = new GnomeCmdFileList::Private(fl);
  1027. init_dnd (fl);
  1028. gtk_signal_connect_after (*fl, "scroll-vertical", GTK_SIGNAL_FUNC (on_scroll_vertical), fl);
  1029. gtk_signal_connect (*fl, "click-column", GTK_SIGNAL_FUNC (on_column_clicked), fl);
  1030. gtk_signal_connect (*fl, "button-press-event", GTK_SIGNAL_FUNC (on_button_press), fl);
  1031. gtk_signal_connect (*fl, "button-release-event", GTK_SIGNAL_FUNC (on_button_release), fl);
  1032. gtk_signal_connect (*fl, "motion-notify-event", GTK_SIGNAL_FUNC (on_motion_notify), fl);
  1033. gtk_signal_connect_after (*fl, "realize", GTK_SIGNAL_FUNC (on_realize), fl);
  1034. gtk_signal_connect (*fl, "file-clicked", GTK_SIGNAL_FUNC (on_file_clicked), fl);
  1035. gtk_signal_connect (*fl, "file-released", GTK_SIGNAL_FUNC (on_file_released), fl);
  1036. }
  1037. /***********************************
  1038. * Public functions
  1039. ***********************************/
  1040. GtkType gnome_cmd_file_list_get_type ()
  1041. {
  1042. static GtkType type = 0;
  1043. if (type == 0)
  1044. {
  1045. GtkTypeInfo info =
  1046. {
  1047. "GnomeCmdFileList",
  1048. sizeof (GnomeCmdFileList),
  1049. sizeof (GnomeCmdFileListClass),
  1050. (GtkClassInitFunc) class_init,
  1051. (GtkObjectInitFunc) init,
  1052. /* reserved_1 */ NULL,
  1053. /* reserved_2 */ NULL,
  1054. (GtkClassInitFunc) NULL
  1055. };
  1056. type = gtk_type_unique (gnome_cmd_clist_get_type (), &info);
  1057. }
  1058. return type;
  1059. }
  1060. guint GnomeCmdFileList::get_column_default_width (GnomeCmdFileList::ColumnID col)
  1061. {
  1062. return file_list_column[col].default_width;
  1063. }
  1064. GnomeCmdFileList::ColumnID GnomeCmdFileList::get_sort_column()
  1065. {
  1066. return (ColumnID) priv->current_col;
  1067. }
  1068. inline void add_file_to_clist (GnomeCmdFileList *fl, GnomeCmdFile *f, gint in_row)
  1069. {
  1070. GtkCList *clist = GTK_CLIST (fl);
  1071. FileFormatData data(f,FALSE);
  1072. gint row = in_row == -1 ? gtk_clist_append (clist, data.text) : gtk_clist_insert (clist, in_row, data.text);
  1073. // Setup row data and color
  1074. if (!gnome_cmd_data.use_ls_colors)
  1075. gtk_clist_set_row_style (clist, row, row%2 ? alt_list_style : list_style);
  1076. else
  1077. {
  1078. LsColor *col = ls_colors_get (f);
  1079. if (col)
  1080. {
  1081. if (col->bg)
  1082. gtk_clist_set_background (clist, row, col->bg);
  1083. if (col->fg)
  1084. gtk_clist_set_foreground (clist, row, col->fg);
  1085. }
  1086. }
  1087. gtk_clist_set_row_data (clist, row, f);
  1088. // If the use wants icons to show file types set it now
  1089. if (gnome_cmd_data.layout != GNOME_CMD_LAYOUT_TEXT)
  1090. {
  1091. gtk_clist_set_pixmap (clist, row, 0,
  1092. gnome_cmd_file_get_type_pixmap (f),
  1093. gnome_cmd_file_get_type_mask (f));
  1094. }
  1095. // If we have been waiting for this file to show up, focus it
  1096. if (fl->priv->focus_later &&
  1097. strcmp (gnome_cmd_file_get_name (f), fl->priv->focus_later) == 0)
  1098. focus_file_at_row (fl, row);
  1099. }
  1100. /******************************************************************************
  1101. *
  1102. * Function: GnomeCmdFileList::append_file
  1103. *
  1104. * Purpose: Add a file to the list
  1105. *
  1106. * Params: @f: The file to add
  1107. *
  1108. * Returns:
  1109. *
  1110. * Statuses:
  1111. *
  1112. ******************************************************************************/
  1113. void GnomeCmdFileList::append_file (GnomeCmdFile *f)
  1114. {
  1115. priv->visible_files.add(f);
  1116. add_file_to_clist (this, f, -1);
  1117. }
  1118. gboolean GnomeCmdFileList::insert_file(GnomeCmdFile *f)
  1119. {
  1120. if (!file_is_wanted(f))
  1121. return FALSE;
  1122. gint num_files = size();
  1123. for (gint i=0; i<num_files; i++)
  1124. {
  1125. GnomeCmdFile *f2 = get_file_at_row(i);
  1126. if (priv->sort_func (f2, f, this) == 1)
  1127. {
  1128. priv->visible_files.add(f);
  1129. add_file_to_clist (this, f, i);
  1130. if (i<=priv->cur_file)
  1131. priv->cur_file++;
  1132. return TRUE;
  1133. }
  1134. }
  1135. // Insert the file at the end of the list
  1136. append_file(f);
  1137. return TRUE;
  1138. }
  1139. void GnomeCmdFileList::show_files(GnomeCmdDir *dir)
  1140. {
  1141. remove_all_files();
  1142. GList *list;
  1143. GList *files = NULL;
  1144. // select the files to show
  1145. for (gnome_cmd_dir_get_files (dir, &list); list; list = list->next)
  1146. {
  1147. GnomeCmdFile *f = GNOME_CMD_FILE (list->data);
  1148. if (file_is_wanted (f))
  1149. files = g_list_append (files, f);
  1150. }
  1151. // Create a parent dir file (..) if appropriate
  1152. gchar *path = gnome_cmd_file_get_path (GNOME_CMD_FILE (dir));
  1153. if (path && strcmp (path, G_DIR_SEPARATOR_S) != 0)
  1154. files = g_list_append (files, gnome_cmd_dir_new_parent_dir_file (dir));
  1155. g_free (path);
  1156. if (!files)
  1157. return;
  1158. files = g_list_sort_with_data (files, (GCompareDataFunc) priv->sort_func, this);
  1159. gtk_clist_freeze (*this);
  1160. for (GList *i = files; i; i = i->next)
  1161. append_file(GNOME_CMD_FILE (i->data));
  1162. gtk_clist_thaw (*this);
  1163. if (files)
  1164. g_list_free (files);
  1165. }
  1166. void GnomeCmdFileList::update_file(GnomeCmdFile *f)
  1167. {
  1168. if (!gnome_cmd_file_needs_update (f))
  1169. return;
  1170. gint row = get_row_from_file(f);
  1171. if (row == -1)
  1172. return;
  1173. FileFormatData data(f, FALSE);
  1174. for (gint i=1; i<GnomeCmdFileList::NUM_COLUMNS; i++)
  1175. gtk_clist_set_text (*this, row, i, data.text[i]);
  1176. if (gnome_cmd_data.layout != GNOME_CMD_LAYOUT_TEXT)
  1177. {
  1178. GdkPixmap *pixmap;
  1179. GdkBitmap *mask;
  1180. if (gnome_cmd_file_get_type_pixmap_and_mask (f, &pixmap, &mask))
  1181. gtk_clist_set_pixmap (*this, row, 0, pixmap, mask);
  1182. }
  1183. }
  1184. void GnomeCmdFileList::show_dir_tree_size(GnomeCmdFile *f)
  1185. {
  1186. g_return_if_fail (GNOME_CMD_IS_FILE (f));
  1187. gint row = get_row_from_file(f);
  1188. if (row == -1)
  1189. return;
  1190. FileFormatData data(f,TRUE);
  1191. for (gint i=1; i<NUM_COLUMNS; i++)
  1192. gtk_clist_set_text (*this, row, i, data.text[i]);
  1193. }
  1194. gboolean GnomeCmdFileList::remove_file(GnomeCmdFile *f)
  1195. {
  1196. g_return_val_if_fail (f != NULL, FALSE);
  1197. gint row = get_row_from_file(f);
  1198. if (row<0) // f not found in the shown file list...
  1199. return FALSE;
  1200. gtk_clist_remove (GTK_CLIST (this), row);
  1201. priv->selected_files = g_list_remove (priv->selected_files, f);
  1202. priv->visible_files.remove(f);
  1203. if (gtk_widget_is_focus(*this))
  1204. focus_file_at_row (this, MIN (row, GTK_CLIST (this)->focus_row));
  1205. return TRUE;
  1206. }
  1207. gboolean GnomeCmdFileList::remove_file(const gchar *uri_str)
  1208. {
  1209. g_return_val_if_fail (uri_str != NULL, FALSE);
  1210. return remove_file (priv->visible_files.find(uri_str));
  1211. }
  1212. void GnomeCmdFileList::clear()
  1213. {
  1214. gtk_clist_clear (GTK_CLIST (this));
  1215. priv->visible_files.clear();
  1216. gnome_cmd_file_list_free (priv->selected_files);
  1217. priv->selected_files = NULL;
  1218. }
  1219. GList *GnomeCmdFileList::get_selected_files()
  1220. {
  1221. if (priv->selected_files)
  1222. return g_list_copy (priv->selected_files);
  1223. GnomeCmdFile *file = get_selected_file();
  1224. return file ? g_list_append (NULL, file) : NULL;
  1225. }
  1226. GList *GnomeCmdFileList::get_marked_files()
  1227. {
  1228. return priv->selected_files;
  1229. }
  1230. GList *GnomeCmdFileList::get_visible_files()
  1231. {
  1232. return priv->visible_files.get_list();
  1233. }
  1234. GnomeCmdFile *GnomeCmdFileList::get_first_selected_file()
  1235. {
  1236. return priv->selected_files ? (GnomeCmdFile *) priv->selected_files->data : get_selected_file();
  1237. }
  1238. GnomeCmdFile *GnomeCmdFileList::get_focused_file()
  1239. {
  1240. return priv->cur_file < 0 ? NULL : get_file_at_row(priv->cur_file);
  1241. }
  1242. void GnomeCmdFileList::select_all()
  1243. {
  1244. gnome_cmd_file_list_free (priv->selected_files);
  1245. priv->selected_files = NULL;
  1246. for (GList *tmp = get_visible_files(); tmp; tmp = tmp->next)
  1247. select_file (this, (GnomeCmdFile *) tmp->data);
  1248. }
  1249. void GnomeCmdFileList::unselect_all()
  1250. {
  1251. GList *selfiles = g_list_copy (priv->selected_files);
  1252. for (GList *tmp = selfiles; tmp; tmp = tmp->next)
  1253. unselect_file (this, (GnomeCmdFile *) tmp->data);
  1254. g_list_free (selfiles);
  1255. gnome_cmd_file_list_free (priv->selected_files);
  1256. priv->selected_files = NULL;
  1257. }
  1258. void GnomeCmdFileList::toggle()
  1259. {
  1260. GnomeCmdFile *f = get_file_at_row(priv->cur_file);
  1261. if (f)
  1262. toggle_file (this, f);
  1263. }
  1264. void GnomeCmdFileList::toggle_and_step()
  1265. {
  1266. GnomeCmdFile *f = get_file_at_row(priv->cur_file);
  1267. if (f)
  1268. toggle_file (this, f);
  1269. if (priv->cur_file < size()-1)
  1270. focus_file_at_row (this, priv->cur_file+1);
  1271. }
  1272. void GnomeCmdFileList::focus_file(const gchar *focus_file, gboolean scroll_to_file)
  1273. {
  1274. for (GList *tmp = get_visible_files(); tmp; tmp = tmp->next)
  1275. {
  1276. GnomeCmdFile *f = (GnomeCmdFile *) tmp->data;
  1277. g_return_if_fail (f != NULL);
  1278. g_return_if_fail (f->info != NULL);
  1279. gint row = get_row_from_file (f);
  1280. if (row == -1)
  1281. return;
  1282. if (strcmp (f->info->name, focus_file) == 0)
  1283. {
  1284. priv->cur_file = row;
  1285. focus_file_at_row (this, row);
  1286. if (scroll_to_file)
  1287. gtk_clist_moveto (*this, row, 0, 0, 0);
  1288. return;
  1289. }
  1290. }
  1291. /* The file was not found, remember the filename in case the file gets
  1292. added to the list in the future (after a FAM event etc). */
  1293. g_free (priv->focus_later);
  1294. priv->focus_later = g_strdup (focus_file);
  1295. }
  1296. void GnomeCmdFileList::select_row(gint row)
  1297. {
  1298. focus_file_at_row (this, row==-1 ? 0 : row);
  1299. }
  1300. void GnomeCmdFileList::select_pattern(const gchar *pattern, gboolean case_sens)
  1301. {
  1302. toggle_with_pattern (this, pattern, case_sens, TRUE);
  1303. }
  1304. void GnomeCmdFileList::unselect_pattern(const gchar *pattern, gboolean case_sens)
  1305. {
  1306. toggle_with_pattern (this, pattern, case_sens, FALSE);
  1307. }
  1308. void GnomeCmdFileList::invert_selection()
  1309. {
  1310. GList *sel = g_list_copy (priv->selected_files);
  1311. for (GList *tmp=get_visible_files(); tmp; tmp = tmp->next)
  1312. {
  1313. GnomeCmdFile *f = (GnomeCmdFile *) tmp->data;
  1314. if (f && f->info)
  1315. {
  1316. if (g_list_index (sel, f) == -1)
  1317. select_file (this, f);
  1318. else
  1319. unselect_file (this, f);
  1320. }
  1321. }
  1322. g_list_free (sel);
  1323. }
  1324. void GnomeCmdFileList::select_all_with_same_extension()
  1325. {
  1326. toggle_files_with_same_extension (this, TRUE);
  1327. }
  1328. void GnomeCmdFileList::unselect_all_with_same_extension()
  1329. {
  1330. toggle_files_with_same_extension (this, FALSE);
  1331. }
  1332. void GnomeCmdFileList::restore_selection()
  1333. {
  1334. }
  1335. static gint compare_filename (GnomeCmdFile *f1, GnomeCmdFile *f2)
  1336. {
  1337. return strcmp (f1->info->name, f2->info->name);
  1338. }
  1339. void gnome_cmd_file_list_compare_directories (GnomeCmdFileList *fl1, GnomeCmdFileList *fl2)
  1340. {
  1341. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl1) || GNOME_CMD_IS_FILE_LIST (fl2));
  1342. fl1->unselect_all();
  1343. fl2->select_all();
  1344. for (GList *i=fl1->get_visible_files(); i; i=i->next)
  1345. {
  1346. GnomeCmdFile *f1 = (GnomeCmdFile *) i->data;
  1347. GnomeCmdFile *f2;
  1348. GList *gl2 = g_list_find_custom (fl2->priv->selected_files, f1, (GCompareFunc) compare_filename);
  1349. if (!gl2)
  1350. {
  1351. select_file (fl1, f1);
  1352. continue;
  1353. }
  1354. f2 = (GnomeCmdFile *) gl2->data;
  1355. if (f1->info->type==GNOME_VFS_FILE_TYPE_DIRECTORY || f2->info->type==GNOME_VFS_FILE_TYPE_DIRECTORY)
  1356. {
  1357. unselect_file (fl2, f2);
  1358. continue;
  1359. }
  1360. if (f1->info->mtime > f2->info->mtime)
  1361. {
  1362. select_file (fl1, f1);
  1363. unselect_file (fl2, f2);
  1364. continue;
  1365. }
  1366. if (f1->info->mtime == f2->info->mtime)
  1367. {
  1368. if (f1->info->size == f2->info->size)
  1369. unselect_file (fl2, f2);
  1370. else
  1371. select_file (fl1, f1);
  1372. }
  1373. }
  1374. }
  1375. void GnomeCmdFileList::sort()
  1376. {
  1377. GnomeCmdFile *selfile = get_selected_file();
  1378. gtk_clist_freeze (*this);
  1379. gtk_clist_clear (*this);
  1380. // resort the files and readd them to the list
  1381. for (GList *list = priv->visible_files.sort(priv->sort_func, this); list; list = list->next)
  1382. add_file_to_clist (this, GNOME_CMD_FILE (list->data), -1);
  1383. // refocus the previously selected file if this file list has the focus
  1384. if (selfile && GTK_WIDGET_HAS_FOCUS (this))
  1385. {
  1386. gint selrow = get_row_from_file(selfile);
  1387. select_row(selrow);
  1388. gtk_clist_moveto (GTK_CLIST (this), selrow, -1, 1, 0);
  1389. }
  1390. // reselect the previously selected files
  1391. for (GList *list = priv->selected_files; list; list = list->next)
  1392. select_file (this, GNOME_CMD_FILE (list->data));
  1393. gtk_clist_thaw (*this);
  1394. }
  1395. void gnome_cmd_file_list_show_rename_dialog (GnomeCmdFileList *fl)
  1396. {
  1397. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  1398. GnomeCmdFile *f = fl->get_selected_file();
  1399. if (GNOME_CMD_IS_FILE (f))
  1400. {
  1401. gint x, y, w, h;
  1402. get_focus_row_coordinates (fl, x, y, w, h);
  1403. GtkWidget *dialog = gnome_cmd_rename_dialog_new (f, x, y, w, h);
  1404. gtk_widget_ref (dialog);
  1405. gtk_widget_show (dialog);
  1406. }
  1407. }
  1408. void gnome_cmd_file_list_show_delete_dialog (GnomeCmdFileList *fl)
  1409. {
  1410. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  1411. GList *files = fl->get_selected_files();
  1412. if (files)
  1413. {
  1414. gnome_cmd_delete_dialog_show (files);
  1415. g_list_free (files);
  1416. }
  1417. }
  1418. void gnome_cmd_file_list_show_chown_dialog (GnomeCmdFileList *fl)
  1419. {
  1420. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  1421. GList *files = fl->get_selected_files();
  1422. if (files)
  1423. {
  1424. GtkWidget *dialog = gnome_cmd_chown_dialog_new (files);
  1425. gtk_widget_ref (dialog);
  1426. gtk_widget_show (dialog);
  1427. g_list_free (files);
  1428. }
  1429. }
  1430. void gnome_cmd_file_list_show_chmod_dialog (GnomeCmdFileList *fl)
  1431. {
  1432. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  1433. GList *files = fl->get_selected_files();
  1434. if (files)
  1435. {
  1436. GtkWidget *dialog = gnome_cmd_chmod_dialog_new (files);
  1437. gtk_widget_ref (dialog);
  1438. gtk_widget_show (dialog);
  1439. g_list_free (files);
  1440. }
  1441. }
  1442. void gnome_cmd_file_list_show_properties_dialog (GnomeCmdFileList *fl)
  1443. {
  1444. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  1445. GnomeCmdFile *f = fl->get_selected_file();
  1446. if (f)
  1447. gnome_cmd_file_show_properties (f);
  1448. }
  1449. void gnome_cmd_file_list_show_selpat_dialog (GnomeCmdFileList *fl, gboolean mode)
  1450. {
  1451. show_selpat_dialog (fl, mode);
  1452. }
  1453. void gnome_cmd_file_list_cap_cut (GnomeCmdFileList *fl)
  1454. {
  1455. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  1456. GList *files = fl->get_selected_files();
  1457. if (files)
  1458. {
  1459. cap_cut_files (fl, files);
  1460. g_list_free (files);
  1461. }
  1462. }
  1463. void gnome_cmd_file_list_cap_copy (GnomeCmdFileList *fl)
  1464. {
  1465. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  1466. GList *files = fl->get_selected_files();
  1467. if (files)
  1468. {
  1469. cap_copy_files (fl, files);
  1470. g_list_free (files);
  1471. }
  1472. }
  1473. void gnome_cmd_file_list_view (GnomeCmdFileList *fl, gint internal_viewer)
  1474. {
  1475. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  1476. GnomeCmdFile *f = fl->get_selected_file();
  1477. if (!f) return;
  1478. if (f->info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
  1479. create_error_dialog (_("Not an ordinary file: %s"), f->info->name);
  1480. else
  1481. gnome_cmd_file_view (f, internal_viewer);
  1482. }
  1483. void gnome_cmd_file_list_edit (GnomeCmdFileList *fl)
  1484. {
  1485. g_return_if_fail (GNOME_CMD_IS_FILE_LIST (fl));
  1486. GnomeCmdFile *f = fl->get_selected_file();
  1487. if (!f) return;
  1488. if (f->info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
  1489. create_error_dialog (_("Not an ordinary file: %s"), f->info->name);
  1490. else
  1491. gnome_cmd_file_edit (f);
  1492. }
  1493. gboolean gnome_cmd_file_list_quicksearch_shown (GnomeCmdFileList *fl)
  1494. {
  1495. g_return_val_if_fail (fl!=NULL, FALSE);
  1496. g_return_val_if_fail (GNOME_CMD_IS_FILE_LIST (fl), FALSE);
  1497. g_return_val_if_fail (fl->priv!=NULL, FALSE);
  1498. return fl->priv->quicksearch_popup!=NULL;
  1499. }
  1500. void gnome_cmd_file_list_show_quicksearch (GnomeCmdFileList *fl, gchar c)
  1501. {
  1502. gchar text[2];
  1503. if (fl->priv->quicksearch_popup)
  1504. return;
  1505. gtk_clist_unselect_all (*fl);
  1506. fl->priv->quicksearch_popup = gnome_cmd_quicksearch_popup_new (fl);
  1507. text[0] = c;
  1508. text[1] = '\0';
  1509. gtk_widget_ref (fl->priv->quicksearch_popup);
  1510. gtk_widget_show (fl->priv->quicksearch_popup);
  1511. if (c != 0)
  1512. {
  1513. GnomeCmdQuicksearchPopup *popup = GNOME_CMD_QUICKSEARCH_POPUP (fl->priv->quicksearch_popup);
  1514. gtk_entry_set_text (GTK_ENTRY (popup->entry), text);
  1515. gtk_editable_set_position (GTK_EDITABLE (popup->entry), 1);
  1516. }
  1517. gtk_signal_connect (GTK_OBJECT (fl->priv->quicksearch_popup), "hide",
  1518. GTK_SIGNAL_FUNC (on_quicksearch_popup_hide), fl);
  1519. }
  1520. gboolean GnomeCmdFileList::key_pressed(GdkEventKey *event)
  1521. {
  1522. g_return_val_if_fail (event != NULL, FALSE);
  1523. if (state_is_alt (event->state))
  1524. {
  1525. switch (event->keyval)
  1526. {
  1527. case GDK_Return:
  1528. case GDK_KP_Enter:
  1529. gnome_cmd_file_list_show_properties_dialog (this);
  1530. return TRUE;
  1531. case GDK_KP_Add:
  1532. toggle_files_with_same_extension (this, TRUE);
  1533. break;
  1534. case GDK_KP_Subtract:
  1535. toggle_files_with_same_extension (this, FALSE);
  1536. break;
  1537. }
  1538. }
  1539. else if (state_is_ctrl_alt (event->state) || state_is_ctrl_alt_shift (event->state))
  1540. {
  1541. if ((event->keyval >= GDK_a && event->keyval <= GDK_z)
  1542. || (event->keyval >= GDK_A && event->keyval <= GDK_Z)
  1543. || event->keyval == GDK_period)
  1544. gnome_cmd_file_list_show_quicksearch (this, (gchar) event->keyval);
  1545. }
  1546. else if (state_is_shift (event->state))
  1547. {
  1548. switch (event->keyval)
  1549. {
  1550. case GDK_F6:
  1551. gnome_cmd_file_list_show_rename_dialog (this);
  1552. return TRUE;
  1553. case GDK_F10:
  1554. show_file_popup_with_warp (this);
  1555. return TRUE;
  1556. case GDK_Left:
  1557. case GDK_KP_Left:
  1558. case GDK_Right:
  1559. case GDK_KP_Right:
  1560. event->state -= GDK_SHIFT_MASK;
  1561. return FALSE;
  1562. case GDK_Page_Up:
  1563. case GDK_KP_Page_Up:
  1564. case GDK_KP_9:
  1565. priv->shift_down = TRUE;
  1566. gtk_signal_emit_by_name (GTK_OBJECT (this), "scroll-vertical", GTK_SCROLL_PAGE_BACKWARD, 0.0, NULL);
  1567. return FALSE;
  1568. case GDK_Page_Down:
  1569. case GDK_KP_Page_Down:
  1570. case GDK_KP_3:
  1571. priv->shift_down = TRUE;
  1572. gtk_signal_emit_by_name (GTK_OBJECT (this), "scroll-vertical", GTK_SCROLL_PAGE_FORWARD, 0.0, NULL);
  1573. return FALSE;
  1574. case GDK_Up:
  1575. case GDK_KP_Up:
  1576. case GDK_KP_8:
  1577. priv->shift_down = TRUE;
  1578. gtk_signal_emit_by_name (GTK_OBJECT (this), "scroll-vertical", GTK_SCROLL_STEP_BACKWARD, 0.0, NULL);
  1579. return FALSE;
  1580. case GDK_Down:
  1581. case GDK_KP_Down:
  1582. case GDK_KP_2:
  1583. priv->shift_down = TRUE;
  1584. gtk_signal_emit_by_name (GTK_OBJECT (this), "scroll-vertical", GTK_SCROLL_STEP_FORWARD, 0.0, NULL);
  1585. return FALSE;
  1586. case GDK_Home:
  1587. case GDK_KP_Home:
  1588. case GDK_KP_7:
  1589. priv->shift_down = TRUE;
  1590. gtk_signal_emit_by_name (GTK_OBJECT (this), "scroll-vertical", GTK_SCROLL_JUMP, 0.0);
  1591. return TRUE;
  1592. case GDK_End:
  1593. case GDK_KP_End:
  1594. case GDK_KP_1:
  1595. priv->shift_down = TRUE;
  1596. gtk_signal_emit_by_name (GTK_OBJECT (this), "scroll-vertical", GTK_SCROLL_JUMP, 1.0);
  1597. return TRUE;
  1598. }
  1599. }
  1600. else if (state_is_ctrl (event->state))
  1601. {
  1602. switch (event->keyval)
  1603. {
  1604. case GDK_X:
  1605. case GDK_x:
  1606. gnome_cmd_file_list_cap_cut (this);
  1607. return TRUE;
  1608. case GDK_C:
  1609. case GDK_c:
  1610. gnome_cmd_file_list_cap_copy (this);
  1611. return TRUE;
  1612. case GDK_F3:
  1613. on_column_clicked (GTK_CLIST (this), GnomeCmdFileList::COLUMN_NAME, this);
  1614. return TRUE;
  1615. case GDK_F4:
  1616. on_column_clicked (GTK_CLIST (this), GnomeCmdFileList::COLUMN_EXT, this);
  1617. return TRUE;
  1618. case GDK_F5:
  1619. on_column_clicked (GTK_CLIST (this), GnomeCmdFileList::COLUMN_DATE, this);
  1620. return TRUE;
  1621. case GDK_F6:
  1622. on_column_clicked (GTK_CLIST (this), GnomeCmdFileList::COLUMN_SIZE, this);
  1623. return TRUE;
  1624. }
  1625. }
  1626. else if (state_is_blank (event->state))
  1627. {
  1628. switch (event->keyval)
  1629. {
  1630. case GDK_Return:
  1631. case GDK_KP_Enter:
  1632. return mime_exec_file (get_focused_file());
  1633. case GDK_KP_Add:
  1634. case GDK_plus:
  1635. case GDK_equal:
  1636. show_selpat_dialog (this, TRUE);
  1637. return TRUE;
  1638. case GDK_KP_Subtract:
  1639. case GDK_minus:
  1640. show_selpat_dialog (this, FALSE);
  1641. return TRUE;
  1642. case GDK_KP_Multiply:
  1643. invert_selection();
  1644. return TRUE;
  1645. case GDK_KP_Divide:
  1646. restore_selection();
  1647. return TRUE;
  1648. case GDK_Insert:
  1649. case GDK_KP_Insert:
  1650. toggle();
  1651. gtk_signal_emit_by_name (GTK_OBJECT (this), "scroll-vertical", GTK_SCROLL_STEP_FORWARD, 0.0, NULL);
  1652. return TRUE;
  1653. case GDK_KP_Page_Up:
  1654. event->keyval = GDK_Page_Up;
  1655. return FALSE;
  1656. case GDK_KP_Page_Down:
  1657. event->keyval = GDK_Page_Down;
  1658. return FALSE;
  1659. case GDK_KP_Up:
  1660. event->keyval = GDK_Up;
  1661. return FALSE;
  1662. case GDK_KP_Down:
  1663. event->keyval = GDK_Down;
  1664. return FALSE;
  1665. case GDK_Home:
  1666. case GDK_KP_Home:
  1667. gtk_signal_emit_by_name (GTK_OBJECT (this), "scroll-vertical", GTK_SCROLL_JUMP, 0.0);
  1668. return TRUE;
  1669. case GDK_End:
  1670. case GDK_KP_End:
  1671. gtk_signal_emit_by_name (GTK_OBJECT (this), "scroll-vertical", GTK_SCROLL_JUMP, 1.0);
  1672. return TRUE;
  1673. case GDK_Delete:
  1674. case GDK_KP_Delete:
  1675. gnome_cmd_file_list_show_delete_dialog (this);
  1676. return TRUE;
  1677. case GDK_Shift_L:
  1678. case GDK_Shift_R:
  1679. if (!priv->shift_down)
  1680. priv->shift_down_row = priv->cur_file;
  1681. return TRUE;
  1682. case GDK_Menu:
  1683. show_file_popup_with_warp (this);
  1684. return TRUE;
  1685. }
  1686. }
  1687. return FALSE;
  1688. }
  1689. GList *GnomeCmdFileList::sort_selection(GList *list)
  1690. {
  1691. return g_list_sort_with_data (list, (GCompareDataFunc) priv->sort_func, this);
  1692. }
  1693. void GnomeCmdFileList::update_style()
  1694. {
  1695. gtk_clist_set_row_height (*this, gnome_cmd_data.list_row_height);
  1696. gnome_cmd_clist_update_style (*this);
  1697. }
  1698. gboolean GnomeCmdFileList::file_is_wanted(GnomeCmdFile *f)
  1699. {
  1700. g_return_val_if_fail (f != NULL, FALSE);
  1701. GnomeVFSFileInfo *info = f->info;
  1702. if (strcmp (info->name, ".") == 0)
  1703. return FALSE;
  1704. if (f->is_dotdot)
  1705. return FALSE;
  1706. if (gnome_cmd_data.hide_type(info->type))
  1707. return FALSE;
  1708. if (info->symlink_name && gnome_cmd_data.hide_type(GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK))
  1709. return FALSE;
  1710. if (info->name[0] == '.' && gnome_cmd_data.filter_settings.hidden)
  1711. return FALSE;
  1712. if (gnome_cmd_data.filter_settings.backup && patlist_matches (gnome_cmd_data_get_backup_pattern_list (), info->name))
  1713. return FALSE;
  1714. return TRUE;
  1715. }
  1716. void GnomeCmdFileList::invalidate_tree_size()
  1717. {
  1718. for (GList *tmp = get_visible_files(); tmp; tmp = tmp->next)
  1719. {
  1720. GnomeCmdFile *f = (GnomeCmdFile *) tmp->data;
  1721. if (f->info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
  1722. gnome_cmd_file_invalidate_tree_size (f);
  1723. }
  1724. }