changeset 16549:3cd80afc3509

improve debugging with the GUI * dialog.h, dialog.cc (cd_or_addpath_dialog): New class. (QUIWidgetCreator::signal_debug_cd_or_addpath): New function. (QUIWidgetCreator::create_debug_cd_or_addpath_dialog): New signal. * file-editor-tab.h, file-editor-tab.cc (file_editor_tab::file_in_path): New function. (file_editor_tab::add_breakpoint_callback, file_editor_tab::remove_breakpoint_callback, file_editor_tab::remove_all_breakpoints_callback): Use file_in_path. Don't cd to the directory containing the file. Don't add 1 to the line number. (file_editor_tab::request_add_breakpoint, file_editor_tab::request_remove_breakpoint): Add 1 to the line number. (file_editor_tab::insert_debugger_pointer, file_editor_tab::delete_debugger_pointer, file_editor_tab::do_breakpoint_marker): Subtract 1 from line. (file_editor_tab::bp_info): Also cache full file name. Change all uses. * file-editor.h, file-editor.cc (file_editor::request_open_file, file_editor::handle_delete_debugger_pointer_request): Don't subtract 1 from line numbers. * main-window.h, main-window.cc (main_window::connect_uiwidget_links): Connect uiwidget_creator::create_debug_cd_or_addpath_dialog to main_window::handle_create_debug_cd_or_addpath_dialog. (main_window::handle_create_debug_cd_or_addpath_dialog): New function. * octave-qt-link.h, octave-qt-link.cc (octave_qt_link::do_debug_cd_or_addpath_error): New function. * load-path.h, load-path.cc (load_path::contains_canonical, load_path::do_contains_canonical): New functions. * octave-link.h (octave_link::debug_cd_or_addpath_error, octave_link::do_debug_cd_or_addpath_error): New functions.
author John W. Eaton <jwe@octave.org>
date Fri, 19 Apr 2013 17:36:40 -0400
parents c1e90c7cfd30
children 7a4fd41ac823
files libgui/src/dialog.cc libgui/src/dialog.h libgui/src/m-editor/file-editor-tab.cc libgui/src/m-editor/file-editor-tab.h libgui/src/m-editor/file-editor.cc libgui/src/main-window.cc libgui/src/main-window.h libgui/src/octave-qt-link.cc libgui/src/octave-qt-link.h libinterp/interpfcn/load-path.cc libinterp/interpfcn/load-path.h libinterp/interpfcn/octave-link.h
diffstat 12 files changed, 300 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/dialog.cc
+++ b/libgui/src/dialog.cc
@@ -377,9 +377,89 @@
   done (QDialog::Rejected);
 }
 
-
+  
 void
 InputDialog::reject (void)
 {
   buttonCancel_clicked ();
 }
