changeset 21158:65827e9cccb8

Gui support for enhancement of dbstop. * octave-qscintilla.cc (contextMenuEvent): Capture right-click in the left margins to show a context menu for "dbstop if...". * octave-qscintilla.{cc,h} (contextmenu_break_condition): new function * file-editor-interface.h: pass condition to handle_update_breakpoint_marker_request * file-editor-tab.{cc,h}: (file_editor_tab, bp_info, handle_request_add_breakpoint, next_breakpoint, previous_breakpoint, do_breakpoint_marker, add_breakpoint_callback): Allow conditional breakpoint markers * file-editor-tab.cc (handle_context_menu_break_condition): new function * file-editor.{cc,h} (request_open_file, add_file_editor_tab, handle_delete_debugger_pointer_request): pass bp conditions. * marker.{cc,h} (marker, construct, handle_report_editor_linenr): pass breakpoint conditions * main-window.{cc,h} (handle_update_breakpoint_marker_request): pass breakpoint condition. * octave-link.h (update_breakpoint): pass breakpoint condition. * octave-qt-link.{cc,h} (do_update_breakpoint): pass breakpoint condition.
author Lachlan Andrew <lachlanbis@gmail.com>
date Sat, 30 Jan 2016 10:13:34 +1100
parents 94fc5f13d51b
children 4aa8e4b868c9
files libgui/src/m-editor/file-editor-interface.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/m-editor/file-editor.h libgui/src/m-editor/marker.cc libgui/src/m-editor/marker.h libgui/src/m-editor/octave-qscintilla.cc libgui/src/m-editor/octave-qscintilla.h libgui/src/main-window.cc libgui/src/main-window.h libgui/src/octave-qt-link.cc libgui/src/octave-qt-link.h libinterp/corefcn/octave-link.h
diffstat 14 files changed, 348 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/m-editor/file-editor-interface.h	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/m-editor/file-editor-interface.h	Sat Jan 30 10:13:34 2016 +1100
@@ -56,7 +56,7 @@
 
   virtual void
   handle_update_breakpoint_marker_request (bool insert, const QString& file,
-                                           int line) = 0;
+                                           int line, const QString& cond) = 0;
 
   virtual void handle_edit_file_request (const QString& file) = 0;
 
@@ -76,7 +76,8 @@
                                   int line = -1,
                                   bool debug_pointer = false,
                                   bool breakpoint_marker = false,
-                                  bool insert = true) = 0;
+                                  bool insert = true,
+                                  const QString& cond = "") = 0;
 //signals:
 
 //protected:
--- a/libgui/src/m-editor/file-editor-tab.cc	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/m-editor/file-editor-tab.cc	Sat Jan 30 10:13:34 2016 +1100
@@ -74,6 +74,7 @@
 #include "version.h"
 #include "utils.h"
 #include "defaults.h"
+#include "unwind-prot.h"
 #include <oct-map.h>
 
 bool file_editor_tab::_cancelled = false;
@@ -103,7 +104,8 @@
   _line = 0;
   _col  = 0;
 
-  _bp_list.clear ();  // start with an empty list of breakpoints
+  _bp_lines.clear ();      // start with empty lists of breakpoints
+  _bp_conditions.clear ();
 
   connect (_edit_area, SIGNAL (cursorPositionChanged (int, int)),
            this, SLOT (handle_cursor_moved (int,int)));
@@ -155,6 +157,8 @@
   _edit_area->setMarkerBackgroundColor (QColor (0,0,232), marker::bookmark);
   _edit_area->markerDefine (QsciScintilla::Circle, marker::breakpoint);
   _edit_area->setMarkerBackgroundColor (QColor (192,0,0), marker::breakpoint);
+  _edit_area->markerDefine (QsciScintilla::Circle, marker::cond_break);
+  _edit_area->setMarkerBackgroundColor (QColor (255,127,0), marker::cond_break);
   _edit_area->markerDefine (QsciScintilla::RightTriangle, marker::debugger_position);
   _edit_area->setMarkerBackgroundColor (QColor (255,255,0), marker::debugger_position);
   _edit_area->markerDefine (QsciScintilla::RightTriangle,
@@ -166,6 +170,9 @@
            this, SLOT (handle_margin_clicked (int, int,
                                               Qt::KeyboardModifiers)));
 
+  connect (_edit_area, SIGNAL (context_menu_break_condition_signal (int)),
+           this, SLOT (handle_context_menu_break_condition (int)));
+
   // line numbers
   _edit_area->setMarginsForegroundColor (QColor (96, 96, 96));
   _edit_area->setMarginsBackgroundColor (QColor (232, 232, 220));
@@ -316,6 +323,83 @@
   emit edit_mfile_request (word_at_cursor, _file_name, _ced, -1);
 }
 
