# HG changeset patch
# User Daniel J Sebald <daniel.sebald@ieee.org>
# Date 1364883175 18000
# Node ID b9c00b75414b4cbdd73c468b880bca9389811ddf
# Parent  5293cee91891c330738c884cbecad7744e88ce5c
Add builtin Qt equivalents of UI dialogs, i.e.,, qterrordlg, qtinputdlg, etc.

* dialog.cc, dialog.h (QUIWidgetCreator): Add. New class to communicate across
Octave and GUI threads using signals. (QUIWidgetCreator::create_dialog): Signal
emitted when wanting to create MessageDialog object. (QUIWidgetCreator::
create_listview): Signal emitted when wanting to create ListDialog object.
(QUIWidgetCreator::create_inputlayout): Signal emitted with wanting to create
InputDialog object. (MessageDialog : QMessageBox, ListDialog : QDialog,
InputDialog : QDialog): Add. New customized classes derived from existing Qt
objects to layout desired functionality and connect signals back to
QUIWidgetCreator.

* libgui/guifcn/module.mk (EXTRA_DIST): Add ../libgui/guifcn/module.mk.
(GUIFCN_INC): Add ../libgui/guifcn/dialog.h. (GUIFCN_SRC): Add
../libgui/guifcn/dialog.cc. And a few other additions so that this file, the
above source files and derivative intermediate files are included as part of
the project.

* libinterp/Makefile.am (octinclude_HEADERS): Add ../libgui/$(GUIFCN_INC) to
list of headers. (DIST_SRC): Add ../libgui/$(GUIFCN_SRC) to list of source
files. (liboctinterp_la_LIBADD): Add guifcn/libguifcn.la to list of library
links.  This is somewhat awkward because all other builtins are part of
libinterp, but a better setup would be a major rework.

* libgui/src/module.mk (octave_gui_MOC): Add intermediate meta-object-code
file guifcn/moc-dialog.cc to list of sources. Necessary for signal/slot
mechanism.

* main-window.cc, main-window.h (main_window::connect_uiwidget_links): Function
to initialize signal/slot connections between QUIWidgetCreator object and the
main window.  Also register QIntList and QFloatList so that these types may be
transfered via signal. May be better located in dialog.h, but OK for now.
(main_window::handle_create_dialog): Simple slot that relays inputs to
MessageDialog constructor, sets attribute to Qt::WA_DeleteOnClose and makes
the dialog visible. (main_window::handle_create_listview): Simple slot that
relays inputs to ListDialog constructor, sets attribute to Qt::WA_DeleteOnClose
and makes the dialog visible. (main_window::handle_create_inputlayout): Simple
slot that relays inputs to InputDialog constructor, sets attribute to
Qt::WA_DeleteOnClose and makes the dialog visible.

* octave-gui.cc (octave_start_gui): Call main_window::connect_uiwidget_links
so that connections are made between main window and QUIWidgetCreator.  This
should probably be part of QUIWidgetCreator, but currently the main window
pointer is not globally accessible.  This setup should be OK for now.