+
+
+cd_or_addpath_dialog::cd_or_addpath_dialog (const QString& file,
+                                            const QString& dir,
+                                            bool addpath_option)
+  : QDialog ()
+{
+  QString prompt_string
+    = (addpath_option
+       ? tr ("The file %1 does not exist in the load path.  To debug the function you are editing, you must either change to the directory %2 or add that directory to the load path.").arg(file).arg(dir)
+       : tr ("The file %1 is shadowed by a file with the same name in the load path.  To debug the function you are editing, change to the directory %2.").arg(file).arg(dir));
+
+  QLabel *label = new QLabel (prompt_string);
+  label->setFixedWidth (500);
+  label->setWordWrap (true);
+  //    QIcon *question_mark = new QIcon;
+  QHBoxLayout *horizontalLayout = new QHBoxLayout;
+  //    horizontalLayout->addWidget (question_mark);
+  horizontalLayout->addWidget (label);
+
+  QPushButton *buttonCd = new QPushButton (tr ("Change directory"));
+  QPushButton *buttonAddpath = 0;
+  if (addpath_option)
+    buttonAddpath = new QPushButton (tr ("Add directory to load path"));
+  QPushButton *buttonCancel = new QPushButton (tr ("Cancel"));
+
+  QHBoxLayout *buttonsLayout = new QHBoxLayout;
+  buttonsLayout->addStretch (1);
+  buttonsLayout->addWidget (buttonCd);
+  if (addpath_option)
+    buttonsLayout->addWidget (buttonAddpath);
+  buttonsLayout->addWidget (buttonCancel);
+
+  QVBoxLayout *mainLayout = new QVBoxLayout;
+  mainLayout->addLayout (horizontalLayout);
+  mainLayout->addSpacing (12);
+  mainLayout->addLayout (buttonsLayout);
+  setLayout (mainLayout);
+
+  setWindowTitle (tr ("Change Directory or Add Directory to Load Path"));
+
+  connect (buttonCd, SIGNAL (clicked ()),
+           this, SLOT (buttonCd_clicked ()));
+
+  connect (buttonAddpath, SIGNAL (clicked ()),
+           this, SLOT (buttonAddpath_clicked ()));
+
+  connect (buttonCancel, SIGNAL (clicked ()),
+           this, SLOT (buttonCancel_clicked ()));
+
+  connect (this, SIGNAL (finished (int)),
+           &uiwidget_creator, SLOT (dialog_finished (int)));
+}
+
+void
+cd_or_addpath_dialog::buttonCd_clicked (void)
+{
+  emit finished (1);
+  done (QDialog::Accepted);
+}
+
+void
+cd_or_addpath_dialog::buttonAddpath_clicked (void)
+{
+  emit finished (2);
+  done (QDialog::Accepted);
+}
+
+void
+cd_or_addpath_dialog::buttonCancel_clicked (void)
+{
+  emit finished (-1);
+  done (QDialog::Rejected);
+}
+  
+void
+cd_or_addpath_dialog::reject (void)
+{
+  buttonCancel_clicked ();
+}
--- a/libgui/src/dialog.h
+++ b/libgui/src/dialog.h
@@ -101,6 +101,17 @@
     return true;
   };
 
+  // The debug dialog functionality may not really belong here, but it
+  // seems like the easiest thing to do at the moment.
+
+  bool signal_debug_cd_or_addpath (const QString& file, const QString& dir,
+                                   bool addpath_option)
+  {
+    emit create_debug_cd_or_addpath_dialog (file, dir, addpath_option);
+
+    return true;
+  }
+
   const QStringList *get_string_list (void) { return string_list; }
   
   void wait (void)
@@ -122,6 +133,8 @@
                            const QIntList&, const QIntList&,
                            const QStringList&);
 
+  void create_debug_cd_or_addpath_dialog (const QString&, const QString&, bool);
+
 public slots:
 
   void dialog_finished (int result);
@@ -219,4 +232,24 @@
   void reject (void);
 };
 
+class cd_or_addpath_dialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+
+  cd_or_addpath_dialog (const QString& file, const QString& dir,
+                        bool addpath_option);
+
+public slots:
+
+  void buttonCd_clicked (void);
+
+  void buttonAddpath_clicked (void);
+
+  void buttonCancel_clicked (void);
+
+  void reject (void);
+};
+
 #endif
--- a/libgui/src/m-editor/file-editor-tab.cc
+++ b/libgui/src/m-editor/file-editor-tab.cc
@@ -47,10 +47,13 @@
 
 #include "file-editor-tab.h"
 #include "file-editor.h"
+
+#include "builtin-defun-decls.h"
+#include "debug.h"
+#include "load-path.h"
 #include "octave-link.h"
-
-#include "debug.h"
 #include "oct-env.h"
+#include "utils.h"
 
 // Make parent null for the file editor tab so that warning
 // WindowModal messages don't affect grandparents.
@@ -195,13 +198,9 @@
       else
         {
           if (markers_mask && (1 << breakpoint))
-            {
-              request_remove_breakpoint (line);
-            }
+            request_remove_breakpoint (line);
           else
-            {
-              request_add_breakpoint (line);
-            }
+            request_add_breakpoint (line);
         }
     }
 }
@@ -431,42 +430,96 @@
   _edit_area->markerDeleteAll (bookmark);
 }
 