+// If "dbstop if ..." selected from context menu, create a conditional
+// breakpoint.  The default condition is (a) the existing condition if there
+// is already a breakpoint (b) any selected text, or (c) empty
+void
+file_editor_tab::handle_context_menu_break_condition (int linenr)
+{
+  QString cond;
+  bp_info info (_file_name, linenr);  // Get function name & dir from filename.
+
+  // Ensure editor line numbers match Octave core's line numbers.
+  // Give users the option to save modifications if necessary.
+  if (! unchanged_or_saved ()
+     || !(_main_win->get_octave_qt_link ()->file_in_path (info.file, info.dir)))
+    return;
+
+  // Search for previous condition.  FIXME -- is there a more direct way?
+  if (_edit_area->markersAtLine (linenr) & (1 << marker::cond_break))
+    {
+      emit report_marker_linenr (_bp_lines, _bp_conditions);
+      for (int i = 0; i < _bp_lines.length (); i++)
+        if (_bp_lines.value (i) == linenr)
+          {
+            cond = _bp_conditions.value (i);
+            break;
+          }
+      _bp_lines.clear ();
+    }
+
+  // If text selected by the mouse, default to that instead
+  // If both present, use the OR of them, to avoid accidental overwriting
+  // FIXME If both are present, show old condition unselected and
+  //       the selection (in edit area) selected (in the dialog).
+  if (_edit_area->hasSelectedText ())
+    {
+      if (cond == "")
+        cond = _edit_area->selectedText ();
+      else
+        cond = "(" + cond + ") || (" + _edit_area->selectedText () + ")";
+    }
+
+  bool valid = false;
+  std::string prompt = "dbstop if";
+  while (!valid)
+    {
+      bool ok;
+      QString new_condition
+        = QInputDialog::getText (this, tr ("Breakpoint condition"),
+                                 tr (prompt.c_str ()), QLineEdit::Normal, cond,
+                                 &ok);
+      if (ok)     // If cancel, don't change breakpoint condition.
+        {
+          bp_table::intmap line;
+          line[0] = linenr + 1;
+
+          try
+            {
+              // Suppress error messages on the console.
+              unwind_protect frame;
+              frame.protect_var (buffer_error_messages);
+              buffer_error_messages++;
+
+              bp_table::add_breakpoint (info.function_name, line,
+                                        new_condition.toStdString ());
+              valid = true;
+            }
+          catch (const octave_interrupt_exception&) { valid = true; }
+          catch (const index_exception& e) { }
+          catch (const octave_execution_exception& e) { }
+
+          // In case we repeat, set new prompt.
+          prompt = "ERROR: " + last_error_message () + "\n\ndbstop if";
+          cond = new_condition;
+        }
+      else
+        valid = true;
+    }
+}
 
 void
 file_editor_tab::set_file_name (const QString& fileName)
@@ -398,12 +482,13 @@
         }
       else
         {
-          if (markers_mask & (1 << marker::breakpoint))
+          if (markers_mask & ((1 << marker::breakpoint)
+                              | (1 << marker::cond_break)))
             handle_request_remove_breakpoint (editor_linenr + 1);
           else
             {
               if (unchanged_or_saved ())
-                handle_request_add_breakpoint (editor_linenr + 1);
+                handle_request_add_breakpoint (editor_linenr + 1, "");
             }
         }
     }
@@ -845,7 +930,7 @@
   line_info[0] = info.line;
 
   if (_main_win->get_octave_qt_link ()->file_in_path (info.file, info.dir))
-    bp_table::add_breakpoint (info.function_name, line_info);
+    bp_table::add_breakpoint (info.function_name, line_info, info.condition);
 }
 
 void
@@ -865,8 +950,9 @@
     bp_table::remove_all_breakpoints_in_file (info.function_name, true);
 }
 
-file_editor_tab::bp_info::bp_info (const QString& fname, int l)
-  : line (l), file (fname.toStdString ())
+file_editor_tab::bp_info::bp_info (const QString& fname, int l,
+                                   const QString& cond)
+  : line (l), file (fname.toStdString ()), condition (cond.toStdString ())
 {
   QFileInfo file_info (fname);
 
@@ -896,9 +982,10 @@
 }
 
 void
-file_editor_tab::handle_request_add_breakpoint (int line)
+file_editor_tab::handle_request_add_breakpoint (int line,
+                                                const QString& condition)
 {
-  bp_info info (_file_name, line);
+  bp_info info (_file_name, line, condition);
 
   octave_link::post_event
     (this, &file_editor_tab::add_breakpoint_callback, info);
@@ -927,11 +1014,11 @@
   else
     {
       if (unchanged_or_saved ())
-        handle_request_add_breakpoint (editor_linenr + 1);
+        handle_request_add_breakpoint (editor_linenr + 1, "");
     }
 }
 
-// Move the text cursor to the closest breakpoint
+// Move the text cursor to the closest breakpoint (conditional or unconditional)
 // after the current line.
 void
 file_editor_tab::next_breakpoint (const QWidget *ID)
@@ -945,11 +1032,16 @@
   line++; // Find breakpoint strictly after the current line.
 
   int nextline = _edit_area->markerFindNext (line, (1 << marker::breakpoint));
+  int nextcond = _edit_area->markerFindNext (line, (1 << marker::cond_break));
+
+  // Check if the next conditional breakpoint is before next unconditional one.
+  if (nextcond != -1 && (nextcond < nextline || nextline == -1))
+    nextline = nextcond;
 
   _edit_area->setCursorPosition (nextline, 0);
 }
 
-// Move the text cursor to the closest breakpoint
+// Move the text cursor to the closest breakpoint (conditional or unconditional)
 // before the current line.
 void
 file_editor_tab::previous_breakpoint (const QWidget *ID)
@@ -957,12 +1049,17 @@
   if (ID != this)
     return;
 
