1 
2 /******************************************************************************
3 * MODULE     : qt_utilities.cpp
4 * DESCRIPTION: Utilities for QT
5 * COPYRIGHT  : (C) 2007  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 "QTMStyle.hpp"
13 #include "qt_utilities.hpp"
14 #include <time.h>
15 
16 #include <QImage>
17 #include <QPrinter>
18 #include <QPainter>
19 #include <QCoreApplication>
20 #include <QLocale>
21 #include <QDateTime>
22 #include <QTextCodec>
23 #include <QHash>
24 #include <QStringList>
25 #include <QKeySequence>
26 
27 #include <QPrinter>
28 #include <QPrintDialog>
29 
30 #include "colors.hpp"
31 
32 #include "dictionary.hpp"
33 #include "converter.hpp"
34 #include "language.hpp"
35 #include "scheme.hpp"
36 #include "wencoding.hpp"
37 
38 #include "qt_gui.hpp"    // gui_maximal_extents()
39 
40 #ifdef USE_GS
41 #include "Ghostscript/gs_utilities.hpp"
42 #endif
43 
44 #define SCREEN_PIXEL (PIXEL)
45 
46 /******************************************************************************
47  * Debugging
48  ******************************************************************************/
49 
50 void
qt_dump(QObject * obj,int indent)51 qt_dump (QObject* obj, int indent) {
52   if (obj == NULL) { cout << "NULL\n"; return; }
53   for (int j = 0;j < indent; ++j) cout << "  ";
54   cout << from_qstring (obj->metaObject()->className()) << ":\n";
55   foreach (QObject* child , obj->children()) {
56     qt_dump (child, indent+1);
57   }
58 }
59 
60 tm_ostream&
operator <<(tm_ostream & out,QRect rect)61 operator << (tm_ostream& out, QRect rect) {
62   return out << "(" << rect.x() << "," << rect.y() << ","
63   << rect.width() << "," << rect.height() << ")";
64 }
65 
66 /******************************************************************************
67  * Conversion of data types
68  ******************************************************************************/
69 
70 QFont
to_qfont(int style,QFont font)71 to_qfont (int style, QFont font) {
72   if (style & WIDGET_STYLE_MINI) {  // Use smaller text font
73     int fs = as_int (get_preference ("gui:mini-fontsize", QTM_MINI_FONTSIZE));
74     font.setPointSize (fs > 0 ? fs : QTM_MINI_FONTSIZE);
75   }
76   if (style & WIDGET_STYLE_MONOSPACED) {  // Use monospaced font
77     font.setFixedPitch (true);        //FIXME: ignored for fonts in QActions
78 #if (QT_VERSION >= 0x040800)
79     font.setStyleHint (QFont::Monospace);
80 #endif
81   }
82   if (style & WIDGET_STYLE_GREY)      // use grey text font
83     font.setWeight (QFont::Light);    // FIXME: this is only an approximation
84   if (style & WIDGET_STYLE_PRESSED)   // Button is currently pressed
85     {}
86   if (style & WIDGET_STYLE_INERT)     // Only render, don't associate any action
87     {}
88   if (style & WIDGET_STYLE_BUTTON)    // Render button as standard button
89     {}
90   if (style & WIDGET_STYLE_BOLD)
91     font.setBold(true);
92   return font;
93 }
94 
95 /*! Try to convert a TeXmacs lenght (em, px, w, h) into a QSize.
96 
97  This uses the widget's current size to compute relative sizes as specified
98  with "FFw", where FF is the string representation of a double.
99  A value of "1w" should not affect the widget size.
100 
101  FIXME: does 1w mean 100% of the contents' size or 100% of the available size?
102  */
103 QSize
qt_decode_length(string width,string height,const QSize & ref,const QFontMetrics & fm)104 qt_decode_length (string width, string height,
105                   const QSize& ref, const QFontMetrics& fm) {
106   QSize size = ref;
107 
108     // Width as a function of the default width
109   if (ends (width, "w") && is_double (width (0, N(width) - 1))) {
110     double x = as_double (width (0, N(width) - 1));
111     size.rwidth() *= x;
112   }
113     // Width as a function of the default height
114   else if (ends (width, "h") && is_double (width (0, N(width) - 1))) {
115     double y = as_double (width (0, N(width) - 1));
116     size.rwidth() = y * size.height();
117   }
118     // Absolute EM units
119   else if (ends (width, "em") && is_double (width (0, N(width) - 2))) {
120     double x = as_double (width (0, N(width) - 2));
121     size.setWidth(x * fm.width("M"));
122   }
123     // Absolute pixel units
124   else if (ends (width, "px") && is_double (width (0, N(width) - 2))) {
125     double x = as_double (width (0, N(width) - 2));
126     size.setWidth(x);
127   }
128 
129     // Height as a function of the default width
130   if (ends (height, "w") && is_double (height (0, N(height) - 1))) {
131     double x = as_double (height (0, N(height) - 1));
132     size.rheight() = x * size.width();
133   }
134     // Height as a function of the default height
135   else if (ends (height, "h") && is_double (width (0, N(width) - 1))) {
136     double y = as_double (height (0, N(height) - 1));
137     size.rheight() *= y;
138   }
139   else if (ends (height, "em") && is_double (height (0, N(height) - 2))) {
140     double y = as_double (height (0, N(height) - 2));
141     size.setHeight(y * fm.width("M"));
142   }
143   else if (ends (height, "px") && is_double (height (0, N(height) - 2))) {
144     double y = as_double (height (0, N(height) - 2));
145     size.setHeight(y);
146   }
147   return size;
148 }
149 
150 // used only by to_qkeysequence
151 static string
conv_sub(const string & ks)152 conv_sub (const string& ks) {
153   string r(ks);
154   r = replace (r, "S-", "Shift+");
155   r = replace (r, "A-", "Alt+");
156   //r = replace (r, "K-", "");
157 #ifdef Q_WS_MAC
158   r = replace (r, "C-", "Meta+");
159   r = replace (r, "M-", "Ctrl+");
160 #else
161   r = replace (r, "C-", "Ctrl+");
162   r = replace (r, "M-", "Meta+");
163 #endif
164   array<string> a = tokenize (r, " ");
165   for (int i = 0; i < N(a); ++i) {
166     int pos = -1, tmp = 0, n = N(a[i]);
167     while (tmp < n && (tmp = search_forwards ("+", tmp, a[i])) != -1)
168       pos = tmp++;
169     if (pos != -1 && n > pos+1) {
170       if (a[i][pos+1] == '&')
171          // FIXME: this isn't enough to see the ampersand in the menus... (?)
172         a[i] = a[i](0, pos+1) * "&&";
173       else if (is_locase (a[i][pos+1]))
174         a[i] = a[i](0, pos) * upcase_all (a[i] (pos, n));
175       else if (is_upcase (a[i][pos+1])) {
176         // HACK: don't prepend Shift for function keys F1, F2...
177         if (n>pos+2 && a[i][pos+1] == 'F' && as_int (a[i][pos+2]) > 0)
178           ;
179         else
180           a[i] = a[i](0, pos) * "+Shift" * upcase_all (a[i] (pos, n));
181       }
182     }
183   }
184   return recompose (a, ",");
185 }
186 
187 QKeySequence
to_qkeysequence(string ks)188 to_qkeysequence (string ks) {
189   string r (conv_sub (ks));
190   if (DEBUG_QT && N(r) > 0) {
191     QKeySequence qks (to_qstring (r));
192     debug_qt << "ks: " << ks << " --> " << r << " --> "
193              << qks.toString (QKeySequence::NativeText).toAscii().data() << LF;
194     return qks;
195   }
196   return QKeySequence (to_qstring (r));
197 }
198 
199 coord4
from_qrect(const QRect & rect)200 from_qrect (const QRect & rect) {
201   SI c1, c2, c3, c4;
202   c1= rect.x() * SCREEN_PIXEL;
203   c2= -(rect.y() + rect.height()) * SCREEN_PIXEL;
204   c3= (rect.x() + rect.width()) * SCREEN_PIXEL;
205   c4= -rect.y() * SCREEN_PIXEL;
206   return coord4 (c1, c2, c3, c4);
207 }
208 
209 /*! Transforms a rectangle given by its lower left and upper right corners
210  into one given by its upper left and width/height */
211 QRect
to_qrect(const coord4 & p)212 to_qrect (const coord4 & p) {
213   float c= 1.0/SCREEN_PIXEL;
214   return QRect (p.x1*c, -p.x4*c,
215                 (p.x3-p.x1+SCREEN_PIXEL-1)*c, (p.x4-p.x2+SCREEN_PIXEL-1)*c);
216 }
217 
218 coord2
from_qsize(const QSize & s)219 from_qsize (const QSize & s) {
220   return coord2 (s.width() * SCREEN_PIXEL, s.height() * SCREEN_PIXEL);
221 }
222 
223 QSize
to_qsize(const coord2 & p)224 to_qsize (const coord2 & p) {
225   float c= 1.0/SCREEN_PIXEL;
226   return QSize (p.x1*c, p.x2*c);
227 }
228 
229 QSize
to_qsize(const SI & w,const SI & h)230 to_qsize (const SI& w, const SI& h) {
231   float c= 1.0/SCREEN_PIXEL;
232   return QSize (w*c, h*c);
233 }
234 
235 coord2
from_qpoint(const QPoint & pt)236 from_qpoint (const QPoint & pt) {
237   return coord2 (pt.x() * SCREEN_PIXEL, -pt.y() * SCREEN_PIXEL);
238 }
239 
240 /*! Transforms texmacs coordinates, with origin at the lower left corner, into
241  Qt coordinates, with origin at the upper left corner */
242 QPoint
to_qpoint(const coord2 & p)243 to_qpoint (const coord2 & p) {
244   float c= 1.0/SCREEN_PIXEL;
245   return QPoint (p.x1*c, -p.x2*c);
246 }
247 
248 array<string>
from_qstringlist(const QStringList & l)249 from_qstringlist(const QStringList& l) {
250   array<string> tl (l.size());
251   for(QStringList::const_iterator it = l.begin(); it != l.end(); ++it)
252     tl << from_qstring(*it);
253   return tl;
254 }
255 
256 QStringList
to_qstringlist(array<string> l)257 to_qstringlist (array<string> l) {
258   QStringList ql;
259   for(int i=0; i<N(l); ++i)
260     ql << to_qstring(l[i]);
261   return ql;
262 }
263 
264 /* HACK!!! Something has to be done wrt. to internal encoding: most of the times
265  it's cork, but often it's utf8. For instance when the title is built in a tmfs
266  title handler in scheme, it is sent to us as an utf8 string. Should we convert
267  before? Another example are items in the go-menu: file names are internally
268  stored as utf8, but we assume that strings are sent to us for display in
269  widgets as cork and thus display the wrong encoding.
270 
271  It gets tricky soon, so for the time being we use this hack.
272  */
273 QString
to_qstring(const string & s)274 to_qstring (const string& s) {
275   if (looks_utf8 (s) && !(looks_ascii (s) || looks_universal (s)))
276     return utf8_to_qstring (s);
277   else
278     return utf8_to_qstring (cork_to_utf8 (s));
279 }
280 
281 QString
latin1_to_qstring(const string & s)282 latin1_to_qstring (const string& s) {
283   c_string p (s);
284   QString nss= QString::fromLatin1 (p, N(s));
285   return nss;
286 }
287 
288 QString
utf8_to_qstring(const string & s)289 utf8_to_qstring (const string& s) {
290   c_string p (s);
291   QString nss= QString::fromUtf8 (p, N(s));
292   return nss;
293 }
294 
295 string
from_qstring_utf8(const QString & s)296 from_qstring_utf8 (const QString &s) {
297   QByteArray arr= s.toUtf8 ();
298   const char* cstr= arr.constData ();
299   return string ((char*) cstr);
300 }
301 
302 string
from_qstring(const QString & s)303 from_qstring (const QString &s) {
304   return utf8_to_cork (from_qstring_utf8 (s));
305 }
306 
307 // This should provide better lookup times
308 static QHash<QString, QColor> _NamedColors;
309 
310 /*!
311   Takes either an hexadecimal RGB color, as in #e3a1ff, or a named color
312   as those defined in src/Graphics/Renderer/ * _colors.hpp and returns a QColor
313  */
314 QColor
to_qcolor(const string & col)315 to_qcolor (const string& col) {
316   QString _col = to_qstring(col);
317   if (_NamedColors.contains (_col))
318     return _NamedColors[_col];
319   color c= named_color (col);
320   if (c == 0 && locase_all (col) != "black") {
321     if(DEBUG_QT_WIDGETS)
322       debug_widgets << "to_qcolor(" << col << "): "
323         << "name is not defined.\n";
324     return QColor(100,100,100);  // FIXME?
325   }
326   QColor _c= to_qcolor (c);
327   _NamedColors.insert(_col, _c);
328   return _c;
329 }
330 
331 /*! Returns a color encoded as a string with hexadecimal RGB values,
332  as in #e3a1ff
333  */
334 string
from_qcolor(const QColor & col)335 from_qcolor (const QColor& col) {
336   return from_qstring(col.name());
337 }
338 
339 QColor
to_qcolor(color c)340 to_qcolor(color c) {
341   int r, g, b, a;
342   get_rgb_color (c, r, g, b, a);
343   if (get_reverse_colors ()) reverse (r, g, b);
344   return QColor (r, g, b, a);
345 }
346 
347 color
to_color(const QColor & c)348 to_color (const QColor& c) {
349   int r, g, b, a;
350   c.getRgb (&r, &g, &b, &a);
351   if (get_reverse_colors ()) reverse (r, g, b);
352   return rgb_color (r, g, b, a);
353 }
354 
355 /******************************************************************************
356  * Image conversion
357  ******************************************************************************/
358 
359   //FIXME!?!?
360 bool
qt_supports(url u)361 qt_supports (url u) {
362   string s= suffix (u);
363   if (s == "ps" || s == "eps" || s == "pdf") return false;
364   return true;
365 }
366 
367 void
qt_image_size(url image,int & w,int & h)368 qt_image_size (url image, int& w, int& h) {
369     //cout <<  concretize (image) << LF;
370   QImage im= QImage (utf8_to_qstring (concretize (image)));
371   if (im.isNull ()) {
372     if (as_bool (call ("file-converter-exists?", image, "x.png"))) {
373       url temp= url_temp (".png");
374       call ("file-convert", object (image), object (temp));
375       qt_image_size (temp, w, h);
376       remove (temp);
377     }
378     else {
379       convert_error << "Cannot read image file '" << image << "'"
380       << " in qt_image_size" << LF;
381       w= 35; h= 35;
382     }
383   }
384   else {
385     w= im.width ();
386     h= im.height ();
387   }
388 }
389 
390 void
qt_convert_image(url image,url dest,int w,int h)391 qt_convert_image (url image, url dest, int w, int h) {
392   QImage im (utf8_to_qstring (concretize (image)));
393   if (im.isNull ())
394     convert_error << "Cannot read image file '" << image << "'"
395     << " in qt_convert_image" << LF;
396   else {
397     if (w > 0 && h > 0)
398       im= im.scaled (w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
399     im.scaled (w, h).save (utf8_to_qstring (concretize (dest)));
400   }
401 }
402 
403 void
qt_image_to_eps(url image,url eps,int w_pt,int h_pt,int dpi)404 qt_image_to_eps (url image, url eps, int w_pt, int h_pt, int dpi) {
405   string r= qt_image_to_eps (image, w_pt, h_pt, dpi);
406   save_string (eps, r);
407 }
408 
409 string
qt_image_to_eps(url image,int w_pt,int h_pt,int dpi)410 qt_image_to_eps (url image, int w_pt, int h_pt, int dpi) {
411   static const char* d= "0123456789ABCDEF";
412   QImage im (utf8_to_qstring (concretize (image)));
413   string r;
414   if (im.isNull ())
415     convert_error << "Cannot read image file '" << image << "'"
416     << " in qt_image_to_eps" << LF;
417   else {
418     bool alpha= im.hasAlphaChannel ();
419     if (dpi > 0 && w_pt > 0 && h_pt > 0) {
420       int ww= w_pt * dpi / 72;
421       int hh= h_pt * dpi / 72;
422       if (ww < im.width () || hh < im.height ()) {
423         im= im.scaled (ww, hh, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
424       }
425     }
426     string sw= as_string (im.width ());
427     string sh= as_string (im.height ());
428     r << "%!PS-Adobe-3.0 EPSF-3.0\n%%Creator: TeXmacs\n%%BoundingBox: 0 0 "
429     << sw << " " << sh
430     << "\n\n% Created by qt_image_to_eps ()\n\n%%BeginProlog\nsave\n"
431     << "countdictstack\nmark\nnewpath\n/showpage {} def\n/setpagedevice "
432     << "{pop} def\n%%EndProlog\n%%Page 1 1\n"
433     << "/max { 2 copy lt { exch } if pop } bind def\n"
434     << "/ImageWidth " << sw
435     << " def\n/ImageHeight " << sh << " def\nImageWidth ImageHeight max "
436     << "ImageWidth ImageHeight max scale\n\n/ImageDatas\n\tcurrentfile\n\t"
437     << "<< /Filter /ASCIIHexDecode >>\n\t/ReusableStreamDecode\n\tfilter\n";
438 
439     int v, i= 0, j= 0, k= 0, l= 0;
440     string mask;
441     for (j= 0; j < im.height (); j++) {
442       for (i=0; i < im.width (); i++) {
443         l++;
444         QRgb p= im.pixel (i, j);
445         v= qRed (p);
446         r << d [(v >> 4)] << d [v % 16];
447         v= qGreen (p);
448         r << d [(v >> 4)] << d [v % 16];
449         v= qBlue (p);
450         r << d [(v >> 4)] << d [v % 16];
451         if (l > 12) {
452           r << "\n";
453           l= 0;
454         }
455       }
456       if (alpha) {
457         v= 0;
458         for (i=0; i < im.width (); i++) {
459           v+= (qAlpha (im.pixel (i, j)) == 0) << (3 - i % 4);
460           if (i % 4 == 3 || i + 1 == im.width ()) {
461             mask << d[v];
462             v= 0;
463             k++;
464               // Padding of the image data mask
465             if (i + 1 == im.width () && k % 2 == 1) {
466               mask << d[0];
467               k++;
468             }
469               // Code layout
470             if (k >= 78) {
471               mask << "\n";
472               k= 0;
473             }
474           }
475         }
476       }
477     }
478     r << ">\ndef\n\n";
479 
480     if (alpha) {
481       r << "/MaskDatas\n\tcurrentfile\n\t<< /Filter /ASCIIHexDecode >>\n"
482       << "\t/ReusableStreamDecode\n\tfilter\n"
483       << mask
484       << ">\ndef\n\n"
485       << "/TheMask\n<<\n\t/ImageType\t1\n\t/Width\t\tImageWidth\n\t/Height\t"
486       << "\tImageHeight\n\t/BitsPerComponent 1\n\t/Decode [ 0 1 ]\n\t"
487       << "/ImageMatrix [ ImageWidth 0 0 ImageWidth neg 0 ImageHeight ]\n\t"
488       << "/DataSource MaskDatas\n>> def\n\n";
489     }
490     r << "/TheImage\n<<\n\t/ImageType\t1\n\t/Width\t\tImageWidth\n\t/Height\t"
491     << "\tImageHeight\n\t/BitsPerComponent 8\n\t/Decode [ 0 1 0 1 0 1 ]\n\t"
492     << "/ImageMatrix [ ImageWidth 0 0 ImageWidth neg 0 ImageHeight ]\n\t"
493     << "/DataSource ImageDatas\n>> def\n\n"
494     << "/DeviceRGB setcolorspace\n";
495     if (alpha) {
496       r << "<<\n\t/ImageType 3\n\t/InterleaveType 3\n\t/DataDict TheImage\n"
497       << "\t/MaskDict TheMask\n>>";
498     }
499     else {
500       r << "\tTheImage";
501     }
502     r << "\nimage\nshowpage\n%%Trailer\ncleartomark\ncountdictstack\n"
503     << "exch sub { end } repeat\nrestore\n%%EOF\n";
504   }
505   return r;
506 }
507 
508 
509 void
qt_image_data(url image,int & w,int & h,string & data,string & palette,string & mask)510 qt_image_data (url image, int& w, int&h, string& data, string& palette, string& mask) {
511   (void) palette;
512   QImage im (utf8_to_qstring (concretize (image)));
513 
514 
515 
516   if (im.isNull ())
517     convert_error << "Cannot read image file '" << image << "'"
518     << " in qt_image_data" << LF;
519   else {
520     bool alpha= im.hasAlphaChannel ();
521     w=  im.width ();
522     h=  im.height ();
523 
524     data = string ((w*h)*3);
525 
526     int v, i= 0, j= 0, k= 0, l= 0;
527 
528     for (j= 0; j < im.height (); j++) {
529       for (i=0; i < im.width (); i++) {
530         QRgb p= im.pixel (i, j);
531         data[l++] = qRed (p);
532         data[l++] = qGreen (p);
533         data[l++] = qBlue (p);
534       }
535     }
536 
537     if (alpha) {
538       mask = string ((w*h+7)/8);
539 
540 
541       v= 0;
542       for (i=0; i < im.width (); i++) {
543         v+= (qAlpha (im.pixel (i, j)) == 0) << (3 - i % 4);
544         if (i % 8 == 7 || i + 1 == im.width ()) {
545           mask[k++] = v;
546           v= 0;
547             // Padding of the image data mask
548           if (i + 1 == im.width () && k % 2 == 1) {
549             mask[k++] = 0;
550           }
551         }
552       }
553     }
554 
555   }
556 }
557 
558 QPixmap
as_pixmap(const QImage & im)559 as_pixmap (const QImage& im) {
560   QPixmap pm (im.size ());
561 #if (QT_VERSION >= 0x040700)
562   pm.convertFromImage (im);
563 #else
564   pm.fromImage (im);
565 #endif
566   return pm;
567 }
568 
569 
570 /******************************************************************************
571  * Stuff related to widgets
572  ******************************************************************************/
573 
574 QString
parse_tm_style(int style)575 parse_tm_style (int style) {
576   QString sheet;
577   if (style & WIDGET_STYLE_MINI) {  // Use smaller text font
578     int fs = as_int (get_preference ("gui:mini-fontsize", QTM_MINI_FONTSIZE));
579     sheet += QString("font-size: %1pt;").arg (fs > 0 ? fs : QTM_MINI_FONTSIZE);
580     sheet += QString("padding: 1px;");
581   }
582   if (style & WIDGET_STYLE_MONOSPACED)  // Use monospaced font
583     sheet += "font-family: \"monospace\";";
584   if (style & WIDGET_STYLE_GREY)      // Use grey text font
585     sheet += "color: #414141;";
586   if (style & WIDGET_STYLE_PRESSED)   // Button is currently pressed
587     sheet += "";
588   if (style & WIDGET_STYLE_INERT)     // Only render, don't associate any action
589     sheet += "color: #414141;";
590   if (style & WIDGET_STYLE_BUTTON)    // Render button as standard button
591     sheet += "";
592   if (style & WIDGET_STYLE_CENTERED)  // Use centered text
593     sheet += "text-align: center;";
594   if (style & WIDGET_STYLE_BOLD)
595     sheet += "font-weight: bold;";
596   if (DEBUG_QT_WIDGETS)
597     sheet += "border:1px solid rgb(255, 0, 0);";
598   return sheet;
599 }
600 
601 void
qt_apply_tm_style(QWidget * qwid,int style)602 qt_apply_tm_style (QWidget* qwid, int style) {
603   QString sheet = "* {" + parse_tm_style (style) + "}";
604   qwid->setStyleSheet (sheet);
605   qwid->setEnabled (! (style & WIDGET_STYLE_INERT));
606 }
607 
608 void
qt_apply_tm_style(QWidget * qwid,int style,color c)609 qt_apply_tm_style (QWidget* qwid, int style, color c) {
610   int r,g,b,a;
611   get_rgb_color (c, r, g, b, a);
612   a = a*100/255;
613   QString sheet = "* {" + parse_tm_style (style)
614   + QString("color: rgba(%1, %2, %3, %4%);").arg(r).arg(g).arg(b).arg(a)
615   + "} ";
616 
617 #ifdef Q_WS_MAC
618     /* Disabled QLabels are not greyed out (at least in MacOS, since Qt 4.7.2),
619      see: https://bugreports.qt-project.org/browse/QTBUG-19008
620      For consistency we set the disabled color for all widgets.
621      */
622   sheet += " :disabled { color: #7F7F7F; }";
623 #endif
624   qwid->setEnabled (! (style & WIDGET_STYLE_INERT));
625   qwid->setStyleSheet (sheet);
626 }
627 
628 
629 QString
qt_translate(const string & s)630 qt_translate (const string& s) {
631   string in_lan= get_input_language ();
632   string out_lan= get_output_language ();
633   return to_qstring(tm_var_encode (translate (s, in_lan, out_lan)));
634 }
635 
636 string
qt_application_directory()637 qt_application_directory () {
638   return string (QCoreApplication::applicationDirPath().toAscii().constData());
639   // return from_qstring (QCoreApplication::applicationDirPath ());
640 }
641 
642 string
qt_get_date(string lan,string fm)643 qt_get_date (string lan, string fm) {
644   QDateTime localtime = QDateTime::currentDateTime();
645   if (fm == "") {
646     if ((lan == "british") || (lan == "english") || (lan == "american"))
647       fm = "MMMM d, yyyy";
648     else if (lan == "german")
649       fm = "d. MMMM yyyy";
650     else if (lan == "chinese" || lan == "japanese" ||
651              lan == "korean" || lan == "taiwanese")
652     {
653       string y = as_string(localtime.date().year());
654       string m = as_string(localtime.date().month());
655       string d = as_string(localtime.date().day());
656       if (lan == "japanese")
657         return y * "<#5e74>" * m * "<#6708>" * d * "<#65e5>";
658       if (lan == "korean")
659         return y * "<#b144> " * m * "<#c6d4> " * d * "<#c77c>";
660       return y * "," * m * "," * d;
661     }
662     else fm = "d MMMM yyyy";
663   }
664   else if (fm[0] == '%') {
665     char buf[64];
666     time_t ti;
667     time (&ti);
668     strftime (buf, sizeof(buf), as_charp(fm), ::localtime(&ti));
669     return buf;
670   }
671   QLocale loc = QLocale (to_qstring (language_to_locale(lan)));
672 #if (QT_VERSION >= 0x040400)
673   QString date = loc.toString (localtime, to_qstring (fm));
674 #else
675   QString date = localtime.toString (to_qstring (fm));
676 #endif
677   return from_qstring (date);
678 }
679 
680 string
qt_pretty_time(int t)681 qt_pretty_time (int t) {
682   QDateTime dt= QDateTime::fromTime_t (t);
683   QString s= dt.toString ();
684   return from_qstring (s);
685 }
686 
687 #ifndef _MBD_EXPERIMENTAL_PRINTER_WIDGET  // this is in qt_printer_widget
688 
689 #define PAPER(fmt)  case QPrinter::fmt : return "fmt"
690 static string
qt_papersize_to_string(QPrinter::PaperSize sz)691 qt_papersize_to_string (QPrinter::PaperSize sz) {
692   switch (sz) {
693       PAPER (A0) ;
694       PAPER (A1) ;
695       PAPER (A2) ;
696       PAPER (A3) ;
697       PAPER (A4) ;
698       PAPER (A5) ;
699       PAPER (A6) ;
700       PAPER (A7) ;
701       PAPER (A8) ;
702       PAPER (A9) ;
703       PAPER (B0) ;
704       PAPER (B1) ;
705       PAPER (B2) ;
706       PAPER (B3) ;
707       PAPER (B4) ;
708       PAPER (B5) ;
709       PAPER (B6) ;
710       PAPER (B7) ;
711       PAPER (B8) ;
712       PAPER (B9) ;
713       PAPER (B10) ;
714       PAPER (Letter) ;
715     default:
716       return "A4";
717   }
718 }
719 #undef PAPER
720 
721 bool
qt_print(bool & to_file,bool & landscape,string & pname,url & filename,string & first,string & last,string & paper_type)722 qt_print (bool& to_file, bool& landscape, string& pname, url& filename,
723           string& first, string& last, string& paper_type) {
724   static QPrinter *qprinter = NULL;
725   if (!qprinter) {
726     qprinter = new QPrinter;
727   }
728   QPrintDialog pdialog(qprinter);
729   if (pdialog.exec() == QDialog::Accepted) {
730     to_file = !(qprinter->outputFileName().isNull());
731     pname = from_qstring( qprinter->printerName() );
732     filename = from_qstring( qprinter->outputFileName() );
733     landscape = (qprinter->orientation() == QPrinter::Landscape);
734     paper_type = qt_papersize_to_string(qprinter->paperSize());
735     if (qprinter->printRange() == QPrinter::PageRange) {
736       first = qprinter->fromPage();
737       last = qprinter->toPage();
738     }
739     //cout << "Printer :" << pname << LF;
740     //cout << "File :" << filename << LF;
741     return true;
742   }
743   return false;
744 }
745 
746 #endif //(not defined) _MBD_EXPERIMENTAL_PRINTER_WIDGET
747