+bool
+file_editor_tab::file_in_path (const bp_info& info)
+{
+  bool ok = false;
+  bool addpath_option = true;
+
+  std::string curr_dir = octave_env::get_current_directory ();
+
+  if (curr_dir == info.path)
+    ok = true;
+  else
+    {
+      bool dir_in_load_path = load_path::contains_canonical (info.path);
+
+      std::string base_file = octave_env::base_pathname (info.file);
+      std::string lp_file = load_path::find_file (base_file);
+
+      if (dir_in_load_path)
+        {
+          if (same_file (lp_file, info.file))
+            ok = true;
+        }
+      else
+        {
+          // File directory is not in path.  Is the file in the path in
+          // the current directory?  If so, then changing the current
+          // directory will be needed.  Adding directory to path is
+          // not enough because the file in the current directory would
+          // still be found.
+
+          if (same_file (lp_file, base_file))
+            {
+              if (same_file (curr_dir, info.path))
+                ok = true;
+              else
+                addpath_option = false;
+            }
+        }
+    }
+
+  if (! ok)
+    {
+      int action
+        = octave_link::debug_cd_or_addpath_error (info.file, info.path,
+                                                  addpath_option);
+      switch (action)
+        {
+        case 1:
+          Fcd (ovl (info.path));
+          ok = true;
+          break;
+
+        case 2:
+          load_path::prepend (info.path);
+          ok = true;
+          break;
+
+        default:
+          break;
+        }
+    }
+
+  return ok;
+}
+
 void
 file_editor_tab::add_breakpoint_callback (const bp_info& info)
 {
-  bp_table::intmap intmap;
-  intmap[0] = info.line + 1;
+  bp_table::intmap line_info;
+  line_info[0] = info.line;
 
-  std::string previous_directory = octave_env::get_current_directory ();
-  octave_env::chdir (info.path);
-  intmap = bp_table::add_breakpoint (info.function_name, intmap);
-  octave_env::chdir (previous_directory);
-  // bp_table::add_breakpoint also sets the marker in the editor
+  if (file_in_path (info))
+    bp_table::add_breakpoint (info.function_name, line_info);
 }
 
 void
 file_editor_tab::remove_breakpoint_callback (const bp_info& info)
 {
-  bp_table::intmap intmap;
-  intmap[0] = info.line + 1;
+  bp_table::intmap line_info;
+  line_info[0] = info.line;
 
-  std::string previous_directory = octave_env::get_current_directory ();
-  octave_env::chdir (info.path);
-  bp_table::remove_breakpoint (info.function_name, intmap);
-  octave_env::chdir (previous_directory);
+  if (file_in_path (info))
+    bp_table::remove_breakpoint (info.function_name, line_info);
 }
 
 void
 file_editor_tab::remove_all_breakpoints_callback (const bp_info& info)
 {
-  bp_table::intmap intmap;
-  std::string previous_directory = octave_env::get_current_directory ();
-  octave_env::chdir (info.path);
-  intmap = bp_table::remove_all_breakpoints_in_file (info.function_name, true);
-  octave_env::chdir (previous_directory);
-
-  if (intmap.size() > 0)
-    _edit_area->markerDeleteAll (breakpoint);
+  if (file_in_path (info))
+    bp_table::remove_all_breakpoints_in_file (info.function_name, true);
 }
 
 void
@@ -479,7 +532,7 @@
   // We have to cut off the suffix, because octave appends it.
   function_name.chop (file_info.suffix ().length () + 1);
 
-  bp_info info (path, function_name, line);
+  bp_info info (_file_name, path, function_name, line+1);
 
   octave_link::post_event
     (this, &file_editor_tab::add_breakpoint_callback, info);
@@ -495,7 +548,7 @@
   // We have to cut off the suffix, because octave appends it.
   function_name.chop (file_info.suffix ().length () + 1);
 
-  bp_info info (path, function_name, line);
+  bp_info info (_file_name, path, function_name, line+1);
 
   octave_link::post_event
     (this, &file_editor_tab::remove_breakpoint_callback, info);
@@ -556,7 +609,7 @@
   // We have to cut off the suffix, because octave appends it.
   function_name.chop (file_info.suffix ().length () + 1);
 
-  bp_info info (path, function_name, 0);
+  bp_info info (_file_name, path, function_name, 0);
 
   octave_link::post_event
     (this, &file_editor_tab::remove_all_breakpoints_callback, info);
@@ -1143,7 +1196,7 @@
 
   if (line > 0)
     {
-      _edit_area->markerAdd (line, debugger_position);
+      _edit_area->markerAdd (line-1, debugger_position);
       center_current_line ();
     }
 }