-  int line, cur, prevline;
+  int line, cur, prevline, prevcond;
   _edit_area->getCursorPosition (&line, &cur);
 
   line--; // Find breakpoint strictly before the current line.
 
   prevline = _edit_area->markerFindPrevious (line, (1 << marker::breakpoint));
+  prevcond = _edit_area->markerFindPrevious (line, (1 << marker::cond_break));
+
+  // Check if the prev conditional breakpoint is closer than the unconditional.
+  if (prevcond != -1 && prevcond > prevline)
+    prevline = prevcond;
 
   _edit_area->setCursorPosition (prevline, 0);
 }
@@ -1405,18 +1502,19 @@
 void
 file_editor_tab::check_restore_breakpoints ()
 {
-  if (! _bp_list.isEmpty ())
+  if (! _bp_lines.isEmpty ())
     {
       // At least one breakpoint is present.
       // Get rid of breakpoints at old (now possibly invalid) linenumbers
       remove_all_breakpoints (this);
 
       // and set breakpoints at the new linenumbers
-      for (int i = 0; i < _bp_list.length (); i++)
-        handle_request_add_breakpoint (_bp_list.value (i) + 1);
+      for (int i = 0; i < _bp_lines.length (); i++)
+        handle_request_add_breakpoint (_bp_lines.value (i) + 1,
+                                       _bp_conditions.value (i));
 
      // reset the list of breakpoints
-      _bp_list.clear ();
+      _bp_lines.clear ();
     }
 }
 
@@ -1613,7 +1711,7 @@
   QFile file (file_to_save);
 
   // Get a list of all the breakpoint line numbers.
-  emit report_editor_linenr (_bp_list);
+  emit report_marker_linenr (_bp_lines, _bp_conditions);
 
   // stop watching file
   QStringList trackedFiles = _file_system_watcher.files ();
@@ -2225,7 +2323,8 @@
           // isn't certain whether the original line number and current line
           // number match.
           int editor_linenr = -1;
-          emit find_translated_line_number (line, editor_linenr);
+          marker *dummy;
+          emit find_translated_line_number (line, editor_linenr, dummy);
           if (editor_linenr != -1)
             {
               // Match with an existing breakpoint.
@@ -2277,7 +2376,8 @@
 }
 
 void
