GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
dialog.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2013-2018 John W. Eaton
4 Copyright (C) 2013-2018 Daniel J. Sebald
5 
6 This file is part of Octave.
7 
8 Octave is free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include "dialog.h"
29 
30 #include <QString>
31 #include <QStringList>
32 #include <QStringListModel>
33 #include <QListView>
34 #include <QFileInfo>
35 // Could replace most of these with #include <QtGui>
36 #include <QMessageBox>
37 #include <QHBoxLayout>
38 #include <QVBoxLayout>
39 #include <QPushButton>
40 #include <QGroupBox>
41 #include <QGridLayout>
42 #include <QLabel>
43 
44 namespace octave
45 {
47 
49  : QObject (), m_dialog_result (-1), m_dialog_button (),
50  m_string_list (new QStringList ()), m_list_index (new QIntList ()),
51  m_path_name (new QString ())
52  { }
53 
55  {
56  delete m_string_list;
57  delete m_list_index;
58  delete m_path_name;
59  }
60 
61  QString QUIWidgetCreator::rm_amp (const QString& text)
62  {
63  QString text_wo_amp = text;
64  text_wo_amp.replace (QRegExp ("&(\\w)"), "\\1");
65  return text_wo_amp;
66  }
67 
68  void QUIWidgetCreator::dialog_button_clicked (QAbstractButton *button)
69  {
70  // Wait for link thread to go to sleep state.
71  lock ();
72 
73  // Check for a matching button text while ignoring accelerators because
74  // the window manager may have added one in the passed button
75  QString text_clean = rm_amp (button->text ());
76  for (int i = 0; i < m_button_list.count (); i++)
77  {
78  if (rm_amp (m_button_list.at (i)) == text_clean)
79  {
80  m_dialog_button = m_button_list.at (i); // text w/o extra accelerator
81  break;
82  }
83  }
84 
85  // The value should always be 1 for the Octave functions.
86  m_dialog_result = 1;
87 
88  unlock ();
89 
90  // Wake up Octave process so that it continues.
91  wake_all ();
92  }
93 
95  int button_pressed)
96  {
97  // Wait for link thread to go to sleep state.
98  lock ();
99 
100  // Store the value so that builtin functions can retrieve.
101  *m_list_index = selected;
102  m_dialog_result = button_pressed;
103 
104  unlock ();
105 
106  // Wake up Octave process so that it continues.
107  wake_all ();
108  }
109 
110  void QUIWidgetCreator::input_finished (const QStringList& input,
111  int button_pressed)
112  {
113  // Wait for link thread to go to sleep state.
114  lock ();
115 
116  // Store the value so that builtin functions can retrieve.
117  *m_string_list = input;
118  m_dialog_result = button_pressed;
119 
120  unlock ();
121 
122  // Wake up Octave process so that it continues.
123  wake_all ();
124  }
125 
127  const QString& path,
128  int filterindex)
129  {
130  // Wait for link thread to go to sleep state.
131  lock ();
132 
133  // Store the value so that builtin functions can retrieve.
134  *m_string_list = files;
135  m_dialog_result = filterindex;
136  *m_path_name = path;
137 
138  unlock ();
139 
140  // Wake up Octave process so that it continues.
141  wake_all ();
142  }
143 
145  const QString& title,
146  const QString& qsicon,
147  const QStringList& qsbutton,
148  const QString& defbutton,
149  const QStringList& role)
150  : QMessageBox (QMessageBox::NoIcon, title.isEmpty () ? " " : title,
151  message, nullptr, nullptr)
152  {
153  // Create a NonModal message.
154  setWindowModality (Qt::NonModal);
155 
156  // Interpret the icon string, because enumeration QMessageBox::Icon can't
157  // easily be made to pass through a signal.
158  QMessageBox::Icon eicon = QMessageBox::NoIcon;
159  if (qsicon == "error")
160  eicon = QMessageBox::Critical;
161  else if (qsicon == "warn")
162  eicon = QMessageBox::Warning;
163  else if (qsicon == "help")
164  eicon = QMessageBox::Information;
165  else if (qsicon == "quest")
166  eicon = QMessageBox::Question;
167  setIcon (eicon);
168 
169  int N = (qsbutton.size () < role.size () ? qsbutton.size () : role.size ());
170  if (N == 0)
171  addButton (QMessageBox::Ok);
172  else
173  {
174  for (int i = 0; i < N; i++)
175  {
176  // Interpret the button role string, because enumeration
177  // QMessageBox::ButtonRole can't be made to pass through a signal.
178  QString srole = role.at (i);
179  QMessageBox::ButtonRole erole = QMessageBox::InvalidRole;
180  if (srole == "ResetRole")
181  erole = QMessageBox::ResetRole;
182  else if (srole == "YesRole")
183  erole = QMessageBox::YesRole;
184  else if (srole == "NoRole")
185  erole = QMessageBox::NoRole;
186  else if (srole == "RejectRole")
187  erole = QMessageBox::RejectRole;
188  else if (srole == "AcceptRole")
189  erole = QMessageBox::AcceptRole;
190 
191  QPushButton *pbutton = addButton (qsbutton.at (i), erole);
192  if (qsbutton.at (i) == defbutton)
193  setDefaultButton (pbutton);
194  // Make the last button the button pressed when <esc> key activated.
195  if (i == N-1)
196  {
197  // FIXME: Why define and then immediately test value?
198 #define ACTIVE_ESCAPE 1
199 #if ACTIVE_ESCAPE
200  setEscapeButton (pbutton);
201 #else
202  setEscapeButton (0);
203 #endif
204 #undef ACTIVE_ESCAPE
205  }
206  }
207  }
208 
209  connect (this, SIGNAL (buttonClicked (QAbstractButton *)),
211  SLOT (dialog_button_clicked (QAbstractButton *)));
212  }
213 
214  ListDialog::ListDialog (const QStringList& list, const QString& mode,
215  int wd, int ht, const QList<int>& initial,
216  const QString& title, const QStringList& prompt,
217  const QString& ok_string,
218  const QString& cancel_string)
219  : QDialog (), m_model (new QStringListModel (list))
220  {
221  QListView *view = new QListView;
222  view->setModel (m_model);
223 
224  if (mode == "single")
225  view->setSelectionMode (QAbstractItemView::SingleSelection);
226  else if (mode == "multiple")
227  view->setSelectionMode (QAbstractItemView::ExtendedSelection);
228  else
229  view->setSelectionMode (QAbstractItemView::NoSelection);
230 
231  selector = view->selectionModel ();
232  int i = 0;
233  for (QList<int>::const_iterator it = initial.begin ();
234  it != initial.end (); it++)
235  {
236  QModelIndex idx = m_model->index (initial.value (i++) - 1, 0,
237  QModelIndex ());
238  selector->select (idx, QItemSelectionModel::Select);
239  }
240 
241  bool fixed_layout = false;
242  if (wd > 0 && ht > 0)
243  {
244  view->setFixedSize (wd, ht);
245  fixed_layout = true;
246  }
247 
248  view->setEditTriggers (QAbstractItemView::NoEditTriggers);
249 
250  QVBoxLayout *listLayout = new QVBoxLayout;
251  if (! prompt.isEmpty ())
252  {
253  // For now, assume html-like Rich Text. May be incompatible
254  // with something down the road, but just testing capability.
255  QString prompt_string;
256  for (int j = 0; j < prompt.length (); j++)
257  {
258  if (j > 0)
259  // FIXME: Why define and then immediately test value?
260 #define RICH_TEXT 1
261 #if RICH_TEXT
262  prompt_string.append ("<br>");
263 #else
264  prompt_string.append ("\n");
265 #endif
266  prompt_string.append (prompt.at (j));
267  }
268  QLabel *plabel = new QLabel (prompt_string);
269 #if RICH_TEXT
270  plabel->setTextFormat (Qt::RichText);
271 #endif
272 #undef RICH_TEXT
273  listLayout->addWidget (plabel);
274  }
275  listLayout->addWidget (view);
276  QPushButton *select_all = new QPushButton (tr ("Select All"));
277  select_all->setVisible (mode == "multiple");
278  listLayout->addWidget (select_all);
279 
280  QPushButton *buttonOk = new QPushButton (ok_string);
281  QPushButton *buttonCancel = new QPushButton (cancel_string);
282  QHBoxLayout *buttonsLayout = new QHBoxLayout;
283  buttonsLayout->addStretch (1);
284  buttonsLayout->addWidget (buttonOk);
285  buttonsLayout->addWidget (buttonCancel);
286  buttonOk->setDefault (true);
287 
288  QVBoxLayout *mainLayout = new QVBoxLayout;
289  mainLayout->addLayout (listLayout);
290  mainLayout->addSpacing (12);
291  mainLayout->addLayout (buttonsLayout);
292  setLayout (mainLayout);
293  if (fixed_layout)
294  layout ()->setSizeConstraint (QLayout::SetFixedSize);
295 
296  // If empty, make blank rather than use default OS behavior.
297  setWindowTitle (title.isEmpty () ? " " : title);
298 
299  connect (select_all, SIGNAL (clicked ()),
300  view, SLOT (selectAll ()));
301 
302  connect (buttonOk, SIGNAL (clicked ()),
303  this, SLOT (buttonOk_clicked ()));
304 
305  connect (buttonCancel, SIGNAL (clicked ()),
306  this, SLOT (buttonCancel_clicked ()));
307 
308  connect (this, SIGNAL (finish_selection (const QIntList&, int)),
310  SLOT (list_select_finished (const QIntList&, int)));
311 
312  connect (view, SIGNAL (doubleClicked (const QModelIndex&)),
313  this, SLOT (item_double_clicked (const QModelIndex&)));
314  }
315 
317  {
318  delete m_model;
319  }
320 
322  {
323  // Store information about what button was pressed so that builtin
324  // functions can retrieve.
325  QModelIndexList selected_index = selector->selectedIndexes ();
326  QIntList selected_int;
327 
328  for (int i = 0; i < selected_index.size (); i++)
329  selected_int << selected_index.at (i).row () + 1;
330 
331  emit finish_selection (selected_int, 1);
332 
333  done (QDialog::Accepted);
334  }
335 
337  {
338  // Store information about what button was pressed so that builtin
339  // functions can retrieve.
340  QIntList empty;
341 
342  emit finish_selection (empty, 0);
343 
344  done (QDialog::Rejected);
345  }
346 
347  void ListDialog::reject (void)
348  {
350  }
351 
352  void ListDialog::item_double_clicked (const QModelIndex&)
353  {
354  buttonOk_clicked ();
355  }
356 
357  InputDialog::InputDialog (const QStringList& prompt, const QString& title,
358  const QFloatList& nr, const QFloatList& nc,
359  const QStringList& defaults)
360  : QDialog ()
361  {
362 
363 #define LINE_EDIT_FOLLOWS_PROMPT 0
364 
365 #if LINE_EDIT_FOLLOWS_PROMPT
366  // Prompt on left followed by input on right.
367  QGridLayout *promptInputLayout = new QGridLayout;
368 #else
369  // Prompt aligned above input.
370  QVBoxLayout *promptInputLayout = new QVBoxLayout;
371 #endif
372  int N_gridrows = prompt.size ();
373  for (int i = 0; i < N_gridrows; i++)
374  {
375  QLabel *label = new QLabel (prompt.at (i));
376  QLineEdit *line_edit = new QLineEdit ();
377  if (i < defaults.size ())
378  line_edit->setText (defaults.at (i));
379  if (i < nr.size () && nr.at (i) > 0)
380  {
381  QSize qsize = line_edit->sizeHint ();
382  int intval = qsize.height () * nr.at (i);
383  line_edit->setFixedHeight (intval);
384  if (i < nc.size () && nc.at (i) > 0)
385  {
386  intval = qsize.height () * nc.at (i) / 2;
387  line_edit->setFixedWidth (intval);
388  }
389  }
390  input_line << line_edit;
391 #if LINE_EDIT_FOLLOWS_PROMPT
392  promptInputLayout->addWidget (label, i + 1, 0);
393  promptInputLayout->addWidget (line_edit, i + 1, 1);
394 #else
395  promptInputLayout->addWidget (label);
396  promptInputLayout->addWidget (line_edit);
397 #endif
398  }
399 #undef LINE_EDIT_FOLLOWS_PROMPT
400 
401  QPushButton *buttonOk = new QPushButton ("OK");
402  QPushButton *buttonCancel = new QPushButton ("Cancel");
403  QHBoxLayout *buttonsLayout = new QHBoxLayout;
404  buttonsLayout->addStretch (1);
405  buttonsLayout->addWidget (buttonOk);
406  buttonsLayout->addWidget (buttonCancel);
407 
408  QVBoxLayout *mainLayout = new QVBoxLayout;
409  mainLayout->addLayout (promptInputLayout);
410  mainLayout->addSpacing (12);
411  mainLayout->addLayout (buttonsLayout);
412  setLayout (mainLayout);
413 
414  // If empty, make blank rather than use default OS behavior.
415  setWindowTitle (title.isEmpty () ? " " : title);
416 
417  connect (buttonOk, SIGNAL (clicked ()),
418  this, SLOT (buttonOk_clicked ()));
419 
420  connect (buttonCancel, SIGNAL (clicked ()),
421  this, SLOT (buttonCancel_clicked ()));
422 
423  connect (this, SIGNAL (finish_input (const QStringList&, int)),
425  SLOT (input_finished (const QStringList&, int)));
426  }
427 
429  {
430  // Store information about what button was pressed so that builtin
431  // functions can retrieve.
432  QStringList string_result;
433  for (int i = 0; i < input_line.size (); i++)
434  string_result << input_line.at (i)->text ();
435  emit finish_input (string_result, 1);
436  done (QDialog::Accepted);
437  }
438 
440  {
441  // Store information about what button was pressed so that builtin
442  // functions can retrieve.
443  QStringList empty;
444  emit finish_input (empty, 0);
445  done (QDialog::Rejected);
446  }
447 
449  {
451  }
452 
453  FileDialog::FileDialog (const QStringList& name_filters, const QString& title,
454  const QString& filename, const QString& dirname,
455  const QString& multimode)
456  : QFileDialog ()
457  {
458  // Create a NonModal message.
459  setWindowModality (Qt::NonModal);
460 
461  setWindowTitle (title.isEmpty () ? " " : title);
462  setDirectory (dirname);
463 
464  if (multimode == "on") // uigetfile multiselect=on
465  {
466  setFileMode (QFileDialog::ExistingFiles);
467  setAcceptMode (QFileDialog::AcceptOpen);
468  }
469  else if (multimode == "create") // uiputfile
470  {
471  setFileMode (QFileDialog::AnyFile);
472  setAcceptMode (QFileDialog::AcceptSave);
473  setOption (QFileDialog::DontConfirmOverwrite, false);
474  setConfirmOverwrite (true);
475  }
476  else if (multimode == "dir") // uigetdir
477  {
478  setFileMode (QFileDialog::Directory);
479  setOption (QFileDialog::ShowDirsOnly, true);
480  setOption (QFileDialog::HideNameFilterDetails, true);
481  setAcceptMode (QFileDialog::AcceptOpen);
482  }
483  else // uigetfile multiselect=off
484  {
485  setFileMode (QFileDialog::ExistingFile);
486  setAcceptMode (QFileDialog::AcceptOpen);
487  }
488 
489  setNameFilters (name_filters);
490 
491  selectFile (filename);
492 
493  connect (this,
494  SIGNAL (finish_input (const QStringList&, const QString&, int)),
496  SLOT (filedialog_finished (const QStringList&, const QString&,
497  int)));
498  connect (this, SIGNAL (accepted ()), this, SLOT (acceptSelection ()));
499  connect (this, SIGNAL (rejected ()), this, SLOT (rejectSelection ()));
500  }
501 
503  {
504  QStringList empty;
505  emit finish_input (empty, "", 0);
506  }
507 
509  {
510  QStringList string_result;
511  QString path;
512  int idx = 1;
513 
514  string_result = selectedFiles ();
515 
516  if (testOption (QFileDialog::ShowDirsOnly) == true &&
517  string_result.size () > 0)
518  {
519  path = string_result[0];
520  }
521  else
522  {
523  path = directory ().absolutePath ();
524  }
525 
526  // Matlab expects just the filename, whereas the file dialog gave us
527  // full path names, so fix it.
528 
529  for (int i = 0; i < string_result.size (); i++)
530  string_result[i] = QFileInfo (string_result[i]).fileName ();
531 
532  // if not showing only dirs, add end slash for the path component
533  if (testOption (QFileDialog::ShowDirsOnly) == false)
534  path += '/';
535 
536  // convert to native slashes
537  path = QDir::toNativeSeparators (path);
538 
539  QStringList name_filters = nameFilters ();
540  idx = name_filters.indexOf (selectedNameFilter ()) + 1;
541 
542  // send the selected info
543  emit finish_input (string_result, path, idx);
544  }
545 }
void reject(void)
Definition: dialog.cc:448
QStringList * m_string_list
Definition: dialog.h:165
void reject(void)
Definition: dialog.cc:347
The value of lines which begin with a space character are not saved in the history list A value of all commands are saved on the history list
Definition: oct-hist.cc:734
void input_finished(const QStringList &input, int button_pressed)
Definition: dialog.cc:110
void list_select_finished(const QIntList &selected, int button_pressed)
Definition: dialog.cc:94
F77_RET_T const F77_INT & N
void wake_all(void)
Definition: dialog.h:126
Return the CPU time used by your Octave session The first output is the total time spent executing your process and is equal to the sum of second and third which are the number of CPU seconds spent executing in user mode and the number of CPU seconds spent executing in system mode
Definition: data.cc:6348
QList< QLineEdit * > input_line
Definition: dialog.h:239
QItemSelectionModel * selector
Definition: dialog.h:204
QString * m_path_name
Definition: dialog.h:168
std::string filename
Definition: urlwrite.cc:121
std::string dirname(const std::string &path)
Definition: file-ops.cc:353
QAbstractItemModel * m_model
Definition: dialog.h:232
MessageDialog(const QString &message, const QString &title, const QString &icon, const QStringList &button, const QString &defbutton, const QStringList &role)
Definition: dialog.cc:144
void buttonCancel_clicked(void)
Definition: dialog.cc:439
void message(const char *name, const char *fmt,...)
Definition: error.cc:435
void item_double_clicked(const QModelIndex &)
Definition: dialog.cc:352
done
Definition: syscalls.cc:251
create a structure array and initialize its values The dimensions of each cell array of values must match Singleton cells and non cell values are repeated so that they fill the entire array If the cells are empty
Definition: ov-struct.cc:1736
void finish_input(const QStringList &, int)
void finish_selection(const QIntList &, int)
QIntList * m_list_index
Definition: dialog.h:166
void finish_input(const QStringList &, const QString &, int)
OCTAVE_EXPORT octave_value_list or cell arrays Arguments are concatenated vertically The returned values are padded with blanks as needed to make each row of the string array have the same length Empty input strings are significant and will concatenated in the output For numerical input
Definition: strfns.cc:81
void acceptSelection(void)
Definition: dialog.cc:508
FileDialog(const QStringList &filters, const QString &title, const QString &filename, const QString &dirname, const QString &multimode)
Definition: dialog.cc:453
QStringList m_button_list
Definition: dialog.h:161
void buttonOk_clicked(void)
Definition: dialog.cc:428
ListDialog(const QStringList &list, const QString &mode, int width, int height, const QList< int > &initial, const QString &name, const QStringList &prompt, const QString &ok_string, const QString &cancel_string)
Definition: dialog.cc:214
OCTAVE_EXPORT octave_value_list the first data row corresponds to an index of zero The a spreadsheet style form such as the file is read until end of file is reached The such as text
Definition: dlmread.cc:194
otherwise an error message is printed The permission mask is a UNIX concept used when creating new objects on a file system such as files
Definition: file-io.cc:3038
QString rm_amp(const QString &text)
Definition: dialog.cc:61
for i
Definition: data.cc:5264
QList< int > QIntList
Definition: dialog.h:38
void buttonOk_clicked(void)
Definition: dialog.cc:321
void buttonCancel_clicked(void)
Definition: dialog.cc:336
void dialog_button_clicked(QAbstractButton *button)
Definition: dialog.cc:68
void filedialog_finished(const QStringList &files, const QString &path, int filterindex)
Definition: dialog.cc:126
QUIWidgetCreator uiwidget_creator
Definition: dialog.cc:46
InputDialog(const QStringList &prompt, const QString &title, const QFloatList &nr, const QFloatList &nc, const QStringList &defaults)
Definition: dialog.cc:357
OCTAVE_EXPORT octave_value_list directory
Definition: variables.cc:593
void rejectSelection(void)
Definition: dialog.cc:502