@@ -1155,7 +1208,7 @@
     return;
 
   if (line > 0)
-    _edit_area->markerDelete (line, debugger_position);
+    _edit_area->markerDelete (line-1, debugger_position);
 }
 
 void
@@ -1167,9 +1220,9 @@
   if (line > 0)
     {
       if (insert)
-        _edit_area->markerAdd (line, breakpoint);
+        _edit_area->markerAdd (line-1, breakpoint);
       else
-        _edit_area->markerDelete (line, breakpoint);
+        _edit_area->markerDelete (line-1, breakpoint);
     }
 }
 
--- a/libgui/src/m-editor/file-editor-tab.h
+++ b/libgui/src/m-editor/file-editor-tab.h
@@ -122,10 +122,12 @@
 
   struct bp_info
   {
-    bp_info (const QString& p, const QString& fn, int l)
-      : path (p.toStdString ()), function_name (fn.toStdString ()), line (l)
+    bp_info (const QString& f, const QString& p, const QString& fn, int l)
+      : file (f.toStdString ()), path (p.toStdString ()),
+        function_name (fn.toStdString ()), line (l)
     { }
 
+    std::string file;
     std::string path;
     std::string function_name;
     int line;
@@ -143,6 +145,9 @@
   void do_comment_selected_text (bool comment);
 
   void run_file_callback (void);
+
+  bool file_in_path (const bp_info& info);
+
   void add_breakpoint_callback (const bp_info& info);
   void remove_breakpoint_callback (const bp_info& info);
   void remove_all_breakpoints_callback (const bp_info& info);
--- a/libgui/src/m-editor/file-editor.cc
+++ b/libgui/src/m-editor/file-editor.cc
@@ -230,10 +230,10 @@
               emit fetab_goto_line (tab, line);
 
               if (debug_pointer)
-                emit fetab_insert_debugger_pointer (tab, line-1);
+                emit fetab_insert_debugger_pointer (tab, line);
 
               if (breakpoint_marker)
-                emit fetab_do_breakpoint_marker (insert, tab, line-1);
+                emit fetab_do_breakpoint_marker (insert, tab, line);
             }
 
           emit fetab_set_focus (tab);
@@ -258,10 +258,11 @@
                       emit fetab_goto_line (fileEditorTab, line);
 
                       if (debug_pointer)
-                        emit fetab_insert_debugger_pointer (fileEditorTab, line-1);
+                        emit fetab_insert_debugger_pointer (fileEditorTab,
+                                                            line);
                       if (breakpoint_marker)
-                        emit fetab_do_breakpoint_marker
-                          (insert, fileEditorTab, line-1);
+                        emit fetab_do_breakpoint_marker (insert, fileEditorTab,
+                                                         line);
                     }
                 }
               else
@@ -380,7 +381,7 @@
           _tab_widget->setCurrentWidget (tab);
 
           if (line > 0)
-            emit fetab_delete_debugger_pointer (tab, line-1);
+            emit fetab_delete_debugger_pointer (tab, line);
 
           emit fetab_set_focus (tab);
         }
--- a/libgui/src/main-window.cc
+++ b/libgui/src/main-window.cc
@@ -592,6 +592,14 @@
            SLOT (handle_create_inputlayout (const QStringList&, const QString&,
                                             const QIntList&, const QIntList&,
                                             const QStringList&)));
+
+  connect (&uiwidget_creator,
+           SIGNAL (create_debug_cd_or_addpath_dialog (const QString&,
+                                                      const QString&, bool)),
+           this,
+           SLOT (handle_create_debug_cd_or_addpath_dialog (const QString&,
+                                                           const QString&,
+                                                           bool)));
 }
 
 // Create a message dialog with specified string, buttons and decorative
@@ -648,6 +656,19 @@
   input_dialog->show ();
 }
 
+void
+main_window::handle_create_debug_cd_or_addpath_dialog (const QString& file,
+                                                       const QString& dir,
+                                                       bool addpath_option)
+
+{
+  cd_or_addpath_dialog *dialog
+    = new cd_or_addpath_dialog (file, dir, addpath_option);
+
+  dialog->setAttribute (Qt::WA_DeleteOnClose);
+  dialog->show ();
+}
+
 // Main subroutine of the constructor
 void
 main_window::construct (void)