-file_editor_tab::do_breakpoint_marker (bool insert, const QWidget *ID, int line)
+file_editor_tab::do_breakpoint_marker (bool insert, const QWidget *ID, int line,
+                                       const QString& cond)
 {
   if (ID != this || ID == 0)
     return;
@@ -2287,30 +2387,48 @@
       if (insert)
         {
           int editor_linenr = -1;
-
-          // If comes back indicating a modified editor line number
-          // then there is already a breakpoint marker associated
-          // with this debugger line.
-          emit find_translated_line_number (line, editor_linenr);
-
-          if (editor_linenr == -1)
+          marker *bp = 0;
+
+          // If comes back indicating a non-zero breakpoint marker,
+          // reuse it if possible
+          emit find_translated_line_number (line, editor_linenr, bp);
+          if (bp != 0)
             {
-              marker *bp = new marker (_edit_area, line, marker::breakpoint);
-              connect (this, SIGNAL (remove_breakpoint_via_debugger_linenr (int)),
-                       bp,   SLOT (handle_remove_via_original_linenr (int)));
-              connect (this, SIGNAL (request_remove_breakpoint_via_editor_linenr (int)),
-                       bp,   SLOT (handle_request_remove_via_editor_linenr (int)));
-              connect (this, SIGNAL (remove_all_breakpoints (void)),
-                       bp,   SLOT (handle_remove (void)));
-              connect (this, SIGNAL (find_translated_line_number (int, int&)),
-                       bp,   SLOT (handle_find_translation (int, int&)));
-              connect (this, SIGNAL (find_linenr_just_before (int, int&, int&)),
-                       bp,   SLOT (handle_find_just_before (int, int&, int&)));
-              connect (this, SIGNAL (report_editor_linenr (QIntList&)),
-                       bp,   SLOT (handle_report_editor_linenr (QIntList&)));
-              connect (bp,   SIGNAL (request_remove (int)),
-                       this, SLOT (handle_request_remove_breakpoint (int)));
+              if ((cond == "") != (bp->get_cond () == ""))
+                {       // can only reuse conditional bp as conditional
+                  emit remove_breakpoint_via_debugger_linenr (line);
+                  bp = 0;
+                }
+              else
+                bp->set_cond (cond);
             }
+
+          if (bp == 0)
+            bp = new marker (_edit_area, line,
+                             cond == "" ? marker::breakpoint
+                                        : marker::cond_break, cond);
+
+          connect (this, SIGNAL (remove_breakpoint_via_debugger_linenr
+                                 (int)),
+                   bp,   SLOT (handle_remove_via_original_linenr (int)));
+          connect (this, SIGNAL (request_remove_breakpoint_via_editor_linenr
+                                 (int)),
+                   bp,   SLOT (handle_request_remove_via_editor_linenr
+                                 (int)));
+          connect (this, SIGNAL (remove_all_breakpoints (void)),
+                   bp,   SLOT (handle_remove (void)));
+          connect (this, SIGNAL (find_translated_line_number (int, int&,
+                                                              marker*&)),
+                   bp,   SLOT (handle_find_translation (int, int&,
+                                                        marker*&)));
+          connect (this, SIGNAL (find_linenr_just_before (int, int&, int&)),
+                   bp,   SLOT (handle_find_just_before (int, int&, int&)));
+          connect (this, SIGNAL (report_marker_linenr (QIntList&,
+                                                       QStringList&)),
+                   bp,   SLOT (handle_report_editor_linenr (QIntList&,
+                                                            QStringList&)));
+          connect (bp,   SIGNAL (request_remove (int)),
+                   this, SLOT (handle_request_remove_breakpoint (int)));
         }
       else
         emit remove_breakpoint_via_debugger_linenr (line);
--- a/libgui/src/m-editor/file-editor-tab.h	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/m-editor/file-editor-tab.h	Sat Jan 30 10:13:34 2016 +1100
@@ -128,7 +128,8 @@
   void insert_debugger_pointer (const QWidget *ID, int line = -1);
   void delete_debugger_pointer (const QWidget *ID, int line = -1);
 
-  void do_breakpoint_marker (bool insert, const QWidget *ID, int line = -1);
+  void do_breakpoint_marker (bool insert, const QWidget *ID, int line = -1,
+                             const QString& cond = "");
 
   void recover_from_exit (void);
   void set_modified (bool modified = true);
@@ -142,8 +143,9 @@
   void file_has_changed (const QString& fileName);
 
   void handle_context_menu_edit (const QString&);
+  void handle_context_menu_break_condition (int linenr);
 
-  void handle_request_add_breakpoint (int line);
+  void handle_request_add_breakpoint (int line, const QString& cond);
   void handle_request_remove_breakpoint (int line);
 
   void handle_octave_result (QObject *requester, QString& command, octave_value_list &result);
@@ -165,9 +167,9 @@
   void remove_breakpoint_via_debugger_linenr (int debugger_linenr);
   void request_remove_breakpoint_via_editor_linenr (int editor_linenr);
   void remove_all_breakpoints (void);
-  void find_translated_line_number (int original_linenr, int& translated_linenr);
+  void find_translated_line_number (int original_linenr, int& translated_linenr, marker*&);
   void find_linenr_just_before (int linenr, int& original_linenr, int& editor_linenr);
-  void report_editor_linenr (QIntList& int_list);
+  void report_marker_linenr (QIntList& lines, QStringList& conditions);
   void remove_position_via_debugger_linenr (int debugger_linenr);
   void remove_all_positions (void);
   // TODO: The following is similar to "process_octave_code" signal.  However,
@@ -215,12 +217,13 @@
 
   struct bp_info
   {
-    bp_info (const QString& fname, int l = 0);
+    bp_info (const QString& fname, int l = 0, const QString& cond = "");
 
     int line;
     std::string file;
     std::string dir;
     std::string function_name;
+    std::string condition;
   };
 
   bool valid_file_name (const QString& file=QString ());
@@ -279,7 +282,8 @@
 
   QFileSystemWatcher _file_system_watcher;
 
-  QIntList _bp_list;
+  QIntList _bp_lines;
+  QStringList _bp_conditions;
 
   find_dialog *_find_dialog;
   bool _find_dialog_is_visible;
--- a/libgui/src/m-editor/file-editor.cc	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/m-editor/file-editor.cc	Sat Jan 30 10:13:34 2016 +1100
@@ -404,11 +404,14 @@
     request_open_file (open_file_names.at (i), _file_encoding);
 }
 
+// Open a file, if not already open, and mark the current execution location
+// and/or a breakpoint with condition cond.
 void
 file_editor::request_open_file (const QString& openFileName,
                                 const QString& encoding,
                                 int line, bool debug_pointer,
-                                bool breakpoint_marker, bool insert)
+                                bool breakpoint_marker, bool insert,
+                                const QString& cond)
 {
   if (call_custom_editor (openFileName, line))
     return;   // custom editor called
@@ -440,7 +443,7 @@
                 emit fetab_insert_debugger_pointer (tab, line);
 
               if (breakpoint_marker)
-                emit fetab_do_breakpoint_marker (insert, tab, line);
+                emit fetab_do_breakpoint_marker (insert, tab, line, cond);
             }
 
           if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ()))
@@ -476,7 +479,7 @@
                                                             line);
                       if (breakpoint_marker)
                         emit fetab_do_breakpoint_marker (insert, fileEditorTab,
-                                                         line);
+                                                         line, cond);
                     }
                 }
               else
@@ -758,9 +761,10 @@
 void
 file_editor::handle_update_breakpoint_marker_request (bool insert,
                                                       const QString& file,
-                                                      int line)
+                                                      int line,
+                                                      const QString& cond)
 {
-  request_open_file (file, QString (), line, false, true, insert);
+  request_open_file (file, QString (), line, false, true, insert, cond);
 }
 
 void
@@ -887,6 +891,7 @@
   emit fetab_remove_bookmark (_tab_widget->currentWidget ());
 }
 
