makedist.sh: Rename project
[nomnom.git] / src / util.cpp
blobe2d66104ea489a4749b77629bde40d367990e599
1 /*
2 * Copyright (C) 2010 Toni Gundogdu.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "config.h"
20 #include <QApplication>
21 #include <QTranslator>
22 #include <QMessageBox>
23 #include <QProcess>
24 #include <QWidget>
25 #include <QString>
26 #include <QPoint>
27 #include <QDebug>
28 #include <QSize>
29 #include <QDir>
31 #include "Log.h"
32 #include "util.h"
34 // main.cpp
35 extern QMap<QString,QStringList> hosts;
36 extern QMap<QString,QString> qmFiles;
37 extern QStringList qmLangNames;
38 extern NomNom::FeedHash feed;
39 extern Log log;
41 namespace NomNom {
43 void
44 restore_size (
45 QSettings& s,
46 QWidget *w,
47 const QString& g,
48 const QSize& defaultSize/*=(400,350)*/)
50 w->resize (s.value (QString ("%1/size").arg (g), defaultSize).toSize ());
53 void
54 restore_pos (
55 QSettings& s,
56 QWidget *w,
57 const QString& g,
58 const QPoint& defaultPos/*=(200,200)*/)
60 w->move (s.value (QString ("%1/pos").arg (g), defaultPos).toPoint ());
63 void
64 save_size (QSettings& s, QWidget *w, const QString& g)
65 { s.setValue (QString ("%1/size").arg (g), w->size ()); }
67 void
68 save_pos (QSettings& s, QWidget *w, const QString& g)
69 { s.setValue (QString ("%1/pos").arg (g), w->pos ()); }
71 void
72 info (QWidget *p, const QString& m) {
73 p->show (); // Make sure window is not hidden (e.g. minimized to tray).
74 p->showNormal ();
75 QMessageBox::information (p, QCoreApplication::applicationName(), m);
78 void
79 crit (QWidget *p, const QString& m) {
80 p->show (); // See `info' function above.
81 p->showNormal ();
82 QMessageBox::critical (p, QCoreApplication::applicationName (), m);
85 QMessageBox::StandardButton
86 ask (QWidget *p, const QString& m, QMessageBox::StandardButtons b/*=Yes|No*/) {
87 p->show (); // See `info' function above.
88 p->showNormal ();
89 return QMessageBox::question(p, QCoreApplication::applicationName(), m, b);
92 static QFileInfoList
93 scan_dir (const QString path, const bool show_paths) {
95 const QDir dir (QDir::toNativeSeparators (path));
97 if (show_paths)
98 qDebug () << dir.absolutePath ();
100 return dir.entryInfoList (QStringList( "*.qm"), QDir::Files);
103 QMap<QString,QString>
104 find_qm (QStringList& langNames) {
106 QSettings s;
108 bool show_paths = false;
110 const QString qmShowPaths = "qmShowPaths";
111 if (s.contains (qmShowPaths))
112 show_paths = s.value (qmShowPaths).toBool ();
114 if (show_paths)
115 qDebug () << "qm search paths:";
117 QStringList paths;
119 const QString qmPath = "qmPath";
120 if (s.contains (qmPath))
121 paths << s.value (qmPath).toString ();
123 paths
124 << QDir::currentPath () + "/tr"
125 << QDir::homePath () + "/.config/nomnom/tr"
126 << QDir::homePath () + "/.local/share/nomnom/tr"
127 #ifdef INSTALL_PREFIX
128 << QString (INSTALL_PREFIX) + "/share/nomnom/tr"
129 #endif
132 QFileInfoList lst;
134 foreach (QString p, paths)
135 lst << scan_dir (p, show_paths);
137 QMap<QString,QString> map;
138 QTranslator t;
140 foreach (QFileInfo fi, lst) {
142 t.load (fi.filePath ());
144 const QString langName = t.translate ("MainWindow", "English");
146 if (map.contains (langName)) { // Skip duplicates.
147 if (map[langName] == fi.filePath ())
148 continue;
151 map[langName] = fi.filePath ();
153 langNames << langName;
156 return map;
159 bool
160 choose_lang (QWidget *p, QString& langName) {
162 bool showPaths = false;
163 QStringList langNamesWithPaths;
165 const QString key = "qmShowPaths";
166 QSettings s;
168 if (s.contains (key)) {
170 showPaths = s.value (key).toBool ();
172 if (showPaths) {
174 langNamesWithPaths << "English [default, built-in]";
176 QMapIterator<QString,QString> iter (qmFiles);
178 while (iter.hasNext ()) {
180 iter.next ();
182 langNamesWithPaths << QString ("%1 [%2]")
183 .arg (iter.key ())
184 .arg (iter.value ());
190 bool ok = false;
192 langName = QInputDialog::getItem (
194 QObject::tr ("Select language"),
195 QObject::tr ("Language:"),
196 showPaths ? langNamesWithPaths : qmLangNames,
198 false,
202 langName = langName.split ("[")[0].simplified ();
204 return ok;
207 QTranslator*
208 load_qm () {
210 QString langName;
212 QSettings s;
213 if (s.contains("language")) {
214 const QString v = s.value("language").toString();
216 if (v == "English")
217 return NULL;
219 if (qmFiles.contains(v))
220 langName = v;
223 if (langName.isEmpty()) {
224 if (!choose_lang(NULL, langName))
225 return NULL;
228 s.setValue("language", langName);
230 QTranslator *t = new QTranslator;
231 t->load(qmFiles[langName]);
233 return t;
236 bool
237 parse_quvi_version (const QString& path, QString& output) {
239 output.clear ();
241 // Use command path (arg0) and "--version" only.
243 QStringList args =
244 QStringList () << path.split (" ").takeFirst () << "--version";
246 log << args.join (" ");
248 const QString cmdPath = args.takeFirst ();
250 QProcess proc;
251 proc.setProcessChannelMode (QProcess::MergedChannels);
252 proc.start (cmdPath, args);
254 if (!proc.waitForFinished ()) {
256 output =
257 QObject::tr ("error: %1: %2")
258 .arg (cmdPath)
259 .arg (proc.errorString ());
261 return false;
264 output = QString::fromLocal8Bit (proc.readAll ()).simplified ();
266 return true;
269 bool
270 parse_quvi_support (const QString& path, QString& errmsg) {
272 errmsg.clear ();
274 // Use command path (arg0) and "--support" only.
276 QStringList args =
277 QStringList () << path.split (" ").takeFirst () << "--support";
279 log << args.join (" ");
281 const QString cmdPath = args.takeFirst ();
283 QProcess proc;
284 proc.setProcessChannelMode(QProcess::MergedChannels);
285 proc.start(cmdPath, args);
287 if (!proc.waitForFinished()) {
289 errmsg =
290 QObject::tr("error: %1: %2")
291 .arg(cmdPath)
292 .arg(proc.errorString ());
294 return false;
297 const QRegExp re("(.*)\\s+(.*)$");
299 const QString output =
300 QString::fromLocal8Bit(proc.readAll());
302 foreach (QString ln, output.split("\n")) {
304 if (ln.isEmpty())
305 continue;
307 log << ln;
309 if (re.indexIn(ln) != -1) {
311 const QString host = re.cap (1).simplified ();
312 QStringList formats = re.cap (2).simplified ().split ("|");
314 // Keep "default" at the beginning of the list.
316 const QString top = formats.takeFirst ();
317 formats.sort ();
318 formats.prepend (top);
320 hosts[host] = formats;
324 return true;
327 static bool
328 filter_title (
329 QWidget *p,
330 const QString& user_regexp,
331 const QString& title,
332 QString& dst)
334 QString pattern;
336 bool g = false;
337 bool i = false;
339 QRegExp rx("^\\/(.*)\\/(.*)$");
341 if (rx.indexIn (user_regexp) != -1) {
342 pattern = rx.cap (1);
343 g = rx.cap (2).contains ("g");
344 i = rx.cap (2).contains ("i");
346 else {
347 NomNom::crit (p,
348 QObject::tr ("Expected Perl-style regular expression, e.g. /pattern/flags"));
349 return false;
352 rx.setPattern (pattern);
354 rx.setCaseSensitivity (
356 ? Qt::CaseInsensitive
357 : Qt::CaseSensitive
360 int pos = 0;
362 while ( (pos = rx.indexIn (title, pos)) != -1) {
363 dst += rx.cap (1);
364 pos += rx.matchedLength ();
365 if (!g) break;
368 dst = dst.simplified ();
370 return true;
373 bool
374 format_filename (
375 QWidget *p,
376 const QString& user_regexp,
377 const QString& title,
378 const QString& suffix,
379 const QString& host,
380 const QString& id,
381 QString& dst)
383 // Assumes dst to contain the "filename format".
385 QString filtered_title;
387 const bool ok = filter_title (
389 user_regexp,
390 title,
391 filtered_title
394 if (!ok)
395 return ok;
397 dst.replace ("%t", filtered_title);
398 dst.replace ("%s", suffix);
399 dst.replace ("%h", host);
400 dst.replace ("%i", id);
402 dst = dst.simplified ();
404 return true;
407 QString
408 to_process_errmsg (QProcess::ProcessError n) {
410 QString e;
412 switch (n) {
414 case QProcess::FailedToStart:
415 e = QObject::tr (
416 "The process failed to start. "
417 "Either the invoked program is missing, or you may have "
418 "insufficient permissions to invoke the program."
420 break;
422 case QProcess::Crashed:
423 e = QObject::tr (
424 "The process crashed some time after starting successfully."
426 break;
428 case QProcess::Timedout:
429 e = QObject::tr (
430 "The last waitFor...() function timed out. "
431 "The state of QProcess is unchanged, and you can try calling "
432 "waitFor...() again."
434 break;
436 case QProcess::WriteError:
437 e = QObject::tr (
438 "An error occurred when attempting to write to the process. "
439 "For example, the process may not be running, or it may have closed "
440 "its input channel."
442 break;
444 case QProcess::ReadError:
445 e = QObject::tr (
446 "An error occurred when attempting to read from the process. "
447 "For example, the process may not be running."
449 break;
451 case QProcess::UnknownError:
452 default:
453 e = QObject::tr (
454 "An unknown error occurred. This is the default return value "
455 "of error()."
457 break;
461 return e;
464 bool
465 choose_from_feed (QWidget *parent, QString& dst) {
467 if (feed.isEmpty ())
468 return false;
470 QHashIterator<QString,QString> i (feed);
471 QStringList items;
473 while (i.hasNext ()) {
474 i.next ();
475 items << i.key ();
478 bool ok = false;
480 QString title = QInputDialog::getItem (
481 parent,
482 QObject::tr ("Choose video"),
483 QObject::tr ("Video"),
484 items,
486 false,
490 if (ok)
491 dst = feed[title];
493 return ok;
496 } // End of namespace.