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