1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2011-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 #  include "config.h"
28 #endif
29 
30 #include <iostream>
31 
32 #include <QTreeWidget>
33 
34 #include "gui-preferences-ws.h"
35 #include "gui-settings.h"
36 #include "octave-qobject.h"
37 #include "workspace-model.h"
38 
39 #include "syminfo.h"
40 #include "utils.h"
41 
42 namespace octave
43 {
workspace_model(base_qobject & oct_qobj,QObject * p)44   workspace_model::workspace_model (base_qobject& oct_qobj, QObject *p)
45     : QAbstractTableModel (p), m_octave_qobj (oct_qobj)
46   {
47     m_columnNames.append (tr ("Name"));
48     m_columnNames.append (tr ("Class"));
49     m_columnNames.append (tr ("Dimension"));
50     m_columnNames.append (tr ("Value"));
51     m_columnNames.append (tr ("Attribute"));
52 
53     // Initialize the background and foreground colors of special
54     // classes in the workspace view.  The structure is
55     // m_storage_class_colors(1,2,...,colors):        background colors
56     // m_storage_class_colors(colors+1,...,2*colors): foreground colors
57     for (unsigned int i = 0; i < 2*ws_colors_count; i++)
58       m_storage_class_colors.append (QColor (Qt::white));
59 
60   }
61 
62   int
rowCount(const QModelIndex &) const63   workspace_model::rowCount (const QModelIndex&) const
64   {
65     return m_symbols.size ();
66   }
67 
68   int
columnCount(const QModelIndex &) const69   workspace_model::columnCount (const QModelIndex&) const
70   {
71     return m_columnNames.size ();
72   }
73 
74   Qt::ItemFlags
flags(const QModelIndex & idx) const75   workspace_model::flags (const QModelIndex& idx) const
76   {
77     Qt::ItemFlags retval = Qt::NoItemFlags;
78 
79     if (idx.isValid ())
80       {
81         retval |= Qt::ItemIsEnabled;
82 
83         if (m_top_level && idx.column () == 0)
84           retval |= Qt::ItemIsSelectable;
85       }
86 
87     return retval;
88   }
89 
90   QVariant
headerData(int section,Qt::Orientation orientation,int role) const91   workspace_model::headerData (int section, Qt::Orientation orientation,
92                                int role) const
93   {
94     if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
95       return m_columnNames[section];
96     else
97       return QVariant ();
98   }
99 
100   QVariant
data(const QModelIndex & idx,int role) const101   workspace_model::data (const QModelIndex& idx, int role) const
102   {
103     QVariant retval;
104 
105     if (idx.isValid ())
106       {
107         if ((role == Qt::BackgroundColorRole || role == Qt::ForegroundRole)
108             && m_enable_colors)
109           {
110             int actual_class
111               = ws_class_chars.indexOf (m_scopes[idx.row ()].toLatin1 ());
112             if (actual_class >= 0)
113               {
114                 // Valid class: Get background (normal indexes) or foreground
115                 // color (indexes with offset)
116                 if (role == Qt::ForegroundRole)
117                   actual_class += ws_colors_count;
118 
119                 return QVariant (m_storage_class_colors.at (actual_class));
120               }
121             else
122               return retval;
123           }
124 
125         if (role == Qt::DisplayRole
126             || (idx.column () == 0 && role == Qt::EditRole)
127             || (idx.column () == 0 && role == Qt::ToolTipRole))
128           {
129             switch (idx.column ())
130               {
131               case 0:
132                 if (role == Qt::ToolTipRole)
133                   retval
134                     = QVariant (tr ("Right click to copy, rename, or display"));
135                 else
136                   retval = QVariant (m_symbols[idx.row ()]);
137                 break;
138 
139               case 1:
140                 retval = QVariant (m_class_names[idx.row ()]);
141                 break;
142 
143               case 2:
144                 retval = QVariant (m_dimensions[idx.row ()]);
145                 break;
146 
147               case 3:
148                 retval = QVariant (m_values[idx.row ()]);
149                 break;
150 
151               case 4:
152                 {
153                   QString sclass;
154 
155                   int actual_class
156                     = ws_class_chars.indexOf (m_scopes[idx.row ()].toLatin1 ());
157 
158                   if (actual_class >= 0)
159                     sclass = ws_color_names.at (actual_class);
160 
161                   if (m_complex_flags[idx.row ()])
162                     {
163                       if (sclass.isEmpty ())
164                         sclass = tr ("complex");
165                       else
166                         sclass += ", " + tr ("complex");
167                     }
168 
169                   retval = QVariant (sclass);
170                 }
171                 break;
172               }
173           }
174       }
175 
176     return retval;
177   }
178 
179   void
set_workspace(bool top_level,bool,const symbol_info_list & syminfo)180   workspace_model::set_workspace (bool top_level, bool /* debug */,
181                                   const symbol_info_list& syminfo)
182   {
183     clear_data ();
184 
185     m_top_level = top_level;
186     m_syminfo_list = syminfo;
187 
188     update_table ();
189   }
190 
191   void
clear_workspace(void)192   workspace_model::clear_workspace (void)
193   {
194     clear_data ();
195     update_table ();
196   }
197 
198   void
notice_settings(const gui_settings * settings)199   workspace_model::notice_settings (const gui_settings *settings)
200   {
201     m_enable_colors = settings->value (ws_enable_colors).toBool ();
202 
203     for (int i = 0; i < ws_colors_count; i++)
204       {
205         QColor setting_color = settings->value (ws_colors[i].key,
206                                                 ws_colors[i].def).value<QColor> ();
207 
208         QPalette p (setting_color);
209         m_storage_class_colors.replace (i,setting_color);
210 
211         QColor fg_color = p.color (QPalette::WindowText);
212         m_storage_class_colors.replace (i + ws_colors_count, fg_color);
213 
214       }
215   }
216 
217   void
clear_data(void)218   workspace_model::clear_data (void)
219   {
220     m_top_level = false;
221     m_syminfo_list = symbol_info_list ();
222     m_scopes = QString ();
223     m_symbols = QStringList ();
224     m_class_names = QStringList ();
225     m_dimensions = QStringList ();
226     m_values = QStringList ();
227     m_complex_flags = QIntList ();
228   }
229 
230   void
update_table(void)231   workspace_model::update_table (void)
232   {
233     beginResetModel ();
234 
235     for (const auto& syminfo : m_syminfo_list)
236       {
237         std::string nm = syminfo.name ();
238 
239         octave_value val = syminfo.value ();
240 
241         // FIXME: fix size for objects, see kluge in ov.cc
242         Matrix sz = val.size ();
243         dim_vector dv = dim_vector::alloc (sz.numel ());
244         for (octave_idx_type i = 0; i < dv.ndims (); i++)
245           dv(i) = sz(i);
246 
247         char storage = ' ';
248         if (syminfo.is_formal ())
249           storage = 'a';
250         else if (syminfo.is_global ())
251           storage = 'g';
252         else if (syminfo.is_persistent ())
253           storage = 'p';
254 
255         std::ostringstream buf;
256         val.short_disp (buf);
257         std::string short_disp_str = buf.str ();
258 
259         m_scopes.append (storage);
260         m_symbols.append (QString::fromStdString (nm));
261         m_class_names.append (QString::fromStdString (val.class_name ()));
262         m_dimensions.append (QString::fromStdString (dv.str ()));
263         m_values.append (QString::fromStdString (short_disp_str));
264         m_complex_flags.append (val.iscomplex ());
265       }
266 
267     endResetModel ();
268 
269     emit model_changed ();
270   }
271 }
272