--- a/libgui/src/main-window.h
+++ b/libgui/src/main-window.h
@@ -142,6 +142,9 @@
                                   const QIntList&, const QIntList&,
                                   const QStringList&);
 
+  void handle_create_debug_cd_or_addpath_dialog (const QString& file,
+                                                 const QString& dir,
+                                                 bool addpath_option);
   // find files dialog 
   void find_files(const QString &startdir=QDir::currentPath());
   void find_files_finished(int);
--- a/libgui/src/octave-qt-link.cc
+++ b/libgui/src/octave-qt-link.cc
@@ -31,6 +31,7 @@
 #include "str-vec.h"
 
 #include "dialog.h"
+#include "error.h"
 #include "workspace-element.h"
 
 #include "octave-qt-link.h"
@@ -154,6 +155,20 @@
   return retval;
 }
 
+int
+octave_qt_link::do_debug_cd_or_addpath_error (const std::string& file,
+                                              const std::string& dir,
+                                              bool addpath_option)
+{
+  uiwidget_creator.signal_debug_cd_or_addpath (QString::fromStdString (file),
+                                               QString::fromStdString (dir),
+                                               addpath_option);
+
+  uiwidget_creator.wait ();
+
+  return uiwidget_creator.get_dialog_result ();
+}
+
 void
 octave_qt_link::do_change_directory (const std::string& dir)
 {
--- a/libgui/src/octave-qt-link.h
+++ b/libgui/src/octave-qt-link.h
@@ -79,6 +79,11 @@
                    const std::list<int>& nc,
                    const std::list<std::string>& defaults);
 
+  int
+  do_debug_cd_or_addpath_error (const std::string& file,
+                                const std::string& dir,
+                                bool addpath_option);
+
   void do_change_directory (const std::string& dir);
 
   void do_set_workspace (bool top_level,
--- a/libinterp/interpfcn/load-path.cc
+++ b/libinterp/interpfcn/load-path.cc
@@ -353,6 +353,25 @@
   return find_dir_info (dir) != dir_info_list.end ();
 }
 
+bool
+load_path::do_contains_canonical (const std::string& dir) const
+{
+  bool retval = false;
+
+  for (const_dir_info_list_iterator i = dir_info_list.begin ();
+       i != dir_info_list.end ();
+       i++)
+    {
+      if (same_file (dir, i->dir_name))
+        {
+          retval = true;
+          break;
+        }
+    }
+
+  return retval;
+}
+
 void
 load_path::move_fcn_map (const std::string& dir_name,
                          const string_vector& fcn_files, bool at_end)
--- a/libinterp/interpfcn/load-path.h
+++ b/libinterp/interpfcn/load-path.h
@@ -89,6 +89,11 @@
       instance->do_update ();
   }
 
+  static bool contains_canonical (const std::string& dir_name)
+  {
+    return instance_ok () ? instance->do_contains_canonical (dir_name) : false;
+  }
+
   static std::string find_method (const std::string& class_name,
                                   const std::string& meth,
                                   std::string& dir_name)
@@ -465,6 +470,8 @@
 
   bool contains (const std::string& dir) const;
 
+  bool do_contains_canonical (const std::string& dir) const;
+
   void move_fcn_map (const std::string& dir,
                      const string_vector& fcn_files, bool at_end);
 
--- a/libinterp/interpfcn/octave-link.h
+++ b/libinterp/interpfcn/octave-link.h
@@ -170,6 +170,14 @@
       : std::list<std::string> ();
   }
 
+  static int debug_cd_or_addpath_error (const std::string& file,
+                                        const std::string& dir,
+                                        bool addpath_option)
+  {
+    return enabled ()
+      ? instance->do_debug_cd_or_addpath_error (file, dir, addpath_option) : 0;
+  }
+
   static void change_directory (const std::string& dir)
   {
     if (enabled ())
@@ -341,6 +349,11 @@
                    const std::list<int>& nc,
                    const std::list<std::string>& defaults) = 0;
 
+  virtual int
+  do_debug_cd_or_addpath_error (const std::string& file,
+                                const std::string& dir,
+                                bool addpath_option) = 0;
+
   virtual void do_change_directory (const std::string& dir) = 0;
 
   virtual void