diff -r 5293cee91891 -r b9c00b75414b libgui/guifcn/dialog.cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/guifcn/dialog.cc	Tue Apr 02 01:12:55 2013 -0500
@@ -0,0 +1,1158 @@
+/*
+
+Copyright (C) 1993-2013 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "defun.h"
+#include "builtin-defun-decls.h"
+
+#include "dialog.h"
+
+#include "Cell.h"
+#include "error.h"
+#include "ov.h"
+
+#include <QMutex>
+#include <QWaitCondition>
+#include <QString>
+#include <QStringList>
+#include <QStringListModel>
+#include <QListView>
+// Could replace most of these with #include <QtGui>
+#include <QMessageBox>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QPushButton>
+#include <QGroupBox>
+#include <QGridLayout>
+#include <QLabel>
+
+// GUI objects cannot be accessed in the non-GUI thread.  However, signals
+// can be sent to slots across threads with proper syncronization.  Hence,
+// the use of QWaitCondition.
+QMutex mutex;
+QWaitCondition waitcondition;
+
+QUIWidgetCreator uiwidget_creator;
+
+bool QUIWidgetCreator::qt_gui_valid ()
+{
+#define MAIN_WINDOW_POINTER_INACCESSIBLE
+#ifdef MAIN_WINDOW_POINTER_INACCESSIBLE
+  octave_value_list guitest = Fisguirunning ();
+  if (!guitest (0).bool_value ())
+    {
+      error ("Qt main GUI window must be active to run this routine.");
+      return false;
+    }
+#else
+  if (!uiwidget_creator)
+    {
+      uiwidget_creator = new QUIWidgetCreator ();
+      if (!uiwidget_creator)
+        {
+          error ("Cannot create object to communicate with Qt GUI.");
+          return false;
+        }
+      // Establish connections here, but pointer to main window is
+      // currently not accessible.  So that code is in a routine called
+      // main_window::connect_uiwidget_links () right now.
+      return true;
+    }
+#endif
+  else
+    return true; 
+}
+
+
+QUIWidgetCreator::QUIWidgetCreator ()
+  : QObject ()
+{
+  dialog_result = -1;
+  dialog_button = QString ();
+  string_list = new QStringList ();
+  list_index = new QIntList;
+}
+
+
+QUIWidgetCreator::~QUIWidgetCreator ()
+{
+  // Clean up all dynamically created objects
+  delete string_list;
+  delete list_index;
+}
+
+
+void
+QUIWidgetCreator::dialog_finished (int)
+{
+  // Store the value so that builtin functions can retrieve.
+  // The value should always be 1 for the Octave functions.
+
+  // Value returned by message box is not quite always 1.  If the
+  // window upper-right close button is pressed, 'result' is 0.
+  dialog_result = 1;
+
+  // Wake up Octave process so that it continues.
+  waitcondition.wakeAll();
+}
+
+
+void
+QUIWidgetCreator::dialog_button_clicked (QAbstractButton *button)
+{
+  // Store information about what button was pressed so that builtin
+  // functions can retrieve.
+  dialog_button = button->text ();
+}
+
+
+void
+QUIWidgetCreator::list_select_finished (const QIntList& selected, const int button_pressed)
+{
+  // Store the value so that builtin functions can retrieve.
+  *list_index = selected;
+  dialog_result = button_pressed;
+
+  // Wake up Octave process so that it continues.
+  waitcondition.wakeAll();
+}
+
+
+void
+QUIWidgetCreator::input_finished (const QStringList& input, const int button_pressed)
+{
+  // Store the value so that builtin functions can retrieve.
+  *string_list = input;
+  dialog_result = button_pressed;
+
+  // Wake up Octave process so that it continues.
+  waitcondition.wakeAll();
+}
+
+
+int
+proc_first_two_args_dlg (const octave_value_list& args, QString& message,
+                         QString& title)
+{
+  octave_value ovmessage = args (0);
+
+  if (ovmessage.is_string () || ovmessage.is_cell ())
+    {
+      if (ovmessage.is_string ())
+        message = ovmessage.string_value ().c_str ();
+      else
+        {
+          Cell c_val = ovmessage.cell_value ();
+          for (octave_idx_type i = 0; i < c_val.length (); i++)
+            {
+              if (i > 0)
+                message.append ("\n");
+
+              if (c_val (i).is_string ())
+                message.append (c_val (i).string_value ().c_str ());
+              else
+                {
+                  error ("qtlistdlg: cell %d is not a string", i+1);
+                  return 1;
+                }
+            }
+        }
+
+      if (args.length () > 1)
+        {
+          octave_value ovtitle = args (1);
+
+          if (ovtitle.is_string ())
+            title = ovtitle.string_value ().c_str ();
+          else
+            {
+              error ("second argument must be a string");
+              return 1;
+            }
+        }
+    }
+  else
+    {
+      error ("qtquestdlg: first argument must be a string or string cell");
+      return 1;
+    }
+
+  return 0;
+}
+
+
+octave_value_list
+qtdlg (const octave_value_list& args, const char *default_title,
+       const char *default_icon)
+{
+  if (!QUIWidgetCreator::qt_gui_valid ())
+    {
+      octave_value_list retval;
+      return retval;
+    }
+
+  octave_value_list retval;
+
+  int nargin = args.length ();
+
+  if (nargin > 0 && nargin <= 3)
+    {
+      QString message, title;
+      title = default_title;
+      if (proc_first_two_args_dlg (args, message, title))
+        return retval;
+
+      QString icon;
+      if (nargin > 2)
+        {
+          octave_value ovicon = args (2);
+
+          if (ovicon.is_string ())
+            icon = ovicon.string_value ().c_str ();
+          else
+            {
+              error ("third argument must be a string");
+              return retval;
+            }
+        }
+      else
+        icon = default_icon;
+
+      if (icon != "error" && icon != "help" &&
+          icon != "none" && icon != "warn")
+        {
+          error ("invalid icon string");
+          return retval;
+        }
+
+      // Signal GUI thread to put up simple message box using OK
+      // as the only button.
+      uiwidget_creator.signal_dialog (message, title, icon, QStringList (),
+                                      QString (), QStringList ());
+
+      // Wait while the user is responding to message box.
+      waitcondition.wait (&mutex);
+
+      // The GUI has sent a signal and the process has been awakened.
+      retval (0) = uiwidget_creator.get_dialog_result ();
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+
+octave_value_list
+qtdlg2 (const octave_value_list& args, const char *default_title,
+        const char *icon)
+{
+  octave_value_list retval;
+
+  int nargin = args.length ();
+
+  if (nargin > 0 && nargin <= 2)
+    retval = qtdlg (args, default_title, icon);
+  else
+    print_usage ();
+
+  return retval;
+}
+
+
+DEFUN (qterrordlg, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Function File} {@var{h} =} qterrordlg (@var{msg})\n\
+@deftypefnx {Function File} {@var{h} =} qterrordlg (@var{msg}, @var{title})\n\
+Display @var{msg} using an error dialog box.\n\
+\n\
+The message may have multiple lines separated by newline characters\n\
+(\"\\n\"), or it may be a cellstr array with one element for each\n\
+line.  The optional input @var{title} (character string) can be used to\n\
+set the dialog caption.  The default title is \"Error Dialog\".\n\
+\n\
+The return value is always 1.\n\
+@seealso{qthelpdlg, qtinputdlg, qtlistdlg, qtmsgbox, qtquestdlg, qtwarndlg}\n\
+@end deftypefn")
+{
+  return qtdlg2 (args, "Error Dialog", "error");
+}
+
+
+DEFUN (qthelpdlg, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Function File} {@var{h} =} qthelpdlg (@var{msg})\n\
+@deftypefnx {Function File} {@var{h} =} qthelpdlg (@var{msg}, @var{title})\n\
+Display @var{msg} in a help dialog box.\n\
+\n\
+The message may have multiple lines separated by newline characters\n\
+(\"\\n\"), or it may be a cellstr array with one element for each\n\
+line.  The optional input @var{title} (character string) can be used to\n\
+set the dialog caption.  The default title is \"Help Dialog\".\n\
+\n\
+The return value is always 1.\n\
+@seealso{qterrordlg, qtinputdlg, qtlistdlg, qtmsgbox, qtquestdlg, qtwarndlg}\n\
+@end deftypefn")
+{
+  return qtdlg2 (args, "Help Dialog", "help");
+}
+
+
+DEFUN (qtwarndlg, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Function File} {@var{h} =} qtwarndlg (@var{msg})\n\
+@deftypefnx {Function File} {@var{h} =} qtwarndlg (@var{msg}, @var{title})\n\
+Display @var{msg} using a warning dialog box.\n\
+\n\
+The message may have multiple lines separated by newline characters\n\
+(\"\\n\"), or it may be a cellstr array with one element for each\n\
+line.  The optional input @var{title} (character string) can be used to\n\
+set the dialog caption.  The default title is \"Warning Dialog\".\n\
+\n\
+@seealso{qterrordlg, qthelpdlg, qtinputdlg, qtlistdlg, qtmsgbox, qtquestdlg}\n\
+@end deftypefn")
+{
+  return qtdlg2 (args, "Warning Dialog", "warn");
+}
+
+
+DEFUN (qtmsgbox, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Function File} {@var{h} =} qtmsgbox (@var{msg})\n\
+@deftypefnx {Function File} {@var{h} =} qtmsgbox (@var{msg}, @var{title})\n\
+@deftypefnx {Function File} {@var{h} =} qtmsgbox (@var{msg}, @var{title}, @var{icon})\n\
+Display @var{msg} using a message dialog box.\n\
+\n\
+The message may have multiple lines separated by newline characters\n\
+(@code{\"\\n\"}), or it may be a cellstr array with one element for each\n\
+line.  The optional input @var{title} (character string) can be used to\n\
+decorate the dialog caption.\n\
+\n\
+The optional argument @var{icon} selects a dialog icon.\n\
+It can be one of @code{\"none\"} (default), @code{\"error\"}, @code{\"help\"} or\n\
+@code{\"warn\"}.\n\
+\n\
+The return value is always 1.\n\
+@seealso{qterrordlg, qthelpdlg, qtinputdlg, qtlistdlg, qtquestdlg, qtwarndlg}\n\
+@end deftypefn")
+{
+  return qtdlg (args, "", "none");
+}
+
+
+DEFUN (qtquestdlg, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Function File} {@var{btn} =} qtquestdlg (@var{msg})\n\
+@deftypefnx {Function File} {@var{btn} =} qtquestdlg (@var{msg}, @var{title})\n\
+@deftypefnx {Function File} {@var{btn} =} qtquestdlg (@var{msg}, @var{title}, @var{default})\n\
+@deftypefnx {Function File} {@var{btn} =} qtquestdlg (@var{msg}, @var{title}, @var{btn1}, @var{btn2}, @var{default})\n\
+@deftypefnx {Function File} {@var{btn} =} qtquestdlg (@var{msg}, @var{title}, @var{btn1}, @var{btn2}, @var{btn3}, @var{default})\n\
+Display @var{msg} using a question dialog box and return the caption\n\
+of the activated button.\n\
+\n\
+The dialog may contain two or three buttons which will all close the dialog.\n\
+\n\
+The message may have multiple lines separated by newline characters\n\
+(@code{\"\\n\"}), or it may be a cellstr array with one element for each\n\
+line.  The optional @var{title} (character string) can be used to\n\
+decorate the dialog caption.\n\
+\n\
+The string @var{default} identifies the default button,\n\
+which is activated by pressing the @kbd{ENTER} key.\n\
+It must match one of the strings given in @var{btn1}, @var{btn2} or\n\
+@var{btn3}.\n\
+\n\
+If only @var{msg} and @var{title} are specified, three buttons with\n\
+the default captions \"Yes\", \"No\", and \"Cancel\" are used.\n\
+\n\
+If only two button captions, @var{btn1} and @var{btn2}, are specified\n\
+the dialog will have only these two buttons.\n\
+\n\
+@seealso{qterrordlg, qthelpdlg, qtinputdlg, qtlistdlg, qtmsgbox, qtwarndlg}\n\
+@end deftypefn")
+{
+  octave_value_list retval;
+
+  if (!QUIWidgetCreator::qt_gui_valid ())
+    return retval;
+
+  int nargin = args.length ();
+
+  if (nargin > 0 && nargin <= 6)
+    {
+      QString message, title = "Question Dialog";
+      if (proc_first_two_args_dlg (args, message, title))
+        return retval;
+
+      int i_arg = 2;
+
+      QStringList button = QStringList ();
+      QString defbutton = "Yes";
+ 
+      if (nargin > 3)
+        {
+          octave_value ovbtn1 = args (i_arg++);
+          if (ovbtn1.is_string ())
+            button << ovbtn1.string_value ().c_str ();
+          else
+            error ("qtquestdlg: third argument must be a string");
+
+          octave_value ovbtn2 = args (i_arg++);
+          if (ovbtn2.is_string ())
+            button << ovbtn2.string_value ().c_str ();
+          else
+            error ("qtquestdlg: fourth argument must be a string");
+
+          if (nargin > 5)
+            {
+              octave_value ovbtn3 = args (i_arg++);
+              if (ovbtn3.is_string ())
+                button << ovbtn3.string_value ().c_str ();
+              else
+                error ("qtquestdlg: fifth argument must be a string");
+            }
+        }
+      else
+        {
+          button << "Yes";
+          button << "No";
+          button << "Cancel";
+        }
+
+      if (nargin == 3 || nargin == 5 || nargin == 6)
+        {
+          octave_value ovdef = args (i_arg++);
+          if (ovdef.is_string ())
+            defbutton = ovdef.string_value ().c_str ();
+          else
+            error ("qtquestdlg: default button must be a string");
+        }
+
+      // Qt on Gnome has reject role (cancel) as the left-most button.
+      // This could lead to ordering problems when changing platforms.
+      // I've tried making every role the same, however the message
+      // box doesn't behave well in that case--mixes up button presses
+      // and <esc> doesn't work.  If this does cause problems, it might
+      // be easier to use a custom dialog rather than a QMessageBox.
+      QStringList role = QStringList ();
+      role << "RejectRole";
+      role << "NoRole";
+      role << "YesRole";
+
+      // Signal GUI thread to put up simple message box.
+      uiwidget_creator.signal_dialog (message, title, "quest",
+                                      button, defbutton, role);
+
+      // Wait while the user is responding to message box.
+      waitcondition.wait (&mutex);
+
+      // The GUI has sent a signal and the process has been awakened.
+      retval (0) = uiwidget_creator.get_dialog_button ()->toStdString ();
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+
+MessageDialog::MessageDialog (const QString& message, const QString& title,
+                              const QString& qsicon,
+                              const QStringList& qsbutton,
+                              const QString& defbutton,
+                              const QStringList& role)
+  : QMessageBox (QMessageBox::NoIcon, title, message, 0, 0)
+{
+  // Create a NonModal message.
+  setWindowModality (Qt::NonModal);
+
+  // Interpret the icon string, because enumeration QMessageBox::Icon can't
+  // easily be made to pass through a signal.
+  QMessageBox::Icon eicon = QMessageBox::NoIcon;
+  if (qsicon == "error")
+    eicon = QMessageBox::Critical;
+  else if (qsicon == "warn")
+    eicon = QMessageBox::Warning;
+  else if (qsicon == "help")
+    eicon = QMessageBox::Information;
+  else if (qsicon == "quest")
+    eicon = QMessageBox::Question;
+  setIcon (eicon);
+
+  int N = qsbutton.size () < role.size () ? qsbutton.size () : role.size ();
+  if (N == 0)
+    addButton (QMessageBox::Ok);
+  else
+    {
+      for (int i = 0; i < N; i++)
+        {
+          // Interpret the button role string, because enumeration
+          // QMessageBox::ButtonRole can't be made to pass through a signal.
+          QString srole = role.at (i);
+          QMessageBox::ButtonRole erole = QMessageBox::InvalidRole;
+          if (srole == "YesRole")
+            erole = QMessageBox::YesRole;
+          else if (srole == "NoRole")
+            erole = QMessageBox::NoRole;
+          else if (srole == "RejectRole")
+            erole = QMessageBox::RejectRole;
+          else if (srole == "AcceptRole")
+            erole = QMessageBox::AcceptRole;
+
+          QPushButton *pbutton = addButton (qsbutton.at (i), erole);
+          if (qsbutton.at (i) == defbutton)
+            setDefaultButton (pbutton);
+          // Make the last button the button pressed when <esc> key activated.
+          if (i == N-1)
+            setEscapeButton (pbutton);
+        }
+    }
+
+  connect (this,              SIGNAL (buttonClicked (QAbstractButton *)),
+           &uiwidget_creator, SLOT (dialog_button_clicked (QAbstractButton *)));
+  connect (this,              SIGNAL (finished (int)),
+           &uiwidget_creator, SLOT (dialog_finished (int)));
+}
+
+
+DEFUN (qtlistdlg, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Function File} {[@var{sel}, @var{ok}] =} qtlistdlg (@var{key}, @var{value}, @dots{})\n\
+Return user inputs from a list dialog box in a vector of\n\
+selection indices @var{sel} and a flag @var{ok} indicating how the\n\
+user closed the dialog box.  The value of @var{ok} is 1 if the user\n\
+closed the box with the OK button, otherwise it is 0 and @var{sel} is\n\
+empty.\n\
+\n\
+The indices in @var{sel} are 1 based.\n\
+\n\
+The arguments are specified in form of @var{key}, @var{value} pairs.\n\
+The @code{\"ListString\"} argument pair must be specified.\n\
+\n\
+Valid @var{key} and @var{value} pairs are:\n\
+\n\
+@table @code\n\
+@item \"ListString\"\n\
+   a cell array of strings comprising the content of the list.\n\
+\n\
+@item \"SelectionMode\"\n\
+   can be either @code{\"Single\"} or @code{\"Multiple\"} (default).\n\
+\n\
+@item \"ListSize\"\n\
+   a vector with two elements @var{width} and @var{height} defining\n\
+the size of the list field in pixels.  The dialog is non-scalable.  Default\n\
+is automatic layout by the user interface and a scalable dialog.\n\
+\n\
+@item \"InitialValue\"\n\
+   a vector containing 1-based indices of preselected elements.  Default\n\
+is 1 (first item).\n\
+\n\
+@item \"Name\"\n\
+   a string to be used as the dialog caption.  Default is \"\".\n\
+\n\
+@item \"PromptString\"\n\
+   a cell array of strings to be displayed above the list field.  Default\n\
+is @{@}.\n\
+\n\
+@item \"OKString\"\n\
+   a string used to label the OK button.  Default is \"OK\".\n\
+\n\
+@item \"CancelString\"\n\
+   a string used to label the Cancel button.  Default is \"Cancel\".\n\
+@end table\n\
+\n\
+Example:\n\
+\n\
+@example\n\
+@group\n\
+[sel, ok] = qtlistdlg (\"ListString\", @{\"An item\", \"another\", \"yet another\"@},\n\
+                       \"SelectionMode\", \"Multiple\");\n\
+if (ok == 1)\n\
+  for i = 1:numel (sel)\n\
+    disp (sel(i));\n\
+  endfor\n\
+endif\n\
+@end group\n\
+@end example\n\
+\n\
+@seealso{qterrordlg, qthelpdlg, qtinputdlg, qtmsgbox, qtquestdlg, qtwarndlg}\n\
+@end deftypefn")
+{
+  octave_value_list retval;
+
+  if (!QUIWidgetCreator::qt_gui_valid ())
+    return retval;
+
+  int nargin = args.length ();
+
+  QStringList qvalidtextkey;
+  qvalidtextkey << "Name" << "PromptString" << "OKString" << "CancelString";
+  QStringList qtext;
+  qtext << "" << "" << "OK" << "Cancel";
+  QIntList qsize;
+  qsize << -1 << -1;
+  QString qmode ("Multiple");
+
+  uiwidget_creator.clear_list ();
+  int i_arg = 0;
+
+  while (i_arg < nargin)
+    {
+      if (i_arg + 1 > nargin)
+        {
+          error ("qtlistdlg: variables must come in pairs: (KEY, VALUE)");
+          return retval;
+        }
+
+      octave_value key = args (i_arg++);
+
+      if (!key.is_string ())
+        {
+          error ("qtlistdlg: KEY must be a string");
+          return retval;
+        }
+
+      octave_value val = args (i_arg++);
+
+      int i_text;
+
+      // Letter case is retained.
+      std::string s_key = key.string_value ();
+      if (!s_key.compare ("ListString"))
+        {
+          if (!val.is_cell ())
+            {
+              error ("qtlistdlg: 'ListString' must be string cell");
+              return retval;
+            }
+
+          Cell c_val = val.cell_value ();
+          for (octave_idx_type i = 0; i < c_val.length (); i++)
+            {
+              if (c_val (i).is_string ())
+                  uiwidget_creator.add_string_list (c_val (i).string_value ().c_str ());
+              else
+                {
+                  error ("qtlistdlg: cell %d is not a string", i+1);
+                  return retval;
+                }
+            }
+        }
+      else if (!s_key.compare ("SelectionMode"))
+        {
+          if (!val.is_string ())
+            {
+              error ("qtlistdlg: 'SelectionMode' must be a string");
+              return retval;
+            }
+          std::string s_val = val.string_value ();
+          if (s_val.compare ("Single") && s_val.compare ("Multiple"))
+            {
+              error ("qtlistdlg: 'SelectionMode' options: \"Single\", \"Multiple\"");
+              return retval;
+            }
+          qmode = s_val.c_str ();
+        }
+      else if (!s_key.compare ("ListSize"))
+        {
+          if (!val.is_numeric_type ())
+            {
+              error ("qtlistdlg: 'ListSize' must be an integer vector");
+              return retval;
+            }
+          Array<octave_idx_type> ival = val.octave_idx_type_vector_value ();
+          if (ival.length () != 2)
+            {
+              error ("qtlistdlg: 'InitialValue' must be of length 2");
+              return retval;
+            }
+          for (int i = 0; i < ival.length (); i++)
+            qsize.replace (i, ival.xelem (i));
+        }
+      else if (!s_key.compare ("InitialValue"))
+        {
+          if (!val.is_numeric_type ())
+            {
+              error ("qtlistdlg: 'InitialValue' must be a numeric vector");
+              return retval;
+            }
+
+          // SHOULD CHECK IS INTEGER, TRY USING EXISTING INDEX VALIDATION
+          Array<octave_idx_type> ival = val.octave_idx_type_vector_value ();
+          for (int i = 0; i < ival.length (); i++)
+            uiwidget_creator.add_list_index (ival.xelem (i));
+        }
+      else if ((i_text = qvalidtextkey.indexOf (s_key.c_str ())) != -1)
+        {
+          if (!val.is_string ())
+            {
+              error ("qtlistdlg: '%s' must be a string", s_key.c_str ());
+              return retval;
+            }
+          qtext.replace (i_text, val.string_value ().c_str ());
+        }
+      else
+        {
+          error ("qtlistdlg: unknown keyword: %s", s_key.c_str ());
+          return retval;
+        }
+    }
+
+  // Signal GUI thread to put up a list box.  The string list
+  // is part of the UIWidgetCreator.
+  if (uiwidget_creator.signal_listview (qmode, qsize, qtext))
+    {
+      // Wait while the user is responding to message box.
+      waitcondition.wait (&mutex);
+
+      // The GUI has sent a signal and the process has been awakened.
+      const QIntList *selected = uiwidget_creator.get_list_index ();
+      ColumnVector output (selected->size (), false);
+      octave_idx_type i_oct = 0;
+      for (int i_qt = 0; i_qt < selected->size (); i_qt++, i_oct++)
+        output (i_oct) = selected->value (i_qt);
+      retval (0) = output;
+      retval (1) = uiwidget_creator.get_dialog_result ();
+    }
+  else
+    error ("qtlistdlg: 'ListString' keyword must appear and cell must be non-empty");
+
+  return retval;
+}
+
+
+ListDialog::ListDialog (const QStringList& list, const QIntList& selected,
+                        const QString& mode, const QIntList& view_size,
+                        const QStringList& text)
+  : QDialog ()
+{
+  // Put the list of items into a model.  Keep this off of the stack
+  // because this conceivably could be a very large list.
+  QAbstractItemModel *model = new QStringListModel (list);
+
+  QListView *view = new QListView;
+  view->setModel (model);
+
+  if (mode == "Single")
+    view->setSelectionMode (QAbstractItemView::SingleSelection);
+  else if (mode == "Multiple")
+    view->setSelectionMode (QAbstractItemView::ExtendedSelection);
+//  else if ()
+//    view->setSelectionMode (QAbstractItemView::ContiguousSelection);
+//  else if ()
+//    view->setSelectionMode (QAbstractItemView::MultiSelection);
+  else
+    view->setSelectionMode (QAbstractItemView::NoSelection);
+
+  selector = view->selectionModel ();
+  for (int i = 0; i < selected.size (); i++)
+    {
+      QModelIndex idx = model->index (selected.value (i) - 1, 0, QModelIndex ());
+      selector->select (idx, QItemSelectionModel::Select);
+    }
+
+    bool fixed_layout = false;
+    if (view_size.size () >= 2 && view_size.value (0) > 0 && view_size.value (1) > 0)
+      {
+        view->setFixedSize (view_size.value (0), view_size.value (1));
+        fixed_layout = true;
+      }
+
+    QPushButton *select_all = new QPushButton(tr("Select All"));
+    QVBoxLayout *listLayout = new QVBoxLayout;
+    listLayout->addWidget (view);
+    listLayout->addWidget (select_all);
+    QGroupBox *listGroupBox = new QGroupBox (text.at (1));
+    listGroupBox->setLayout (listLayout);
+
+//    QIcon *question_mark = new QIcon;
+    QHBoxLayout *horizontalLayout = new QHBoxLayout;
+//    horizontalLayout->addWidget (question_mark);
+    horizontalLayout->addWidget (listGroupBox);
+
+    QPushButton *buttonOk = new QPushButton(text.at (2));
+    QPushButton *buttonCancel = new QPushButton(text.at (3));
+    QHBoxLayout *buttonsLayout = new QHBoxLayout;
+    buttonsLayout->addStretch (1);
+    buttonsLayout->addWidget (buttonOk);
+    buttonsLayout->addWidget (buttonCancel);
+
+    QVBoxLayout *mainLayout = new QVBoxLayout;
+    mainLayout->addLayout(horizontalLayout);
+    mainLayout->addSpacing(12);
+    mainLayout->addLayout (buttonsLayout);
+    setLayout (mainLayout);
+    if (fixed_layout)
+      layout()->setSizeConstraint (QLayout::SetFixedSize);
+
+    QString title = text.at (0);
+    setWindowTitle(title);
+
+    connect (select_all, SIGNAL (clicked ()),
+             view,       SLOT (selectAll ()));
+    connect (buttonOk, SIGNAL (clicked ()),
+             this,     SLOT (buttonOk_clicked ()));
+    connect (buttonCancel, SIGNAL (clicked ()),
+             this,         SLOT (buttonCancel_clicked ()));
+    connect (this,              SIGNAL (finish_selection (const QIntList&, const int)),
+             &uiwidget_creator, SLOT (list_select_finished (const QIntList&, const int)));
+}
+
+
+void
+ListDialog::buttonOk_clicked ()
+{
+  // Store information about what button was pressed so that builtin
+  // functions can retrieve.
+  QModelIndexList selected_index = selector->selectedIndexes ();
+  QIntList selected_int;
+  for (int i = 0; i < selected_index.size (); i++)
+    selected_int << selected_index.at (i).row () + 1;
+  emit finish_selection (selected_int, 1);
+  done (QDialog::Accepted);
+}
+
+
+void
+ListDialog::buttonCancel_clicked ()
+{
+  // Store information about what button was pressed so that builtin
+  // functions can retrieve.
+  QIntList empty;
+  emit finish_selection (empty, 0);
+  done (QDialog::Rejected);
+}
+
+
+void
+ListDialog::reject ()
+{
+  buttonCancel_clicked ();
+}
+
+
+DEFUN (qtinputdlg, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Function File} {@var{cstr} =} qtinputdlg (@var{prompt})\n\
+@deftypefnx {Function File} {@var{cstr} =} qtinputdlg (@var{prompt}, @var{title})\n\
+@deftypefnx {Function File} {@var{cstr} =} qtinputdlg (@var{prompt}, @var{title}, @var{rowscols})\n\
+@deftypefnx {Function File} {@var{cstr} =} qtinputdlg (@var{prompt}, @var{title}, @var{rowscols}, @var{defaults})\n\
+Return user input from a multi-textfield dialog box in a cell array\n\
+of strings, or an empty cell array if the dialog is closed by the\n\
+Cancel button.\n\
+\n\
+Inputs:\n\
+\n\
+@table @var\n\
+@item prompt\n\
+A cell array with strings labeling each text field.  This input is required.\n\
+\n\
+@item title\n\
+String to use for the caption of the dialog.  The default is \"Input Dialog\".\n\
+\n\
+@item rowscols\n\
+Specifies the size of the text fields and can take three forms:\n\
+\n\
+@enumerate\n\
+@item a scalar value which defines the number of rows used for each\n\
+text field.\n\
+\n\
+@item a vector which defines the individual number of rows\n\
+used for each text field.\n\
+\n\
+@item a matrix which defines the individual number of rows and\n\
+columns used for each text field.  In the matrix each row describes\n\
+a single text field.  The first column specifies the number of input\n\
+rows to use and the second column specifies the text field width.\n\
+A value of 1 for the row is approximately the height of a character,\n\
+and a value of 1 for the column is approximately the width of a character.\n\
+Fractional quantities are allowed.\n\
+@end enumerate\n\
+\n\
+@item defaults\n\
+A list of default values to place in each text fields.  It must be\n\
+a cell array of strings with the same size as @var{prompt}.\n\
+@end table\n\
+@seealso{qterrordlg, qthelpdlg, qtlistdlg, qtmsgbox, qtquestdlg, qtwarndlg}\n\
+@end deftypefn")
+{
+  octave_value_list retval;
+
+  if (!QUIWidgetCreator::qt_gui_valid ())
+    return retval;
+
+  int nargin = args.length ();
+
+  if (nargin > 0 && nargin <= 4)
+    {
+      QFloatList qrowscols;
+      QString title ("Input Dialog");
+
+      uiwidget_creator.clear_list ();
+
+      octave_value val = args (0);
+      if (!val.is_cell ())
+        {
+          error ("qtinputdlg: first argument must be string cell");
+          return retval;
+        }
+
+      Cell prompt = val.cell_value ();
+      for (octave_idx_type i = 0; i < prompt.length (); i++)
+        {
+          if (prompt (i).is_string ())
+              uiwidget_creator.add_string_list (prompt (i).string_value ().c_str ());
+          else
+            {
+              error ("qtinputdlg: cell %d is not a string", i+1);
+              return retval;
+            }
+        }
+
+      if (nargin > 1)
+        {
+          octave_value ovtitle = args (1);
+
+          if (ovtitle.is_string ())
+            title = ovtitle.string_value ().c_str ();
+          else
+            {
+              error ("qtinputdlg: second argument must be a string");
+              return retval;
+            }
+        }
+
+      if (nargin > 2)
+        {
+          octave_value ovrowscols = args (2);
+
+          if (ovrowscols.is_scalar_type ())
+            {
+              for (int i = 0; i < prompt.length (); i++)
+                {
+                  qrowscols.append (ovrowscols.scalar_value ());
+                  qrowscols.append (-1);
+                }
+            }
+          else if (ovrowscols.is_matrix_type ())
+            {
+              ColumnVector vrows, vcols;
+
+              Matrix mrowscols = ovrowscols.matrix_value ();
+
+              if (mrowscols.rows () == 1)
+                vrows = mrowscols.transpose ().column (0);
+              else if (mrowscols.cols () == 1)
+                vrows = mrowscols.column (0);
+              else if (mrowscols.cols () != 2)
+                {
+                  error ("qtinputdlg: third argument must have two columns");
+                  return retval;
+                }
+              else
+                {
+                  vrows = mrowscols.column (0);
+                  vcols = mrowscols.column (1);
+                }
+
+
+              if (vrows.length () != prompt.length ())
+                {
+                  error ("qtinputdlg: third argument must be same length as prompt vector");
+                  return retval;
+                }
+
+              for (int i = 0; i < prompt.length (); i++)
+                {
+                  qrowscols.append (vrows.elem (i));
+                  if (vcols.length () != 0)
+                    qrowscols.append (vcols.elem (i));
+                  else
+                    qrowscols.append (-1);
+                }
+            }
+          else
+            {
+              error ("qtinputdlg: third argument must be a scalar, vector or matrix");
+              return retval;
+            }
+        }
+      else
+        {
+          for (int i = 0; i < 2*prompt.length (); i++)
+            qrowscols.append (-1);
+        }
+
+      if (nargin > 3)
+        {
+          octave_value ovdef = args (3);
+
+          if (!ovdef.is_cell ())
+            {
+              error ("qtinputdlg: fourth argument must be string cell");
+              return retval;
+            }
+
+          Cell def = ovdef.cell_value ();
+          if (def.length () != prompt.length ())
+            {
+              error ("qtinputdlg: default string cell must be same length as prompt string cell");
+              return retval;
+            }
+
+          for (octave_idx_type i = 0; i < def.length (); i++)
+            {
+              if (def (i).is_string ())
+                uiwidget_creator.add_string_list (def (i).string_value ().c_str ());
+              else
+                {
+                  error ("qtinputdlg: cell %d is not a string", i+1);
+                  return retval;
+                }
+            }
+        }
+      else
+        {
+          // Place same number of empty strings in list for defaults.
+          for (octave_idx_type i = 0; i < prompt.length (); i++)
+            uiwidget_creator.add_string_list ("");
+        }
+
+      if (uiwidget_creator.signal_inputlayout (title, qrowscols))
+        {
+          // Wait while the user is responding to message box.
+          waitcondition.wait (&mutex);
+
+          // The GUI has sent a signal and the process has been awakened.
+          const QStringList *inputLine = uiwidget_creator.get_string_list ();
+
+          string_vector s;
+          for (int i = 0; i < inputLine->size (); i++)
+            s.append (inputLine->value (i).toStdString ());
+          retval (0) = Cell (s);
+        }
+      else
+        error ("qtinputdlg: must have non-empty prompt string");
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+
+InputDialog::InputDialog (const QStringList& prompt_and_default,
+                          const QString& title, const QFloatList& rowscols)
+  : QDialog ()
+{
+
+//#define LINE_EDIT_FOLLOWS_PROMPT
+
+#ifdef LINE_EDIT_FOLLOWS_PROMPT
+    // Prompt on left followed by input on right.
+    QGridLayout *promptInputLayout = new QGridLayout;
+#else
+    // Prompt aligned above input.
+    QVBoxLayout *promptInputLayout = new QVBoxLayout;
+#endif
+    int N_gridrows = prompt_and_default.size ()/2;
+    for (int i = 0; i < N_gridrows; i++)
+      {
+        QLabel *label = new QLabel (prompt_and_default.at (i));
+        QLineEdit *line_edit = new QLineEdit (prompt_and_default.at (N_gridrows + i));
+        if (rowscols.at (2*i) > 0)
+          {
+            QSize qsize = line_edit->sizeHint ();
+            int intval = qsize.height () * rowscols.at (2*i);
+            line_edit->setFixedHeight (intval);
+            if (rowscols.at (2*i + 1) > 0)
+              {
+                intval = (qsize.height () * rowscols.at (2*i + 1))/2;
+                line_edit->setFixedWidth (intval);
+              }
+          }
+        input_line << line_edit;
+#ifdef LINE_EDIT_FOLLOWS_PROMPT
+        promptInputLayout->addWidget (label, i + 1, 0);
+        promptInputLayout->addWidget (line_edit, i + 1, 1);
+#else
+        promptInputLayout->addWidget (label);
+        promptInputLayout->addWidget (line_edit);
+#endif
+      }
+
+    QPushButton *buttonOk = new QPushButton("OK");
+    QPushButton *buttonCancel = new QPushButton("Cancel");
+    QHBoxLayout *buttonsLayout = new QHBoxLayout;
+    buttonsLayout->addStretch (1);
+    buttonsLayout->addWidget (buttonOk);
+    buttonsLayout->addWidget (buttonCancel);
+
+    QVBoxLayout *mainLayout = new QVBoxLayout;
+    mainLayout->addLayout(promptInputLayout);
+    mainLayout->addSpacing(12);
+    mainLayout->addLayout (buttonsLayout);
+    setLayout (mainLayout);
+
+    setWindowTitle(title);
+
+    connect (buttonOk, SIGNAL (clicked ()),
+             this,     SLOT (buttonOk_clicked ()));
+    connect (buttonCancel, SIGNAL (clicked ()),
+             this,         SLOT (buttonCancel_clicked ()));
+    connect (this,              SIGNAL (finish_input (const QStringList&, const int)),
+             &uiwidget_creator, SLOT (input_finished (const QStringList&, const int)));
+}
+
+
+void
+InputDialog::buttonOk_clicked ()
+{
+  // Store information about what button was pressed so that builtin
+  // functions can retrieve.
+  QStringList string_result;
+  for (int i = 0; i < input_line.size (); i++)
+    string_result << input_line.at (i)->text ();
+  emit finish_input (string_result, 1);
+  done (QDialog::Accepted);
+}
+
+
+void
+InputDialog::buttonCancel_clicked ()
+{
+  // Store information about what button was pressed so that builtin
+  // functions can retrieve.
+  QStringList empty;
+  emit finish_input (empty, 0);
+  done (QDialog::Rejected);
+}
+
+
+void
+InputDialog::reject ()
+{
+  buttonCancel_clicked ();
+}
diff -r 5293cee91891 -r b9c00b75414b libgui/guifcn/dialog.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/guifcn/dialog.h	Tue Apr 02 01:12:55 2013 -0500
@@ -0,0 +1,183 @@
+/*
+
+Copyright (C) 1993-2013 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if !defined (octave_guifcn_dialog_h)
+#define octave_guifcn_dialog_h 1
+
+// FIXME -- we should not be including config.h in header files.
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QAbstractButton>
+#include <QList>
+#include <QItemSelectionModel>
+#include <QDialog>
+#include <QMessageBox>
+#include <QLineEdit>
+
+// Defined for purposes of sending QList<int> as part of signal.
+typedef QList<int> QIntList;
+// Defined for purposes of sending QList<float> as part of signal.
+typedef QList<float> QFloatList;
+
+
+class QUIWidgetCreator : public QObject
+{
+  Q_OBJECT
+
+  int dialog_result;
+  QString dialog_button;
+
+  // The list could conceivably be big.  Not sure how things are
+  // stored internally, so keep off of the stack.
+  QStringList *string_list;
+  QIntList *list_index;
+
+public:
+  QUIWidgetCreator ();
+  ~QUIWidgetCreator ();
+
+public:
+  static bool qt_gui_valid ();
+
+  void signal_dialog (const QString& message, const QString& title,
+                      const QString& icon, const QStringList& button,
+                      const QString& defbutton, const QStringList& role) {
+
+    // Use the last button in the list as the reject result, i.e., when no
+    // button is pressed such as in the case of <esc> and close button.
+    if (!button.isEmpty ())
+      dialog_button = button.last ();
+
+    emit create_dialog (message, title, icon, button, defbutton, role);
+  };
+  int get_dialog_result (void) {
+    return dialog_result;
+  }
+  const QString *get_dialog_button (void) {
+    return &dialog_button;
+  }
+  bool signal_listview (const QString& mode, const QIntList& size,
+                        const QStringList& text) {
+    if (string_list->isEmpty ())
+      return false;
+    // Default value if none assigned.
+    if (list_index->isEmpty ())
+      *list_index << 1;
+    emit create_listview (*string_list, *list_index, mode, size, text);
+    return true;
+  };
+  void clear_list (void) {
+    string_list->clear ();
+    list_index->clear ();
+  };
+  void add_string_list (const QString& string) {
+    *string_list << string;
+  };
+  // Index value begins at 1.
+  void add_list_index (const int index) {
+    *list_index << index;
+  };
+  const QIntList *get_list_index (void) {
+    return list_index;
+  }
+  bool signal_inputlayout (const QString& title, const QFloatList& rowscols) {
+    if (string_list->isEmpty ())
+      return false;
+    emit create_inputlayout (*string_list, title, rowscols);
+    return true;
+  };
+  const QStringList *get_string_list (void) {
+    return string_list;
+  }
+  
+signals:
+  void create_dialog (const QString&, const QString&, const QString&,
+                      const QStringList&, const QString&, const QStringList&);
+  void create_listview (const QStringList&, const QIntList&, const QString&,
+                        const QIntList&, const QStringList&);
+  void create_inputlayout (const QStringList&, const QString&, const QFloatList&);
+
+public slots:
+  void dialog_finished (int result);
+  void dialog_button_clicked (QAbstractButton *button);
+  void list_select_finished (const QIntList& selected, const int button_pressed);
+  void input_finished (const QStringList& input, const int button_pressed);
+};
+
+extern QUIWidgetCreator uiwidget_creator;
+
+
+class MessageDialog : public QMessageBox
+{
+  Q_OBJECT
+
+public:
+  explicit MessageDialog (const QString& message, const QString& title,
+                          const QString& icon, const QStringList& button,
+                          const QString& defbutton,
+                          const QStringList& role);
+};
+
+
+class ListDialog : public QDialog
+{
+  Q_OBJECT
+
+  QItemSelectionModel *selector;
+
+public:
+  explicit ListDialog (const QStringList& list, const QIntList& selected,
+                       const QString& mode, const QIntList& view_size,
+                       const QStringList& text);
+
+signals:
+  void finish_selection (const QIntList&, const int);
+
+public slots:
+  void buttonOk_clicked ();
+  void buttonCancel_clicked ();
+  void reject ();
+};
+
+
+class InputDialog : public QDialog
+{
+  Q_OBJECT
+
+  QList<QLineEdit *> input_line;
+
+public:
+  explicit InputDialog (const QStringList& prompt_and_default,
+                        const QString& title, const QFloatList& rowscols);
+
+signals:
+  void finish_input (const QStringList&, const int);
+
+public slots:
+  void buttonOk_clicked ();
+  void buttonCancel_clicked ();
+  void reject ();
+};
+
+#endif
diff -r 5293cee91891 -r b9c00b75414b libgui/guifcn/module.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/guifcn/module.mk	Tue Apr 02 01:12:55 2013 -0500
@@ -0,0 +1,57 @@
+
+EXTRA_DIST += \
+  ../libgui/guifcn/module.mk
+
+GUIFCN_INC = \
+  ../libgui/guifcn/dialog.h
+
+GUIFCN_SRC = \
+  ../libgui/guifcn/dialog.cc
+
+octave_gui_MOC =
+octave_gui_MOC += \
+  ../libgui/guifcn/moc-dialog.cc
+
+moc-%.cc: %.h
+	$(MOC) -o$@ $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(MOC_CPPFLAGS) $(liboctgui_la_CPPFLAGS) $<
+
+noinst_LTLIBRARIES += guifcn/libguifcn.la
+
+## DJS 2013mar17.  Remove this comment in near future, since that
+## indicates no one had the energy or time to follow up.
+##
+## I built up the following list one at a time.  It got to the point
+## where I thought header files were being included that shouldn't
+## have much to do with the simple function I was attempting to
+## create.  For example, why would sparse-related code be necessary:
+##  ../../octave/liboctave/operators/Sparse-op-defs.h:29:20: fatal error: mx-ops.h: No such file or directory
+## The mx-ops.h isn't in the source tree.  It must be a generated file,
+## which means I could no longer simply go to "libgui" and run "make".
+## I needed to compile the whole project first.  It might be worth
+## untangling some of this by starting from the end of the list and
+## strip off one include directory at a time and see if it can be
+## removed from dependency by editing some header files.
+fcn_libgui_fcn_la_CPPFLAGS = \
+  -Iparse-tree -I$(top_srcdir)/libinterp/parse-tree \
+  -I$(top_srcdir)/libinterp/interpfcn \
+  -I$(top_srcdir)/libinterp/interp-core \
+  -I$(top_srcdir)/libinterp/octave-value \
+  -I$(top_srcdir)/liboctave/system \
+  -I$(top_srcdir)/liboctave/util \
+  -I$(top_srcdir)/liboctave/array \
+  -I$(top_srcdir)/liboctave/cruft/misc/ \
+  -I$(top_srcdir)/liboctave/numeric/ \
+  -I$(top_srcdir)/liboctave/operators/ \
+  -I$(top_builddir)/liboctave/operators \
+  -I$(top_builddir)/libinterp
+
+nodist_guifcn_libguifcn_la_SOURCES = $(octave_gui_MOC)
+
+guifcn_libguifcn_la_SOURCES = $(GUIFCN_SRC)
+guifcn_libguifcn_la_CPPFLAGS = \
+  @QT_CPPFLAGS@ \
+  $(liboctinterp_la_CPPFLAGS)
+guifcn_libguifcn_la_LIBADD = @QT_LIBS@
+
+CLEANFILES = \
+  $(octave_gui_MOC)
diff -r 5293cee91891 -r b9c00b75414b libgui/src/main-window.cc
--- a/libgui/src/main-window.cc	Sun Mar 17 05:12:56 2013 -0400
+++ b/libgui/src/main-window.cc	Tue Apr 02 01:12:55 2013 -0500
@@ -36,6 +36,7 @@
 #include <QFileDialog>
 #include <QMessageBox>
 #include <QIcon>
+#include <QMetaType>
 
 #ifdef HAVE_QSCINTILLA
 #include "file-editor.h"
@@ -640,6 +641,85 @@
 }
 
 
+// Connect the signals emitted when the Octave thread wants to create
+// a dialog box of some sort.  Perhaps a better place for this would be
+// as part of the QUIWidgetCreator class.  However, mainWindow currently
+// is not a global variable and not accessible for connecting.  This
+// could be changed easily enough. 
+void
+main_window::connect_uiwidget_links ()
+{
+  connect (&uiwidget_creator, SIGNAL (create_dialog (const QString&,
+                              const QString&, const QString&,
+                              const QStringList&, const QString&,
+                              const QStringList&)),
+           this,              SLOT (handle_create_dialog (const QString&,
+                              const QString&, const QString&,
+                              const QStringList&, const QString&,
+                              const QStringList&)));
+
+  // Register QIntList so that list of ints may be part of a signal.
+  qRegisterMetaType<QIntList> ("QIntList");
+  connect (&uiwidget_creator, SIGNAL (create_listview (const QStringList&,
+                              const QIntList&, const QString&, const QIntList&,
+                              const QStringList&)),
+           this,              SLOT (handle_create_listview (const QStringList&,
+                              const QIntList&, const QString&, const QIntList&,
+                              const QStringList&)));
+
+  // Register QFloatList so that list of ints may be part of a signal.
+  qRegisterMetaType<QFloatList> ("QFloatList");
+  connect (&uiwidget_creator, SIGNAL (create_inputlayout (const QStringList&,
+                              const QString&, const QFloatList&)),
+           this,              SLOT (handle_create_inputlayout (const QStringList&,
+                              const QString&, const QFloatList&)));
+}
+
+ 
+// Create a message dialog with specified string, buttons and decorative text.
+void
+main_window::handle_create_dialog (const QString& message, const QString& title,
+                                   const QString& icon, const QStringList& button,
+                                   const QString& defbutton,
+                                   const QStringList& role)
+{
+  MessageDialog *message_dialog = new MessageDialog (message, title, icon,
+                                                     button, defbutton, role);
+  message_dialog->setAttribute (Qt::WA_DeleteOnClose);
+  message_dialog->show ();
+}
+
+
+// Create a list dialog with specified list, initially selected, mode, view
+// size and decorative text.
+void
+main_window::handle_create_listview (const QStringList& list,
+                                     const QIntList& selected,
+                                     const QString& mode,
+                                     const QIntList& view_size,
+                                     const QStringList& text)
+{
+  ListDialog *list_dialog = new ListDialog (list, selected, mode,
+                                            view_size, text);
+  list_dialog->setAttribute (Qt::WA_DeleteOnClose);
+  list_dialog->show ();
+}
+
+
+// Create an input dialog with specified prompts and defaults, title and
+// row/column size specifications.
+void
+main_window::handle_create_inputlayout (const QStringList& prompt_and_default,
+                                        const QString& title,
+                                        const QFloatList& rowscols)
+{
+  InputDialog *input_dialog = new InputDialog (prompt_and_default,
+                                               title, rowscols);
+  input_dialog->setAttribute (Qt::WA_DeleteOnClose);
+  input_dialog->show ();
+}
+
+
 // Main subroutine of the constructor
 void
 main_window::construct ()
diff -r 5293cee91891 -r b9c00b75414b libgui/src/main-window.h
--- a/libgui/src/main-window.h	Sun Mar 17 05:12:56 2013 -0400
+++ b/libgui/src/main-window.h	Tue Apr 02 01:12:55 2013 -0500
@@ -50,6 +50,7 @@
 #include "terminal-dockwidget.h"
 #include "documentation-dockwidget.h"
 #include "octave-qt-event-listener.h"
+#include "dialog.h"
 
 /**
  * \class MainWindow
@@ -126,6 +127,17 @@
   void write_settings ();
   void connect_visibility_changed ();
 
+  void connect_uiwidget_links ();
+  void handle_create_dialog (const QString& message, const QString& title,
+                             const QString& icon, const QStringList& button,
+                             const QString& defbutton, const QStringList& role);
+  void handle_create_listview (const QStringList& list, const QIntList& selected,
+                               const QString& mode, const QIntList& view_size,
+                               const QStringList& text);
+  void handle_create_inputlayout (const QStringList& prompt_and_default,
+                                  const QString& title,
+                                  const QFloatList& rowscols);
+
 protected:
   void closeEvent (QCloseEvent * closeEvent);
 
diff -r 5293cee91891 -r b9c00b75414b libgui/src/module.mk
--- a/libgui/src/module.mk	Sun Mar 17 05:12:56 2013 -0400
+++ b/libgui/src/module.mk	Tue Apr 02 01:12:55 2013 -0500
@@ -80,7 +80,8 @@
   src/octave-adapter/moc-octave-main-thread.cc \
   src/qtinfo/moc-parser.cc \
   src/qtinfo/moc-webinfo.cc \
-  src/moc-octave-dock-widget.cc
+  src/moc-octave-dock-widget.cc \
+  guifcn/moc-dialog.cc
 
 octave_gui_RC = src/qrc-resource.cc
 
@@ -152,6 +153,7 @@
   -I$(srcdir)/src/m-editor \
   -I$(srcdir)/src/octave-adapter \
   -I$(srcdir)/src/qtinfo \
+  -I$(srcdir)/guifcn \
   -I$(top_srcdir)/liboctave/cruft/misc \
   -I$(top_srcdir)/liboctave/array \
   -I$(top_builddir)/liboctave/numeric -I$(top_srcdir)/liboctave/numeric \
diff -r 5293cee91891 -r b9c00b75414b libgui/src/octave-gui.cc
--- a/libgui/src/octave-gui.cc	Sun Mar 17 05:12:56 2013 -0400
+++ b/libgui/src/octave-gui.cc	Tue Apr 02 01:12:55 2013 -0500
@@ -111,6 +111,8 @@
           w.focus_command_window ();
           w.connect_visibility_changed (); // connect signals for changes in
                                            // visibility not before w is shown
+          w.connect_uiwidget_links (); // connect signals across GUI thread and
+                                       // Octave thread
           return application.exec ();
         }
     }
diff -r 5293cee91891 -r b9c00b75414b libinterp/Makefile.am
--- a/libinterp/Makefile.am	Sun Mar 17 05:12:56 2013 -0400
+++ b/libinterp/Makefile.am	Tue Apr 02 01:12:55 2013 -0500
@@ -108,6 +108,7 @@
   builtins.h \
   builtin-defun-decls.h \
   octave.h \
+  ../libgui/$(GUIFCN_INC) \
   $(OCTAVE_VALUE_INC) \
   $(PARSE_TREE_INC) \
   $(PARSER_INC) \
@@ -124,6 +125,7 @@
 
 DIST_SRC = \
   octave.cc \
+  ../libgui/$(GUIFCN_SRC) \
   $(OCTAVE_VALUE_SRC) \
   $(PARSE_TREE_SRC) \
   $(PARSER_SRC) \
@@ -133,6 +135,7 @@
 
 noinst_LTLIBRARIES =
 
+include ../libgui/guifcn/module.mk
 include parse-tree/module.mk
 include octave-value/module.mk
 include operators/module.mk
@@ -178,6 +181,7 @@
 include link-deps.mk
 
 liboctinterp_la_LIBADD = \
+  guifcn/libguifcn.la \
   octave-value/liboctave-value.la \
   parse-tree/libparse-tree.la \
   parse-tree/libparser.la \
@@ -238,8 +242,8 @@
 ## FIXME -- Shouldn't the build stop if CPP fails here?
 %.df: %.cc
 	$(CXXCPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
-	  $(AM_CPPFLAGS) $(JAVA_CPPFLAGS) $(CPPFLAGS) \
-	  $(AM_CXXFLAGS) $(CXXFLAGS) \
+	  $(AM_CPPFLAGS) $(JAVA_CPPFLAGS) $(QT_CPPFLAGS) \
+          $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) \
 	  -DMAKE_BUILTINS $< | $(srcdir)/mkdefs $(srcdir) $< > $@-t
 	mv $@-t $@
 
