GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
files-dock-widget.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2011-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <QApplication>
31 #include <QClipboard>
32 #include <QCompleter>
33 #include <QDebug>
34 #include <QDesktopServices>
35 #include <QFileDialog>
36 #include <QFileInfo>
37 #include <QHeaderView>
38 #include <QInputDialog>
39 #include <QLineEdit>
40 #include <QMenu>
41 #include <QMessageBox>
42 #include <QProcess>
43 #include <QSizePolicy>
44 #include <QToolButton>
45 #include <QUrl>
46 
47 #include "files-dock-widget.h"
48 #include "gui-preferences-fb.h"
49 #include "gui-preferences-global.h"
50 #include "octave-qobject.h"
51 #include "qt-interpreter-events.h"
52 
53 #include "interpreter.h"
54 #include "load-save.h"
55 #include "oct-env.h"
56 
57 namespace octave
58 {
59  class FileTreeViewer : public QTreeView
60  {
61  public:
62 
64 
65  ~FileTreeViewer (void) = default;
66 
67  void mousePressEvent (QMouseEvent *e)
68  {
69  if (e->button () != Qt::RightButton)
70  QTreeView::mousePressEvent (e);
71  }
72  };
73 
75  : octave_dock_widget ("FilesDockWidget", p, oct_qobj)
76  {
77  setWindowIcon (QIcon (":/actions/icons/logo.png"));
78  set_title (tr ("File Browser"));
79  setToolTip (tr ("Browse your files"));
80 
81  m_sig_mapper = nullptr;
82 
83  m_columns_shown = QStringList ();
84  m_columns_shown.append (tr ("File size"));
85  m_columns_shown.append (tr ("File type"));
86  m_columns_shown.append (tr ("Date modified"));
87  m_columns_shown.append (tr ("Show hidden"));
88  m_columns_shown.append (tr ("Alternating row colors"));
89 
90  m_columns_shown_keys = QStringList ();
96 
103 
104  QWidget *container = new QWidget (this);
105 
106  setWidget (container);
107 
108  connect (this, SIGNAL (open_file (const QString&)),
109  main_win (), SLOT (open_file (const QString&)));
110 
111  connect (this, SIGNAL (displayed_directory_changed (const QString&)),
112  main_win (),
113  SLOT (set_current_working_directory (const QString&)));
114 
115  connect (this,
116  SIGNAL (modify_path_signal (const octave_value_list&, bool, bool)),
117  main_win (),
118  SLOT (modify_path (const octave_value_list&, bool, bool)));
119 
120  // Create a toolbar
121  m_navigation_tool_bar = new QToolBar ("", container);
122  m_navigation_tool_bar->setAllowedAreas (Qt::TopToolBarArea);
123  m_navigation_tool_bar->setMovable (false);
124 
125  m_current_directory = new QComboBox (m_navigation_tool_bar);
126  m_current_directory->setToolTip (tr ("Enter the path or filename"));
127  m_current_directory->setEditable (true);
128  m_current_directory->setMaxCount (MaxMRUDirs);
129  m_current_directory->setInsertPolicy (QComboBox::NoInsert);
130  m_current_directory->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon);
131  QSizePolicy sizePol (QSizePolicy::Expanding, QSizePolicy::Preferred);
132  m_current_directory->setSizePolicy (sizePol);
133 
135 
136  QAction *directory_up_action
137  = new QAction (rmgr.icon ("go-up"), "", m_navigation_tool_bar);
138  directory_up_action->setToolTip (tr ("One directory up"));
139 
141  = new QAction (rmgr.icon ("go-first"), tr ("Show Octave directory"),
143  m_sync_browser_directory_action->setToolTip (tr ("Go to current Octave directory"));
144  m_sync_browser_directory_action->setEnabled (false);
145 
147  = new QAction (rmgr.icon ("go-last"), tr ("Set Octave directory"),
149  m_sync_octave_directory_action->setToolTip (tr ("Set Octave directory to current browser directory"));
150  m_sync_octave_directory_action->setEnabled (false);
151 
152  QToolButton *popdown_button = new QToolButton ();
153  popdown_button->setToolTip (tr ("Actions on current directory"));
154  QMenu *popdown_menu = new QMenu ();
155  popdown_menu->addAction (rmgr.icon ("user-home"),
156  tr ("Show Home Directory"), this,
157  SLOT (popdownmenu_home (bool)));
158  popdown_menu->addAction (m_sync_browser_directory_action);
159  popdown_menu->addAction (m_sync_octave_directory_action);
160  popdown_button->setMenu (popdown_menu);
161  popdown_button->setPopupMode (QToolButton::InstantPopup);
162  popdown_button->setDefaultAction (new QAction (rmgr.icon ("applications-system"),
163  "", m_navigation_tool_bar));
164 
165  popdown_menu->addSeparator ();
166  popdown_menu->addAction (rmgr.icon ("folder"),
167  tr ("Set Browser Directory..."),
168  this, SLOT (popdownmenu_search_dir (bool)));
169  popdown_menu->addSeparator ();
170  popdown_menu->addAction (rmgr.icon ("edit-find"),
171  tr ("Find Files..."),
172  this, SLOT (popdownmenu_findfiles (bool)));
173  popdown_menu->addSeparator ();
174  popdown_menu->addAction (rmgr.icon ("document-new"),
175  tr ("New File..."),
176  this, SLOT (popdownmenu_newfile (bool)));
177  popdown_menu->addAction (rmgr.icon ("folder-new"),
178  tr ("New Directory..."),
179  this, SLOT (popdownmenu_newdir (bool)));
180 
182  m_navigation_tool_bar->addAction (directory_up_action);
183  m_navigation_tool_bar->addWidget (popdown_button);
184 
185  connect (directory_up_action, SIGNAL (triggered ()), this,
186  SLOT (change_directory_up ()));
187  connect (m_sync_octave_directory_action, SIGNAL (triggered ()), this,
188  SLOT (do_sync_octave_directory ()));
189  connect (m_sync_browser_directory_action, SIGNAL (triggered ()), this,
190  SLOT (do_sync_browser_directory ()));
191 
193  // FIXME: what should happen if settings is 0?
194 
195  // Create the QFileSystemModel starting in the desired directory
196  QDir startup_dir; // take current dir
197 
198  if (settings->value (fb_restore_last_dir).toBool ())
199  {
200  // restore last dir from previous session
201  QStringList last_dirs
202  = settings->value (fb_mru_list.key).toStringList ();
203  if (last_dirs.length () > 0)
204  startup_dir = QDir (last_dirs.at (0)); // last dir in previous session
205  }
206  else if (! settings->value (fb_startup_dir).toString ().isEmpty ())
207  {
208  // do not restore but there is a startup dir configured
209  startup_dir = QDir (settings->value (fb_startup_dir.key).toString ());
210  }
211 
212  if (! startup_dir.exists ())
213  {
214  // the configured startup dir does not exist, take actual one
215  startup_dir = QDir ();
216  }
217 
218  m_file_system_model = new QFileSystemModel (this);
219  m_file_system_model->setResolveSymlinks (false);
220  m_file_system_model->setFilter (
221  QDir::System | QDir::NoDotAndDotDot | QDir::AllEntries);
222  QModelIndex rootPathIndex
223  = m_file_system_model->setRootPath (startup_dir.absolutePath ());
224 
225  // Attach the model to the QTreeView and set the root index
226  m_file_tree_view = new FileTreeViewer (container);
227  m_file_tree_view->setSelectionMode (QAbstractItemView::ExtendedSelection);
229  m_file_tree_view->setRootIndex (rootPathIndex);
230  m_file_tree_view->setSortingEnabled (true);
231  m_file_tree_view->setAlternatingRowColors (true);
232  m_file_tree_view->setAnimated (true);
233  m_file_tree_view->setToolTip (tr ("Double-click to open file/folder, right click for alternatives"));
234 
235  // get sort column and order as well as column state (order and width)
236 
237  m_file_tree_view->sortByColumn
238  (settings->value (fb_sort_column).toInt (),
239  static_cast<Qt::SortOrder> (settings->value (fb_sort_order).toUInt ()));
240  // FIXME: use value<Qt::SortOrder> instead of static cast after
241  // dropping support of Qt 5.4
242 
243  if (settings->contains (fb_column_state.key))
244  m_file_tree_view->header ()->restoreState
245  (settings->value (fb_column_state.key).toByteArray ());
246 
247  // Set header properties for sorting
248 #if defined (HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE)
249  m_file_tree_view->header ()->setSectionsClickable (true);
250 #else
251  m_file_tree_view->header ()->setClickable (true);
252 #endif
253 #if defined (HAVE_QHEADERVIEW_SETSECTIONSMOVABLE)
254  m_file_tree_view->header ()->setSectionsMovable (true);
255 #else
256  m_file_tree_view->header ()->setMovable (true);
257 #endif
258  m_file_tree_view->header ()->setSortIndicatorShown (true);
259 
260  QStringList mru_dirs =
261  settings->value (fb_mru_list.key).toStringList ();
262  m_current_directory->addItems (mru_dirs);
263 
264  m_current_directory->setEditText
265  (m_file_system_model->fileInfo (rootPathIndex). absoluteFilePath ());
266 
267  connect (m_file_tree_view, SIGNAL (activated (const QModelIndex &)),
268  this, SLOT (item_double_clicked (const QModelIndex &)));
269 
270  // add context menu to tree_view
271  m_file_tree_view->setContextMenuPolicy (Qt::CustomContextMenu);
272  connect (m_file_tree_view,
273  SIGNAL (customContextMenuRequested (const QPoint &)),
274  this, SLOT (contextmenu_requested (const QPoint &)));
275 
276  m_file_tree_view->header ()->setContextMenuPolicy (Qt::CustomContextMenu);
277  connect (m_file_tree_view->header (),
278  SIGNAL (customContextMenuRequested (const QPoint &)),
279  this, SLOT (headercontextmenu_requested (const QPoint &)));
280 
281  // Layout the widgets vertically with the toolbar on top
282  QVBoxLayout *vbox_layout = new QVBoxLayout ();
283  vbox_layout->setSpacing (0);
284  vbox_layout->addWidget (m_navigation_tool_bar);
285  vbox_layout->addWidget (m_file_tree_view);
286  vbox_layout->setMargin (1);
287 
288  container->setLayout (vbox_layout);
289 
290  // FIXME: Add right-click contextual menus for copying, pasting,
291  // deleting files (and others).
292 
293  connect (m_current_directory->lineEdit (), SIGNAL (returnPressed ()),
294  this, SLOT (accept_directory_line_edit ()));
295 
296  connect (m_current_directory, SIGNAL (activated (const QString &)),
297  this, SLOT (set_current_directory (const QString &)));
298 
299  connect (this, SIGNAL (run_file_signal (const QFileInfo&)),
300  main_win (), SLOT (run_file_in_terminal (const QFileInfo&)));
301 
302  QCompleter *completer = new QCompleter (m_file_system_model, this);
303  m_current_directory->setCompleter (completer);
304 
305  setFocusProxy (m_current_directory);
306 
307  m_sync_octave_dir = true; // default, overwritten with notice_settings ()
308  m_octave_dir = "";
309  }
310 
312  {
315 
316  if (! settings)
317  return;
318 
319  int sort_column = m_file_tree_view->header ()->sortIndicatorSection ();
320  Qt::SortOrder sort_order = m_file_tree_view->header ()->sortIndicatorOrder ();
321  settings->setValue (fb_sort_column.key, sort_column);
322  settings->setValue (fb_sort_order.key, sort_order);
323  settings->setValue (fb_column_state.key,
324  m_file_tree_view->header ()->saveState ());
325 
326  QStringList dirs;
327  for (int i=0; i< m_current_directory->count (); i++)
328  {
329  dirs.append (m_current_directory->itemText (i));
330  }
331  settings->setValue (fb_mru_list.key, dirs);
332 
333  settings->sync ();
334 
336 
337  if (m_sig_mapper)
338  delete m_sig_mapper;
339  }
340 
341  void files_dock_widget::item_double_clicked (const QModelIndex& index)
342  {
343  // Retrieve the file info associated with the model index.
344  QFileInfo fileInfo = m_file_system_model->fileInfo (index);
345  set_current_directory (fileInfo.absoluteFilePath ());
346  }
347 
349  {
350  display_directory (dir);
351  }
352 
354  {
355  display_directory (m_current_directory->currentText ());
356  }
357 
359  {
360  QDir dir
361  = QDir (m_file_system_model->filePath (m_file_tree_view->rootIndex ()));
362 
363  dir.cdUp ();
364  display_directory (dir.absolutePath ());
365  }
366 
368  {
369  QDir dir
370  = QDir (m_file_system_model->filePath (m_file_tree_view->rootIndex ()));
371 
372  emit displayed_directory_changed (dir.absolutePath ());
373  }
374 
376  {
377  display_directory (m_octave_dir,false); // false: no sync of octave dir
378  }
379 
381  {
382  m_octave_dir = dir;
383  if (m_sync_octave_dir)
384  display_directory (m_octave_dir,false); // false: no sync of octave dir
385  }
386 
387  void files_dock_widget::display_directory (const QString& dir,
388  bool set_octave_dir)
389  {
390  QFileInfo fileInfo (dir);
391  if (fileInfo.exists ())
392  {
393  if (fileInfo.isDir ())
394  {
395  m_file_tree_view->setRootIndex (m_file_system_model->
396  index (fileInfo.absoluteFilePath ()));
397  m_file_system_model->setRootPath (fileInfo.absoluteFilePath ());
398  if (m_sync_octave_dir && set_octave_dir)
399  process_set_current_dir (fileInfo.absoluteFilePath ());
400 
401  // see if it's in the list, and if it is,
402  // remove it and then put at top of the list
403  int index
404  = m_current_directory->findText (fileInfo.absoluteFilePath ());
405  if (index != -1)
406  {
407  m_current_directory->removeItem (index);
408  }
409  m_current_directory->insertItem (0, fileInfo.absoluteFilePath ());
410  m_current_directory->setCurrentIndex (0);
411  }
412  else
413  {
414  QString abs_fname = fileInfo.absoluteFilePath ();
415 
416  QString suffix = fileInfo.suffix ().toLower ();
419  QString ext = settings->value (fb_txt_file_ext).toString ();
420 #if defined (HAVE_QT_SPLITBEHAVIOR_ENUM)
421  QStringList extensions = ext.split (";", Qt::SkipEmptyParts);
422 #else
423  QStringList extensions = ext.split (";", QString::SkipEmptyParts);
424 #endif
425  if (QFile::exists (abs_fname))
426  {
427  if (extensions.contains (suffix))
428  emit open_file (fileInfo.absoluteFilePath ());
429  else
430  emit open_any_signal (abs_fname);
431  }
432  }
433  }
434  }
435 
436  void files_dock_widget::open_item_in_app (const QModelIndex& index)
437  {
438  // Retrieve the file info associated with the model index.
439  QFileInfo fileInfo = m_file_system_model->fileInfo (index);
440 
441  QString file = fileInfo.absoluteFilePath ();
442 
443  QDesktopServices::openUrl (QUrl::fromLocalFile (file));
444  }
445 
447  {
450 
451  QString key = m_columns_shown_keys.at (col);
452  bool shown = settings->value (key,false).toBool ();
453  settings->setValue (key, ! shown);
454  settings->sync ();
455 
456  switch (col)
457  {
458  case 0:
459  case 1:
460  case 2:
461  // toggle column visibility
462  m_file_tree_view->setColumnHidden (col + 1, shown);
463  break;
464  case 3:
465  case 4:
466  // other actions depending on new settings
468  break;
469  }
470  }
471 
473  {
474  QMenu menu (this);
475 
476  if (m_sig_mapper)
477  delete m_sig_mapper;
478  m_sig_mapper = new QSignalMapper (this);
479 
482 
483  for (int i = 0; i < m_columns_shown.size (); i++)
484  {
485  QAction *action = menu.addAction (m_columns_shown.at (i),
486  m_sig_mapper, SLOT (map ()));
487  m_sig_mapper->setMapping (action, i);
488  action->setCheckable (true);
489  action->setChecked
490  (settings->value (m_columns_shown_keys.at (i),
491  m_columns_shown_defs.at (i)).toBool ());
492  }
493 
494  connect (m_sig_mapper, SIGNAL (mapped (int)),
495  this, SLOT (toggle_header (int)));
496 
497  menu.exec (m_file_tree_view->mapToGlobal (mpos));
498  }
499 
501  {
502 
503  QMenu menu (this);
504 
505  QModelIndex index = m_file_tree_view->indexAt (mpos);
506 
507  if (index.isValid ())
508  {
509  QFileInfo info = m_file_system_model->fileInfo (index);
510 
511  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
512  QModelIndexList sel = m->selectedRows ();
513 
514  // check if item at mouse position is seleccted
515  if (! sel.contains (index))
516  {
517  // is not selected -> clear actual selection and select this item
518  m->setCurrentIndex (index,
519  QItemSelectionModel::Clear
520  | QItemSelectionModel::Select
521  | QItemSelectionModel::Rows);
522  }
523 
525 
526  // construct the context menu depending on item
527  menu.addAction (rmgr.icon ("document-open"), tr ("Open"),
528  this, SLOT (contextmenu_open (bool)));
529 
530  if (info.isDir ())
531  {
532  menu.addAction (tr ("Open in System File Explorer"),
533  this, SLOT (contextmenu_open_in_app (bool)));
534  }
535 
536  if (info.isFile ())
537  menu.addAction (tr ("Open in Text Editor"),
538  this, SLOT (contextmenu_open_in_editor (bool)));
539 
540  menu.addAction (tr ("Copy Selection to Clipboard"),
541  this, SLOT (contextmenu_copy_selection (bool)));
542 
543  if (info.isFile () && info.suffix () == "m")
544  menu.addAction (rmgr.icon ("media-playback-start"),
545  tr ("Run"), this, SLOT (contextmenu_run (bool)));
546 
547  if (info.isFile ())
548  menu.addAction (tr ("Load Data"), this, SLOT (contextmenu_load (bool)));
549 
550  if (info.isDir ())
551  {
552  menu.addSeparator ();
553  menu.addAction (rmgr.icon ("go-first"),
554  tr ("Set Current Directory"),
555  this, SLOT (contextmenu_setcurrentdir (bool)));
556 
557  QMenu *add_path_menu = menu.addMenu (tr ("Add to Path"));
558 
559  add_path_menu->addAction (tr ("Selected Directories"),
560  this, SLOT (contextmenu_add_to_path (bool)));
561  add_path_menu->addAction (tr ("Selected Directories and Subdirectories"),
562  this, SLOT (contextmenu_add_to_path_subdirs (bool)));
563 
564  QMenu *rm_path_menu = menu.addMenu (tr ("Remove from Path"));
565 
566  rm_path_menu->addAction (tr ("Selected Directories"), this,
567  SLOT (contextmenu_rm_from_path (bool)));
568  rm_path_menu->addAction (tr ("Selected Directories and Subdirectories"),
569  this, SLOT (contextmenu_rm_from_path_subdirs (bool)));
570 
571  menu.addSeparator ();
572 
573  menu.addAction (rmgr.icon ("edit-find"),
574  tr ("Find Files..."), this,
575  SLOT (contextmenu_findfiles (bool)));
576  }
577 
578  menu.addSeparator ();
579  menu.addAction (tr ("Rename..."), this, SLOT (contextmenu_rename (bool)));
580  menu.addAction (rmgr.icon ("edit-delete"),
581  tr ("Delete..."), this, SLOT (contextmenu_delete (bool)));
582 
583  if (info.isDir ())
584  {
585  menu.addSeparator ();
586  menu.addAction (rmgr.icon ("document-new"),
587  tr ("New File..."),
588  this, SLOT (contextmenu_newfile (bool)));
589  menu.addAction (rmgr.icon ("folder-new"),
590  tr ("New Directory..."),
591  this, SLOT (contextmenu_newdir (bool)));
592  }
593 
594  // show the menu
595  menu.exec (m_file_tree_view->mapToGlobal (mpos));
596 
597  }
598  }
599 
601  {
602 
603  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
604  QModelIndexList rows = m->selectedRows ();
605 
606  for (auto it = rows.begin (); it != rows.end (); it++)
607  {
608  QFileInfo file = m_file_system_model->fileInfo (*it);
609  if (file.exists ())
610  display_directory (file.absoluteFilePath ());
611  }
612  }
613 
615  {
616 
617  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
618  QModelIndexList rows = m->selectedRows ();
619 
620  for (auto it = rows.begin (); it != rows.end (); it++)
621  {
622  QFileInfo file = m_file_system_model->fileInfo (*it);
623  if (file.exists ())
624  emit open_file (file.absoluteFilePath ());
625  }
626  }
627 
629  {
630  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
631  QModelIndexList rows = m->selectedRows ();
632 
633  for (auto it = rows.begin (); it != rows.end (); it++)
634  open_item_in_app (*it);
635  }
636 
638  {
639  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
640  QModelIndexList rows = m->selectedRows ();
641 
642  QStringList selection;
643 
644  for (auto it = rows.begin (); it != rows.end (); it++)
645  {
646  QFileInfo info = m_file_system_model->fileInfo (*it);
647 
648  selection << info.fileName ();
649  }
650 
651  QClipboard *clipboard = QApplication::clipboard ();
652 
653  clipboard->setText (selection.join ("\n"));
654  }
655 
657  {
658  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
659  QModelIndexList rows = m->selectedRows ();
660 
661  if (rows.size () > 0)
662  {
663  QModelIndex index = rows[0];
664 
665  QFileInfo info = m_file_system_model->fileInfo (index);
666 
667  emit load_file_signal (info.fileName ());
668  }
669  }
670 
672  {
673  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
674  QModelIndexList rows = m->selectedRows ();
675 
676  if (rows.size () > 0)
677  {
678  QModelIndex index = rows[0];
679 
680  QFileInfo info = m_file_system_model->fileInfo (index);
681  emit run_file_signal (info);
682  }
683  }
684 
686  {
687  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
688  QModelIndexList rows = m->selectedRows ();
689  if (rows.size () > 0)
690  {
691  QModelIndex index = rows[0];
692 
693  QFileInfo info = m_file_system_model->fileInfo (index);
694  QDir path = info.absoluteDir ();
695  QString old_name = info.fileName ();
696  bool ok;
697 
698  QString new_name
699  = QInputDialog::getText (this, tr ("Rename file/directory"),
700  tr ("Rename file/directory:\n")
701  + old_name + tr ("\n to: "),
702  QLineEdit::Normal, old_name, &ok);
703  if (ok && new_name.length () > 0)
704  {
705  new_name = path.absolutePath () + '/' + new_name;
706  old_name = path.absolutePath () + '/' + old_name;
707  // editor: close old
708  emit file_remove_signal (old_name, new_name);
709  // Do the renaming
710  QFile f (old_name); // Must use QFile, not QDir (bug #56298)
711  bool st = f.rename (new_name);
712  // editor: load new/old file depending on success
713  emit file_renamed_signal (st);
714  // Clear cache of file browser
715  m_file_system_model->revert ();
716  }
717  }
718 
719  }
720 
722  {
723  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
724  QModelIndexList rows = m->selectedRows ();
725 
726  for (auto it = rows.begin (); it != rows.end (); it++)
727  {
728  QModelIndex index = *it;
729 
730  QFileInfo info = m_file_system_model->fileInfo (index);
731 
732  if (QMessageBox::question (this, tr ("Delete file/directory"),
733  tr ("Are you sure you want to delete\n")
734  + info.filePath (),
735  QMessageBox::Yes | QMessageBox::No)
736  == QMessageBox::Yes)
737  {
738  if (info.isDir ())
739  {
740  // see if directory is empty
741  QDir path (info.absoluteFilePath ());
742  QList<QFileInfo> fileLst = path.entryInfoList (
743  QDir::Hidden | QDir::AllEntries |
744  QDir::NoDotAndDotDot | QDir::System);
745 
746  if (fileLst.count () != 0)
747  QMessageBox::warning (this, tr ("Delete file/directory"),
748  tr ("Can not delete a directory that is not empty"));
749  else
750  m_file_system_model->rmdir (index);
751  }
752  else
753  {
754  // Close the file in the editor if open
755  emit file_remove_signal (info.filePath (), QString ());
756  // Remove the file.
757  bool st = m_file_system_model->remove (index);
758  // Reload the old file if removing was not successful
759  if (! st)
760  emit file_renamed_signal (false);
761  }
762 
763  m_file_system_model->revert ();
764 
765  }
766  }
767  }
768 
769  // Get the currently selected files/dirs and return their file info
770  // in a list.
772  {
773  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
774  QModelIndexList rows = m->selectedRows ();
775 
776  QList<QFileInfo> infos;
777 
778  for (auto it = rows.begin (); it != rows.end (); it++)
779  {
780  QModelIndex index = *it;
781 
782  QFileInfo info = m_file_system_model->fileInfo (index);
783 
784  if (info.exists () &&
785  ((dir & info.isDir ()) || (! dir && info.isFile ())))
786  infos.append (info);
787  }
788 
789  return infos;
790  }
791 
793  {
794  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
795  QModelIndexList rows = m->selectedRows ();
796 
797  if (rows.size () > 0)
798  {
799  QModelIndex index = rows[0];
800 
801  QFileInfo info = m_file_system_model->fileInfo (index);
802  QString parent_dir = info.filePath ();
803 
804  process_new_file (parent_dir);
805  }
806  }
807 
809  {
810  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
811  QModelIndexList rows = m->selectedRows ();
812 
813  if (rows.size () > 0)
814  {
815  QModelIndex index = rows[0];
816 
817  QFileInfo info = m_file_system_model->fileInfo (index);
818  QString parent_dir = info.filePath ();
819 
820  process_new_dir (parent_dir);
821  }
822  }
823 
825  {
827 
828  if (infos.length () > 0 && infos.first ().isDir ())
829  process_set_current_dir (infos.first ().absoluteFilePath ());
830  }
831 
832  void files_dock_widget::contextmenu_add_to_path (bool, bool rm, bool subdirs)
833  {
835 
836  octave_value_list dir_list = ovl ();
837 
838  for (int i = 0; i < infos.length (); i++)
839  dir_list.append (infos.at (i).absoluteFilePath ().toStdString ());
840 
841  if (infos.length () > 0)
842  emit modify_path_signal (dir_list, rm, subdirs);
843  }
844 
846  {
847  contextmenu_add_to_path (true, false, true);
848  }
849 
851  {
852  contextmenu_add_to_path (true, true, false);
853  }
854 
856  {
857  contextmenu_add_to_path (true, true, true);
858  }
859 
861  {
862  QItemSelectionModel *m = m_file_tree_view->selectionModel ();
863  QModelIndexList rows = m->selectedRows ();
864 
865  if (rows.size () > 0)
866  {
867  QModelIndex index = rows[0];
868 
869  QFileInfo info = m_file_system_model->fileInfo (index);
870 
871  if (info.isDir ())
872  {
873  process_find_files (info.absoluteFilePath ());
874  }
875  }
876  }
877 
879  {
880  // QSettings pointer is checked before emitting.
881 
882  int size_idx = settings->value (global_icon_size).toInt ();
883  size_idx = (size_idx > 0) - (size_idx < 0) + 1; // Make valid index from 0 to 2
884 
885  QStyle *st = style ();
886  int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
887  m_navigation_tool_bar->setIconSize (QSize (icon_size,icon_size));
888 
889  // filenames are always shown, other columns can be hidden by settings
890  for (int i = 0; i < 3; i++)
891  m_file_tree_view->setColumnHidden (i + 1,
892  ! settings->value (m_columns_shown_keys.at (i),false).toBool ());
893 
894  QDir::Filters current_filter = m_file_system_model->filter ();
895  if (settings->value (m_columns_shown_keys.at (3),false).toBool ())
896  m_file_system_model->setFilter (current_filter | QDir::Hidden);
897  else
898  m_file_system_model->setFilter (current_filter & (~QDir::Hidden));
899 
900  m_file_tree_view->setAlternatingRowColors
901  (settings->value (m_columns_shown_keys.at (4),true).toBool ());
903 
904  // enable the buttons to sync octave/browser dir
905  // only if this is not done by default
907  = settings->value (fb_sync_octdir).toBool ();
910 
911  // If m_sync_octave_dir is enabled, then we want the file browser to
912  // update to match the current working directory of the
913  // interpreter. We don't want to queue any signal to change the
914  // interpreter's current working directory. In this case, we just
915  // want the GUI to match the state of the interpreter.
916 
917  if (m_sync_octave_dir)
919  }
920 
922  {
924 
925  if (dir.isEmpty ())
926  dir = QDir::homePath ();
927 
928  set_current_directory (dir);
929  }
930 
932  {
933  // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
934  int opts = QFileDialog::ShowDirsOnly;
937  if (! settings->value (global_use_native_dialogs).toBool ())
938  opts |= QFileDialog::DontUseNativeDialog;
939 
940  QString dir = QFileDialog::getExistingDirectory (this,
941  tr ("Set directory of file browser"),
942  m_file_system_model->rootPath (),
943  QFileDialog::Option (opts));
944  set_current_directory (dir);
945  }
946 
948  {
950  }
951 
953  {
954  process_new_dir (m_file_system_model->rootPath ());
955  }
956 
958  {
959  process_new_file (m_file_system_model->rootPath ());
960  }
961 
962  void files_dock_widget::process_new_file (const QString& parent_dir)
963  {
964  bool ok;
965 
966  QString name = QInputDialog::getText (this, tr ("Create File"),
967  tr ("Create file in\n","String ends with \\n!") + parent_dir,
968  QLineEdit::Normal,
969  tr ("New File.txt"), &ok);
970  if (ok && name.length () > 0)
971  {
972  name = parent_dir + '/' + name;
973 
974  QFile file (name);
975  file.open (QIODevice::WriteOnly);
976  m_file_system_model->revert ();
977  }
978  }
979 
980  void files_dock_widget::process_new_dir (const QString& parent_dir)
981  {
982  bool ok;
983 
984  QString name = QInputDialog::getText (this, tr ("Create Directory"),
985  tr ("Create folder in\n","String ends with \\n!") + parent_dir,
986  QLineEdit::Normal,
987  tr ("New Directory"), &ok);
988  if (ok && name.length () > 0)
989  {
990  QDir dir (parent_dir);
991  dir.mkdir (name);
992  m_file_system_model->revert ();
993  }
994  }
995 
997  {
998  emit displayed_directory_changed (dir);
999  }
1000 
1001  void files_dock_widget::process_find_files (const QString & dir)
1002  {
1003  emit find_files_signal (dir);
1004  }
1005 
1007  {
1008  if (m_file_tree_view->hasFocus ())
1010  if (m_current_directory->hasFocus ())
1011  {
1012  QClipboard *clipboard = QApplication::clipboard ();
1013 
1014  QLineEdit *edit = m_current_directory->lineEdit ();
1015  if (edit && edit->hasSelectedText ())
1016  {
1017  clipboard->setText (edit->selectedText ());
1018  }
1019  }
1020  }
1021 
1023  {
1024  if (m_current_directory->hasFocus ())
1025  {
1026  QClipboard *clipboard = QApplication::clipboard ();
1027  QString str = clipboard->text ();
1028  QLineEdit *edit = m_current_directory->lineEdit ();
1029  if (edit && str.length () > 0)
1030  edit->insert (str);
1031  }
1032  }
1033 
1035  {
1036  if (m_file_tree_view->hasFocus ())
1037  m_file_tree_view->selectAll ();
1038  if (m_current_directory->hasFocus ())
1039  {
1040  QLineEdit *edit = m_current_directory->lineEdit ();
1041  if (edit)
1042  {
1043  edit->selectAll ();
1044  }
1045  }
1046  }
1047 }
void mousePressEvent(QMouseEvent *e)
~FileTreeViewer(void)=default
Base class for Octave interfaces that use Qt.
resource_manager & get_resource_manager(void)
void contextmenu_copy_selection(bool)
Context menu actions.
void contextmenu_rm_from_path_subdirs(bool)
Context menu actions.
QString m_octave_dir
The actual Octave directory.
void contextmenu_add_to_path_subdirs(bool)
Context menu actions.
void contextmenu_add_to_path(bool, bool rm=false, bool subdirs=false)
Context menu actions.
void process_new_dir(const QString &parent_name)
void do_sync_browser_directory(void)
Slot for handling the sync browser directory button in the toolbar.
void open_item_in_app(const QModelIndex &index)
void process_new_file(const QString &parent_name)
Process new file/directory actions.
void headercontextmenu_requested(const QPoint &pos)
void contextmenu_run(bool)
Context menu actions.
void open_file(const QString &fileName)
Emitted, whenever the user requested to open a file.
void open_any_signal(const QString &fileName)
Emitted, whenever the user requested to open an unknown type file.
void update_octave_directory(const QString &dir)
Set the internal variable that holds the actual octave variable.
void contextmenu_rm_from_path(bool)
Context menu actions.
void process_set_current_dir(const QString &parent_name)
Process setting current dir or find in files.
QList< QFileInfo > get_selected_items_info(bool)
Get currently selected QFileInfo object.
QTreeView * m_file_tree_view
The file system view.
void notice_settings(const gui_settings *settings)
Tells the widget to react on changed settings.
void contextmenu_load(bool)
Context menu actions.
void copyClipboard()
Inherited from octave_doc_widget.
void selectAll()
Inherited from octave_doc_widget.
QToolBar * m_navigation_tool_bar
Variables for the actions.
void change_directory_up(void)
Slot for handling the up-directory button in the toolbar.
void run_file_signal(const QFileInfo &info)
Emitted, whenever the user requested to run a file.
void accept_directory_line_edit(void)
Accepts user input a the line edit for the current directory.
void popdownmenu_newdir(bool)
Popdown menu options.
void contextmenu_newdir(bool)
Context menu actions.
void display_directory(const QString &dir, bool set_octave_dir=true)
set a new directory or open a file
void popdownmenu_search_dir(bool)
Popdown menu options.
void popdownmenu_home(bool)
Popdown menu options.
void contextmenu_open(bool)
Context menu actions.
files_dock_widget(QWidget *parent, base_qobject &oct_qobj)
void contextmenu_open_in_editor(bool)
Context menu actions.
void item_double_clicked(const QModelIndex &index)
Slot for handling a change in directory via double click.
bool m_sync_octave_dir
Flag if syncing with Octave.
void pasteClipboard()
Inherited from octave_doc_widget.
void contextmenu_newfile(bool)
Context menu actions.
QFileSystemModel * m_file_system_model
The file system model.
void contextmenu_requested(const QPoint &pos)
Context menu wanted.
void do_sync_octave_directory(void)
Slot for handling the sync octave directory button in the toolbar.
void file_remove_signal(const QString &old_name, const QString &new_name)
Emitted, whenever the user removes or renames a file.
void popdownmenu_findfiles(bool)
Popdown menu options.
QComboBox * m_current_directory
The file system view.
void process_find_files(const QString &dir_name)
void contextmenu_rename(bool)
Context menu actions.
QList< QVariant > m_columns_shown_defs
void find_files_signal(const QString &startdir)
Emitted, whenever wants to search for a file .
void contextmenu_setcurrentdir(bool)
Context menu actions.
void contextmenu_delete(bool)
Context menu actions.
void load_file_signal(const QString &fileName)
Emitted, whenever the user requested to load a file in the text editor.
void popdownmenu_newfile(bool)
Popdown menu options.
void set_current_directory(const QString &dir)
Sets the current directory being displayed.
void file_renamed_signal(bool)
Emitted, when a file or directory is renamed.
void contextmenu_findfiles(bool)
Context menu actions.
void modify_path_signal(const octave_value_list &dir_list, bool rm, bool subdirs)
Emitted, when the path has to be modified.
void contextmenu_open_in_app(bool)
Context menu actions.
void displayed_directory_changed(const QString &dir)
Emitted, whenever the currently displayed directory changed.
void set_title(const QString &)
QMainWindow * main_win(void)
gui_settings * get_settings(void) const
QIcon icon(const QString &icon_name, bool fallback=true)
static std::string get_home_directory(void)
Definition: oct-env.cc:147
octave_value_list & append(const octave_value &val)
Definition: ovl.cc:98
void warning(const char *fmt,...)
Definition: error.cc:1050
QString path
QString name
const gui_pref fb_mru_list("filesdockwidget/mru_dir_list", QVariant(QStringList()))
const gui_pref fb_column_state("filesdockwidget/column_state", QVariant())
const gui_pref fb_show_date("filesdockwidget/showLastModified", QVariant(false))
const gui_pref fb_sync_octdir("filesdockwidget/sync_octave_directory", QVariant(true))
const gui_pref fb_sort_order("filesdockwidget/sort_files_by_order", QVariant(Qt::AscendingOrder))
const gui_pref fb_sort_column("filesdockwidget/sort_files_by_column", QVariant(0))
const gui_pref fb_show_type("filesdockwidget/showFileType", QVariant(false))
const gui_pref fb_show_hidden("filesdockwidget/showHiddenFiles", QVariant(false))
const gui_pref fb_startup_dir("filesdockwidget/startup_dir", QVariant(QString()))
const gui_pref fb_show_size("filesdockwidget/showFileSize", QVariant(false))
const gui_pref fb_txt_file_ext("filesdockwidget/txt_file_extensions", QVariant("m;c;cc;cpp;h;txt"))
const gui_pref fb_restore_last_dir("filesdockwidget/restore_last_dir", QVariant(false))
const gui_pref fb_show_altcol("filesdockwidget/useAlternatingRowColors", QVariant(true))
const QStyle::PixelMetric global_icon_sizes[3]
const gui_pref global_use_native_dialogs("use_native_file_dialogs", QVariant(true))
const gui_pref global_icon_size("toolbar_icon_size", QVariant(0))
T octave_idx_type m
Definition: mx-inlines.cc:773
QString fromStdString(const std::string &s)
static double f(double k, double l_nu, double c_pm)
Definition: randpoisson.cc:118
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
const QString key
const QVariant def