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