+// FIXME What should this do with conditional breakpoints?
 void
 file_editor::request_toggle_breakpoint (bool)
 {
@@ -1858,9 +1863,6 @@
   connect (_tab_widget, SIGNAL (currentChanged (int)),
            this, SLOT (active_tab_changed (int)));
 
-  connect (this, SIGNAL (execute_command_in_terminal_signal (const QString&)),
-           main_win (), SLOT (execute_command_in_terminal (const QString&)));
-
   resize (500, 400);
   setWindowIcon (QIcon (":/actions/icons/logo.png"));
   set_title (tr ("Editor"));
@@ -1981,6 +1983,9 @@
   connect (this, SIGNAL (fetab_check_modified_file (void)),
            f, SLOT (check_modified_file (void)));
 
+  connect (f, SIGNAL (execute_command_in_terminal_signal (const QString&)),
+           main_win (), SLOT (execute_command_in_terminal (const QString&)));
+
   // Signals from the file_editor trivial operations
   connect (this, SIGNAL (fetab_recover_from_exit (void)),
            f, SLOT (recover_from_exit (void)));
@@ -2080,8 +2085,9 @@
            f, SLOT (delete_debugger_pointer (const QWidget*, int)));
 
   connect (this, SIGNAL (fetab_do_breakpoint_marker (bool, const QWidget*,
-                                                     int)),
-           f, SLOT (do_breakpoint_marker (bool, const QWidget*, int)));
+                                                     int, const QString&)),
+           f, SLOT (do_breakpoint_marker (bool, const QWidget*, int,
+                                          const QString&)));
 
   _tab_widget->setCurrentWidget (f);
 
--- a/libgui/src/m-editor/file-editor.h	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/m-editor/file-editor.h	Sat Jan 30 10:13:34 2016 +1100
@@ -143,7 +143,7 @@
   void fetab_insert_debugger_pointer (const QWidget* ID, int line = -1);
   void fetab_delete_debugger_pointer (const QWidget* ID, int line = -1);
   void fetab_do_breakpoint_marker (bool insert, const QWidget* ID,
-                                   int line = -1);
+                                   int line = -1, const QString& = "");
   void fetab_set_focus (const QWidget* ID);
   void fetab_scintilla_command (const QWidget* ID, unsigned int sci_msg);
 
@@ -235,7 +235,8 @@
   void handle_insert_debugger_pointer_request (const QString& file, int line);
   void handle_delete_debugger_pointer_request (const QString& file, int line);
   void handle_update_breakpoint_marker_request (bool insert,
-                                                const QString& file, int line);
+                                                const QString& file, int line,
+                                                const QString& cond);
   void handle_edit_mfile_request (const QString& name, const QString& file,
                                   const QString& curr_dir, int line);
 
@@ -262,7 +263,8 @@
   void request_open_file (const QString& fileName,
                           const QString& encoding = QString (),
                           int line = -1, bool debug_pointer = false,
-                          bool breakpoint_marker = false, bool insert = true);
+                          bool breakpoint_marker = false, bool insert = true,
+                          const QString& cond = "");
   void request_preferences (bool);
   void request_styles_preferences (bool);
   void restore_create_file_setting ();
--- a/libgui/src/m-editor/marker.cc	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/m-editor/marker.cc	Sat Jan 30 10:13:34 2016 +1100
@@ -32,16 +32,16 @@
 
 
 marker::marker (QsciScintilla *area, int original_linenr, editor_markers type,
-                int editor_linenr) : QObject ()
+                int editor_linenr, const QString& condition) : QObject ()
 {
-  construct (area, original_linenr, type, editor_linenr);
+  construct (area, original_linenr, type, editor_linenr, condition);
 }
 
 
 marker::marker (QsciScintilla *area, int original_linenr,
-                editor_markers type) : QObject ()
+                editor_markers type, const QString& condition) : QObject ()
 {
-  construct (area, original_linenr, type, original_linenr - 1);
+  construct (area, original_linenr, type, original_linenr - 1, condition);
 }
 
 
@@ -52,12 +52,14 @@
 
 void
 marker::construct (QsciScintilla *area, int original_linenr,
-                   editor_markers type, int editor_linenr)
+                   editor_markers type, int editor_linenr,
+                   const QString& condition)
 {
   _edit_area = area;
   _original_linenr = original_linenr;
   _marker_type = type;
   _mhandle = _edit_area->markerAdd (editor_linenr, _marker_type);
+  _condition = condition;
 }
 
 
@@ -96,10 +98,14 @@
 
 
 void
-marker::handle_find_translation (int linenr, int& translation_linenr)
+marker::handle_find_translation (int linenr, int& translation_linenr,
+                                 marker *& bp)
 {
   if (_original_linenr == linenr)
-    translation_linenr = _edit_area->markerLine (_mhandle);
+    {
+      translation_linenr = _edit_area->markerLine (_mhandle);
+      bp = this;
+    }
 }
 
 
@@ -126,9 +132,10 @@
 
 
 void
-marker::handle_report_editor_linenr (QIntList& list)
+marker::handle_report_editor_linenr (QIntList& lines, QStringList& conditions)
 {
-  list << _edit_area->markerLine (_mhandle);
+  lines << _edit_area->markerLine (_mhandle);
+  conditions << _condition;
 }
 
 
--- a/libgui/src/m-editor/marker.h	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/m-editor/marker.h	Sat Jan 30 10:13:34 2016 +1100
@@ -46,40 +46,49 @@
     {
       bookmark,
       breakpoint,
+      cond_break,
       unsure_breakpoint,
       debugger_position,
       unsure_debugger_position
     };
 
   marker (QsciScintilla *edit_area, int original_linenr,
-          editor_markers marker_type);
+          editor_markers marker_type, const QString& condition = "");
   marker (QsciScintilla *edit_area, int original_linenr,
-          editor_markers marker_type, int editor_linenr);
+          editor_markers marker_type, int editor_linenr,
+          const QString& condition = "");
   ~marker (void);
 
