1 
2 /******************************************************************************
3  * MODULE     : qt_window_widget.hpp
4  * DESCRIPTION: QT window widget.
5  * COPYRIGHT  : (C) 2008  Massimiliano Gubinelli
6  *******************************************************************************
7  * This software falls under the GNU general public license version 3 or later.
8  * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9  * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10  ******************************************************************************/
11 
12 #include "qt_window_widget.hpp"
13 #include "qt_tm_widget.hpp"
14 #include "qt_utilities.hpp"
15 #include "qt_gui.hpp"
16 #include "QTMWindow.hpp"
17 #include "QTMGuiHelper.hpp"
18 #include "QTMMenuHelper.hpp"
19 
20 #include "message.hpp"
21 #include "analyze.hpp"
22 #include "window.hpp"
23 
24 #include <QWidget>
25 #include <QVariant>
26 #include <QDockWidget>
27 
28 /*! Construct a qt_window_widget_rep around an already compiled widget.
29 
30  This means that the QWidget passed as an argument already represents a fully
31  parsed and compiled scheme widget. We use this fact to decide whether we must
32  be resizable or not, for instance.
33 
34  The parameter "fake" means this qt_window_widget_rep is not part of the window
35  list, so the nr_windows global variable must not be updated.
36  */
qt_window_widget_rep(QWidget * _wid,string name,command _quit,bool _fake)37 qt_window_widget_rep::qt_window_widget_rep (QWidget* _wid, string name,
38                                             command _quit, bool _fake)
39 : qt_widget_rep (window_widget, _wid), orig_name(name), quit(_quit), fake(_fake)
40 {
41   qwid->setProperty ("texmacs_window_widget",
42                      QVariant::fromValue ((void*) this));
43 
44     // Try to connect only if the QWidget has a closed() signal
45     // We need this for the QDockWidgets we use in side tools (see qt_tm_widget_rep)
46   if (qwid->metaObject() ->
47       indexOfSignal (QMetaObject::normalizedSignature ("closed()").constData ()) != -1) {
48     QTMCommand* qtmcmd = new QTMCommand (qwid, quit);
49     QObject::connect(qwid, SIGNAL (closed()), qtmcmd, SLOT (apply()));
50   }
51 
52   if (!has_resizable_children (_wid))
53     qwid->setFixedSize (qwid->sizeHint());
54 
55     // HACK: don't increment window count for side tools or any other fake windows
56   if (!fake) win_id = ++nr_windows;
57 
58   if (DEBUG_QT)
59     debug_qt << "Creating qt_window_widget " << id << "\n";
60 }
61 
62 /*!
63  WARNING! This should be the only place were QWidgets are destroyed!
64  */
~qt_window_widget_rep()65 qt_window_widget_rep::~qt_window_widget_rep ()
66 {
67   if (!fake) nr_windows--;
68   if (DEBUG_QT)
69     debug_qt << "Deleting qt_window_widget " << id << "\n";
70   if (qwid) qwid->deleteLater();
71 }
72 
73 widget
popup_window_widget(string s)74 qt_window_widget_rep::popup_window_widget (string s)
75 {
76   qwid->setWindowTitle (to_qstring (s));
77   qwid->setWindowModality (Qt::NonModal);
78   qwid->setWindowFlags (Qt::Popup);
79   return this;
80 }
81 
82 /*! Looks among the widget's parents for the containing texmacs window
83  */
84 widget_rep*
widget_from_qwidget(QWidget * q)85 qt_window_widget_rep::widget_from_qwidget (QWidget* q)
86 {
87   while (q != NULL) {
88     QVariant v = q->property ("texmacs_window_widget");
89     if (v.canConvert<void*> ())
90       return static_cast<widget_rep*> (v.value<void*> ());
91     else
92       q = q->parentWidget();
93   }
94   return NULL;
95 }
96 
97 /*! Returns true if any of the child QWidgets has different minimum and maximum
98  sizes, as set by qt_ui_element_rep::as_qwidget() for resize_widgets.
99  */
100 bool
has_resizable_children(QWidget * w,bool ret)101 qt_window_widget_rep::has_resizable_children (QWidget* w, bool ret) {
102     // Ignore any non QWidgets
103   if (!w) return false;
104 
105     // Hack: these must always be resizable
106   if (qobject_cast<QMainWindow*> (w) || qobject_cast<QDockWidget*> (w))
107     return true;
108 
109   ret = (w->minimumSize() != QSize (0,0) &&
110          w->maximumSize() != QSize (QWIDGETSIZE_MAX, QWIDGETSIZE_MAX) &&
111          w->minimumSize() != w->maximumSize());
112 
113   QObjectList ch = w->children();
114   for (int i=0; i<ch.size(); ++i)
115     ret = ret || has_resizable_children (qobject_cast<QWidget*> (ch[i]), ret);
116 
117   return ret;
118 }
119 
120 void
send(slot s,blackbox val)121 qt_window_widget_rep::send (slot s, blackbox val) {
122   if (DEBUG_QT_WIDGETS)
123     debug_widgets << "qt_window_widget_rep::send " << slot_name (s) << LF;
124 
125   switch (s) {
126     case SLOT_SIZE:
127     {
128       check_type<coord2>(val, s);
129       coord2 p = open_box<coord2> (val);
130       if (qwid) {
131         QSize size = to_qsize (p);
132         qwid->resize (size);
133       }
134     }
135       break;
136     case SLOT_POSITION:
137     {
138       check_type<coord2>(val, s);
139       coord2 p = open_box<coord2> (val);
140       if (qwid) {
141         QPoint pt = to_qpoint (p);
142 #ifdef OS_MACOS
143         pt.ry() = (pt.y() <= 40) ? 40 : pt.y();
144           // to avoid window under menu bar on MAC when moving at (0,0)
145           // FIXME: use the real menu bar height.
146 #endif
147         qwid->move (pt);
148       }
149     }
150       break;
151     case SLOT_VISIBILITY:
152     {
153       check_type<bool> (val, s);
154       bool flag = open_box<bool> (val);
155       if (qwid) {
156         if (flag) {
157           qwid->show();
158           // wid->activateWindow();
159           //WEIRD: in Ubuntu uncommenting the above line causes the main window
160           //to be opened in the background.
161           qwid->raise();
162         }
163         else qwid->hide();
164       }
165     }
166       break;
167     case SLOT_MOUSE_GRAB:
168     {
169       check_type<bool> (val, s);
170       bool flag = open_box<bool> (val);  // true= get grab, false= release grab
171       if (flag && qwid) {
172         qwid->setWindowFlags (Qt::Window);  // ok?
173         qwid->setWindowModality (Qt::WindowModal); //ok?
174         qwid->show();
175       }
176     }
177       break;
178     case SLOT_NAME:   // sets window *title* not the name
179     {
180       check_type<string> (val, s);
181       string name = open_box<string> (val);
182         // The [*] is for QWidget::setWindowModified()
183       if (qwid) qwid->setWindowTitle (to_qstring (name * "[*]"));
184     }
185       break;
186     case SLOT_MODIFIED:
187     {
188       check_type<bool> (val, s);
189       bool flag = open_box<bool> (val);
190       if (qwid) qwid->setWindowModified (flag);
191     }
192       break;
193     case SLOT_REFRESH:
194     {
195       check_type<string> (val, s);
196       string kind = open_box<string> (val);
197       the_gui->gui_helper->emitTmSlotRefresh (kind);
198     }
199       break;
200     default:
201       qt_widget_rep::send(s, val);
202   }
203 }
204 
205 blackbox
query(slot s,int type_id)206 qt_window_widget_rep::query (slot s, int type_id) {
207   if (DEBUG_QT_WIDGETS)
208     debug_widgets << "qt_window_widget_rep::query " << slot_name(s) << LF;
209   switch (s) {
210     case SLOT_IDENTIFIER:
211     {
212       check_type_id<int> (type_id, s);
213       return close_box<int> (win_id);
214     }
215 
216     case SLOT_POSITION:
217     {
218       check_type_id<coord2> (type_id, s);
219       QRect g;
220         // FIXME: dock widgets are embedded into qt_window_widget_reps as a temporary hack
221         // because of this the underlying widget is not always a top level window
222       if (qwid->isWindow()) g = qwid->frameGeometry();
223       else                  g = qwid->window()->frameGeometry();
224         //cout << "wpos: " << pt.x() << ", " << pt.y() << LF;
225       return close_box<coord2> (from_qpoint (QPoint (g.x(), g.y())));
226     }
227 
228     case SLOT_SIZE:
229     {
230       check_type_id<coord2> (type_id, s);
231       QSize sz = qwid->frameSize();
232       return close_box<coord2> (from_qsize (sz));
233     }
234 
235     default:
236       return qt_widget_rep::query (s, type_id);
237   }
238 }
239 
240 widget
read(slot s,blackbox index)241 qt_window_widget_rep::read (slot s, blackbox index) {
242   if (DEBUG_QT_WIDGETS)
243     debug_widgets << "qt_window_widget_rep::read " << slot_name(s)
244                   << "\tWidget id: " << id << LF;
245 
246   switch (s) {
247     case SLOT_WINDOW:  // We use this in qt_gui_rep::show_help_balloon()
248       check_type_void (index, s);
249       return this;
250 
251     default:
252       return qt_widget_rep::read (s, index);
253   }
254 }
255 
256 void
notify(slot s,blackbox new_val)257 qt_window_widget_rep::notify (slot s, blackbox new_val) {
258   if (DEBUG_QT_WIDGETS)
259     debug_widgets << "qt_window_widget_rep::notify " << slot_name(s) << LF;
260   widget_rep::notify (s, new_val);
261 }
262 
263 
264 /******************************************************************************
265  * popup widget
266  ******************************************************************************/
267 
268 
qt_popup_widget_rep(widget wid,command _quit)269 qt_popup_widget_rep::qt_popup_widget_rep (widget wid, command _quit)
270 : qt_widget_rep(qt_widget_rep::popup_widget, 0), quit(_quit) {
271 
272   qwid = new QTMPopupWidget(concrete(wid)->as_qwidget());
273 
274   if (qwid->metaObject() ->
275       indexOfSignal (QMetaObject::normalizedSignature ("closed()").constData ()) != -1) {
276   QTMCommand* qtmcmd = new QTMCommand(qwid, quit);
277   QObject::connect(qwid, SIGNAL (closed()), qtmcmd, SLOT (apply()));
278   }
279 }
280 
281 /*!
282  WARNING! This should be the only place were QWidgets are destroyed!
283  */
~qt_popup_widget_rep()284 qt_popup_widget_rep::~qt_popup_widget_rep () {
285   if (qwid) qwid->deleteLater();
286 }
287 
288 widget
popup_window_widget(string s)289 qt_popup_widget_rep::popup_window_widget(string s) {
290   qwid->setWindowTitle (to_qstring (s)); // useless for Qt::Popup
291 
292   return this;
293 }
294 
295 void
send(slot s,blackbox val)296 qt_popup_widget_rep::send (slot s, blackbox val) {
297 
298   switch (s) {
299     case SLOT_SIZE:
300     {
301       check_type<coord2>(val, s);
302       qwid->resize (to_qsize (open_box<coord2> (val)));
303     }
304       break;
305 
306     case SLOT_POSITION:
307     {
308       check_type<coord2>(val, s);
309       qwid->move (to_qpoint (open_box<coord2> (val)));
310     }
311       break;
312 
313     case SLOT_VISIBILITY:
314     {
315       check_type<bool> (val, s);
316       qwid->setVisible(open_box<bool> (val));
317     }
318       break;
319 
320       //FIXME: what's this?
321     case SLOT_MOUSE_GRAB:
322     {
323       check_type<bool> (val, s);
324       bool flag = open_box<bool> (val);  // true= get grab, false= release grab
325 
326       qwid->hide();
327       if (flag) qwid->setWindowModality(Qt::WindowModal); //ok?
328       else      qwid->setWindowModality(Qt::NonModal);    //ok?
329       qwid->show();
330     }
331       break;
332 
333     default:
334       qt_widget_rep::send(s, val);
335   }
336 
337   if (DEBUG_QT_WIDGETS)
338     debug_widgets << "qt_popup_widget_rep: sent " << slot_name (s)
339                   << "\t\tto widget\t"         << type_as_string() << LF;
340 }
341 
342 blackbox
query(slot s,int type_id)343 qt_popup_widget_rep::query (slot s, int type_id) {
344   if (DEBUG_QT_WIDGETS)
345     debug_widgets << "qt_popup_widget_rep::query " << slot_name(s) << LF;
346   switch (s) {
347     case SLOT_POSITION:
348     {
349       check_type_id<coord2> (type_id, s);
350       return close_box<coord2> (from_qpoint (qwid->pos()));
351     }
352     case SLOT_SIZE:
353     {
354       check_type_id<coord2> (type_id, s);
355       return close_box<coord2> (from_qsize (qwid->size()));
356     }
357     default:
358       return qt_widget_rep::query (s, type_id);
359   }
360 }
361