+  const QString& get_cond (void) const { return _condition; }
+
+  void set_cond (const QString& cond) { _condition = cond; }
+
 public slots:
   void handle_remove_via_original_linenr (int original_linenr);
   void handle_request_remove_via_editor_linenr (int editor_linenr);
   void handle_remove (void);
-  void handle_find_translation (int original_linenr, int& editor_linenr);
+  void handle_find_translation (int original_linenr, int& editor_linenr,
+                                marker*& bp);
   void handle_find_just_before (int linenr, int& original_linenr, int& editor_linenr);
   void handle_find_just_after (int linenr, int& original_linenr, int& editor_linenr);
 /*  void handle_lines_changed (void);*/
   void handle_marker_line_deleted (int mhandle);
   void handle_marker_line_undeleted (int mhandle);
-  void handle_report_editor_linenr (QIntList& int_list);
+  void handle_report_editor_linenr (QIntList& lines, QStringList& conditions);
 
 signals:
   void request_remove (int original_linenr);
 
 private:
   void construct (QsciScintilla *edit_area, int original_linenr,
-                  editor_markers marker_type, int editor_linenr);
+                  editor_markers marker_type, int editor_linenr,
+                  const QString& condition);
 
   QsciScintilla *       _edit_area;
   int                   _original_linenr;
   editor_markers        _marker_type;
   int                   _mhandle;
+  QString               _condition;
 };
 
 #endif // MARKER_H
--- a/libgui/src/m-editor/octave-qscintilla.cc	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/m-editor/octave-qscintilla.cc	Sat Jan 30 10:13:34 2016 +1100
@@ -194,8 +194,7 @@
   QPoint global_pos, local_pos;                         // the menu's position
   QMenu *context_menu = createStandardContextMenu ();  // standard menu
 
-  // fill context menu with editor's standard actions
-  emit create_context_menu_signal (context_menu);
+  bool in_left_margin = false;
 
   // determine position depending on mouse or keyboard event
   if (e->reason () == QContextMenuEvent::Mouse)
@@ -203,6 +202,8 @@
       // context menu by mouse
       global_pos = e->globalPos ();            // global mouse position
       local_pos  = e->pos ();                  // local mouse position
+      if (e->x () < marginWidth (1) + marginWidth (2))
+        in_left_margin = true;
     }
   else
     {
@@ -215,26 +216,45 @@
         global_pos = editor_rect.topLeft ();   // yes, take top left corner
     }
 
-  // additional custom entries of the context menu
-  context_menu->addSeparator ();   // separator before custom entries
-
-  // help menu: get the position of the mouse or the text cursor
-  // (only for octave files)
-  QString lexer_name = lexer ()->lexer ();
-  if (lexer_name == "octave" || lexer_name == "matlab")
+  if (! in_left_margin)
     {
-      _word_at_cursor = wordAtPoint (local_pos);
-      if (! _word_at_cursor.isEmpty ())
+      // fill context menu with editor's standard actions
+      emit create_context_menu_signal (context_menu);
+
+      // additional custom entries of the context menu
+      context_menu->addSeparator ();   // separator before custom entries
+
+      // help menu: get the position of the mouse or the text cursor
+      // (only for octave files)
+      QString lexer_name = lexer ()->lexer ();
+      if (lexer_name == "octave" || lexer_name == "matlab")
         {
-          context_menu->addAction (tr ("Help on") + " " + _word_at_cursor,
-                                   this, SLOT (contextmenu_help (bool)));
-          context_menu->addAction (tr ("Documentation on")
-                                   + " " + _word_at_cursor,
-                                   this, SLOT (contextmenu_doc (bool)));
-          context_menu->addAction (tr ("Edit") + " " + _word_at_cursor,
-                                   this, SLOT (contextmenu_edit (bool)));
+          _word_at_cursor = wordAtPoint (local_pos);
+          if (! _word_at_cursor.isEmpty ())
+            {
+              context_menu->addAction (tr ("Help on") + " " + _word_at_cursor,
+                                       this, SLOT (contextmenu_help (bool)));
+              context_menu->addAction (tr ("Documentation on")
+                                       + " " + _word_at_cursor,
+                                       this, SLOT (contextmenu_doc (bool)));
+              context_menu->addAction (tr ("Edit") + " " + _word_at_cursor,
+                                       this, SLOT (contextmenu_edit (bool)));
+            }
         }
-    }
+      }
+    else
+      {
+        // remove all standard actions from scintilla
+        QList<QAction *> all_actions = context_menu->actions ();
+        QAction* a;
+
+        foreach (a, all_actions)
+          context_menu->removeAction (a);
+
+        a = context_menu->addAction (tr ("dbstop if ..."), this,
+                                     SLOT (contextmenu_break_condition (bool)));
+        a->setData (local_pos);
+      }
 
   // finaly show the menu
   context_menu->exec (global_pos);
@@ -279,6 +299,38 @@
     emit execute_command_in_terminal_signal (commands.at (i));
 }
 
+// wrappers for dbstop related context menu items
+
+#ifdef HAVE_QSCI_VERSION_2_6_0
+// FIXME Why can't the data be sent as the argument to the function???
+void
+octave_qscintilla::contextmenu_break_condition (bool)
+{
+  QAction *action = qobject_cast<QAction *>(sender());
+  QPoint local_pos = action->data ().value<QPoint> ();
+
+  // pick point just right of margins, so lineAt doesn't give -1
+  int margins = marginWidth (1) + marginWidth (2) + marginWidth (3);
+  local_pos = QPoint (margins + 1, local_pos.y ());
+
+  emit context_menu_break_condition_signal (lineAt (local_pos));
+}
+
+void
+octave_qscintilla::contextmenu_break_once (const QPoint& local_pos)
+{
+  emit context_menu_break_once (lineAt (local_pos));
+}
+
+/*
+void
+octave_qscintilla::contextmenu_break_if_caught (bool)
+{
+  emit context_menu_break_if_caught
+}
+*/
+#endif // HAVE_QSCI_VERSION_2_6_0
+
 void
 octave_qscintilla::text_changed ()
 {
--- a/libgui/src/m-editor/octave-qscintilla.h	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/m-editor/octave-qscintilla.h	Sat Jan 30 10:13:34 2016 +1100
@@ -54,6 +54,8 @@
   void qsci_has_focus_signal (bool);
   void status_update (bool,bool);
   void show_doc_signal (const QString&);
+  void context_menu_break_condition_signal (int);
+  void context_menu_break_once (int);
 
 private slots:
 
@@ -63,6 +65,9 @@
   void contextmenu_edit (bool);
   void contextmenu_run (bool);
 
+  void contextmenu_break_condition (bool);
+  void contextmenu_break_once (const QPoint&);
+
   void text_changed (void);
 
 protected:
--- a/libgui/src/main-window.cc	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/main-window.cc	Sat Jan 30 10:13:34 2016 +1100
@@ -1000,11 +1000,12 @@
 void
 main_window::handle_update_breakpoint_marker_request (bool insert,
                                                       const QString& file,
-                                                      int line)
+                                                      int line,
+						      const QString& cond)
 {
   bool cmd_focus = command_window_has_focus ();
 
-  emit update_breakpoint_marker_signal (insert, file, line);
+  emit update_breakpoint_marker_signal (insert, file, line, cond);
 
   if (cmd_focus)
     focus_command_window ();
@@ -1414,11 +1415,13 @@
                SLOT (handle_delete_debugger_pointer_request (const QString&, int)));
 
       connect (this,
-               SIGNAL (update_breakpoint_marker_signal (bool, const QString&, int)),
+               SIGNAL (update_breakpoint_marker_signal (bool, const QString&,
+	                                                int, const QString&)),
                editor_window,
                SLOT (handle_update_breakpoint_marker_request (bool,
                                                               const QString&,
-                                                              int)));
+                                                              int,
+							      const QString&)));
 #endif
 
       octave_link::post_event (this, &main_window::resize_command_window_callback);
@@ -1558,10 +1561,13 @@
                SLOT (handle_delete_debugger_pointer_request (const QString&, int)));
 
       connect (_octave_qt_link,
-               SIGNAL (update_breakpoint_marker_signal (bool, const QString&, int)),
+               SIGNAL (update_breakpoint_marker_signal (bool, const QString&,
+	                                                int, const QString&)),
                this,
-               SLOT (handle_update_breakpoint_marker_request (bool, const QString&,
-                                                              int)));
+               SLOT (handle_update_breakpoint_marker_request (bool,
+	                                                      const QString&,
+                                                              int,
+							      const QString&)));
 
       connect (_octave_qt_link,
                SIGNAL (show_doc_signal (const QString &)),
--- a/libgui/src/main-window.h	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/main-window.h	Sat Jan 30 10:13:34 2016 +1100
@@ -100,7 +100,7 @@
   void insert_debugger_pointer_signal (const QString& file, int line);
   void delete_debugger_pointer_signal (const QString& file, int line);
   void update_breakpoint_marker_signal (bool insert, const QString& file,
-                                        int line);
+                                        int line, const QString& cond);
 
   void copyClipboard_signal (void);
   void pasteClipboard_signal (void);
@@ -169,7 +169,8 @@
   void handle_insert_debugger_pointer_request (const QString& file, int line);
   void handle_delete_debugger_pointer_request (const QString& file, int line);
   void handle_update_breakpoint_marker_request (bool insert,
-                                                const QString& file, int line);
+                                                const QString& file, int line,
+						const QString& cond);
 
   void read_settings (void);
   void init_terminal_size (void);
--- a/libgui/src/octave-qt-link.cc	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/octave-qt-link.cc	Sat Jan 30 10:13:34 2016 +1100
@@ -29,6 +29,7 @@
 #include <QStringList>
 #include <QDialog>
 #include <QDir>
+#include <QPushButton>
 
 #include "str-vec.h"
 #include "dialog.h"
@@ -372,6 +373,11 @@
   return retval;
 }
 
+// Prompt to allow file to be run by setting cwd (or if addpath_option==true,
+// alternatively setting the path).
+// This uses a QMessageBox unlike other functions in this file,
+// because uiwidget_creator.waitcondition.wait hangs when called from
+// file_editor_tab::handle_context_menu_break_condition().  (FIXME -- why hang?)
 int
 octave_qt_link::do_debug_cd_or_addpath_error (const std::string& file,
                                               const std::string& dir,
@@ -382,46 +388,30 @@
   QString qdir = QString::fromStdString (dir);
   QString qfile = QString::fromStdString (file);
 
-  QString msg
-    = (addpath_option
-       ? tr ("The file %1 does not exist in the load path.  To run or debug the function you are editing, you must either change to the directory %2 or add that directory to the load path.").arg (qfile).arg (qdir)
-       : tr ("The file %1 is shadowed by a file with the same name in the load path. To run or debug the function you are editing, change to the directory %2.").arg (qfile).arg (qdir));
-
-  QString title = tr ("Change Directory or Add Directory to Load Path");
+  QMessageBox msgBox;
 
-  QString cd_txt = tr ("Change Directory");
-  QString addpath_txt = tr ("Add Directory to Load Path");
-  QString cancel_txt = tr ("Cancel");
+  msgBox.setText ("File not in load path");
+  QPushButton *cd_btn = msgBox.addButton (tr ("Change Directory"),
+                                          QMessageBox::YesRole);
 
-  QStringList btn;
-  QStringList role;
-  btn << cd_txt;
-  role << "YesRole";
+  QPushButton *addpath_btn = 0;
   if (addpath_option)
     {
-      btn << addpath_txt;
-      role << "AcceptRole";
+      msgBox.setInformativeText (tr ("The file %1 does not exist in the load path.  To run or debug the function you are editing, you must either change to the directory %2 or add that directory to the load path.").arg (qfile).arg (qdir));
+      addpath_btn = msgBox.addButton (tr ("Add Directory to Load Path"),
+                                     QMessageBox::AcceptRole);
     }
-  btn << cancel_txt;
-  role << "RejectRole";
-
-  // Lock mutex before signaling.
-  uiwidget_creator.mutex.lock ();
-
-  uiwidget_creator.signal_dialog (msg, title, "quest", btn, cancel_txt, role);
+    else
+    {
+      msgBox.setInformativeText (tr ("The file %1 is shadowed by a file with the same name in the load path. To run or debug the function you are editing, change to the directory %2.").arg (qfile).arg (qdir));
+    }
+  msgBox.setStandardButtons (QMessageBox::Cancel);
 
-  // Wait while the user is responding to message box.
-  uiwidget_creator.waitcondition.wait (&uiwidget_creator.mutex);
-
-  // The GUI has sent a signal and the thread has been awakened.
+  msgBox.exec ();
 
-  QString result = uiwidget_creator.get_dialog_button ();
-
-  uiwidget_creator.mutex.unlock ();
-
-  if (result == cd_txt)
+  if (msgBox.clickedButton () == cd_btn)
     retval = 1;
-  else if (result == addpath_txt)
+  else if (msgBox.clickedButton () == addpath_btn)
     retval = 2;
 
   return retval;
@@ -538,12 +528,15 @@
   emit exit_debugger_signal ();
 }
 
+// Display (if @insert true) or remove the appropriate symbol for a breakpoint
+// in @file at @line with condition @cond.
 void
 octave_qt_link::do_update_breakpoint (bool insert,
-                                      const std::string& file, int line)
+                                      const std::string& file, int line,
+                                      const std::string& cond)
 {
   emit update_breakpoint_marker_signal (insert, QString::fromStdString (file),
-                                        line);
+                                        line, QString::fromStdString (cond));
 }
 
 void
--- a/libgui/src/octave-qt-link.h	Sun Jan 24 11:02:30 2016 +1100
+++ b/libgui/src/octave-qt-link.h	Sat Jan 30 10:13:34 2016 +1100
@@ -124,7 +124,8 @@
   void do_execute_in_debugger_event (const std::string& file, int line);
   void do_exit_debugger_event (void);
 
-  void do_update_breakpoint (bool insert, const std::string& file, int line);
+  void do_update_breakpoint (bool insert, const std::string& file, int line,
+                             const std::string& cond);
 
   void do_set_default_prompts (std::string& ps1, std::string& ps2,
                                std::string& ps4);
@@ -191,7 +192,7 @@
   void exit_debugger_signal (void);
 
   void update_breakpoint_marker_signal (bool insert, const QString& file,
-                                        int line);
+                                        int line, const QString& cond);
 
   void insert_debugger_pointer_signal (const QString&, int);
   void delete_debugger_pointer_signal (const QString&, int);
--- a/libinterp/corefcn/octave-link.h	Sun Jan 24 11:02:30 2016 +1100
+++ b/libinterp/corefcn/octave-link.h	Sat Jan 30 10:13:34 2016 +1100
@@ -307,7 +307,7 @@
                      const std::string& cond = "")
   {
     if (enabled ())
-      instance->do_update_breakpoint (insert, file, line);
+      instance->do_update_breakpoint (insert, file, line, cond);
   }
 
   static void connect_link (octave_link *);
@@ -467,7 +467,8 @@
   virtual void do_exit_debugger_event (void) = 0;
 
   virtual void do_update_breakpoint (bool insert,
-                                     const std::string& file, int line) = 0;
+                                     const std::string& file, int line,
+                                     const std::string& cond) = 0;
 
   virtual void do_set_default_prompts (std::string& ps1, std::string& ps2,
                                        std::string& ps4) = 0;