MythTV  master
galleryutil.cpp
Go to the documentation of this file.
1 /* ============================================================
2  * File : exifutil.cpp
3  * Description :
4  *
5 
6  * This program is free software; you can redistribute it
7  * and/or modify it under the terms of the GNU General
8  * Public License as published bythe Free Software Foundation;
9  * either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * ============================================================ */
18 
19 // C++
20 #include <cmath>
21 
22 // qt
23 #include <QDir>
24 #include <QApplication>
25 #include <QImageReader>
26 
27 // myth
28 #include <mythcontext.h>
29 #include <mythdbcon.h>
30 #include <mythdate.h>
31 #include <mythdirs.h>
32 #include <mythdb.h>
33 #include <mythuihelper.h>
34 #include <mythmainwindow.h>
35 
36 // mythgallery
37 #include "config.h"
38 #include "galleryutil.h"
39 #include "thumbgenerator.h"
40 
41 #ifdef DCRAW_SUPPORT
42 #include "../dcrawplugin/dcrawformats.h"
43 #endif // DCRAW_SUPPORT
44 
45 #ifdef EXIF_SUPPORT
46 #include <libexif/exif-data.h>
47 #include <libexif/exif-entry.h>
48 #endif // EXIF_SUPPORT
49 
50 #define LOC QString("GalleryUtil:")
51 
52 static QFileInfo MakeUnique(const QFileInfo &dest);
53 static QFileInfo MakeUniqueDirectory(const QFileInfo &dest);
54 static bool FileCopy(const QFileInfo &src, const QFileInfo &dst);
55 static bool FileMove(const QFileInfo &src, const QFileInfo &dst);
56 static bool FileDelete(const QFileInfo &file);
57 
58 QStringList GalleryUtil::GetImageFilter(void)
59 {
60  QStringList filt;
61 
62  Q_FOREACH(QByteArray format, QImageReader::supportedImageFormats())
63  filt.push_back("*." + format);
64 
65  filt.push_back("*.tif");
66 
67 #ifdef DCRAW_SUPPORT
68  filt << DcrawFormats::getFilters();
69 #endif // DCRAW_SUPPORT
70 
71  return filt;
72 }
73 
74 QStringList GalleryUtil::GetMovieFilter(void)
75 {
76  QStringList filt;
77  filt.push_back("*.avi");
78  filt.push_back("*.bin");
79  filt.push_back("*.iso");
80  filt.push_back("*.img");
81  filt.push_back("*.mpg");
82  filt.push_back("*.mp4");
83  filt.push_back("*.m4v");
84  filt.push_back("*.mpeg");
85  filt.push_back("*.mov");
86  filt.push_back("*.mts");
87  filt.push_back("*.wmv");
88  filt.push_back("*.3gp");
89  filt.push_back("*.wmv");
90  filt.push_back("*.flv");
91  filt.push_back("*.mkv");
92  return filt;
93 }
94 
95 QStringList GalleryUtil::GetMediaFilter(void)
96 {
97  QStringList filt = GetImageFilter();
98  filt << GetMovieFilter();
99  return filt;
100 }
101 
102 bool GalleryUtil::IsImage(const QString &filePath)
103 {
104  QFileInfo fi(filePath);
105  if (fi.isDir())
106  return false;
107 
108  QStringList filt = GetImageFilter();
109  QStringList::const_iterator it = filt.begin();
110  for (; it != filt.end(); ++it)
111  {
112  if ((*it).contains(fi.suffix().toLower()))
113  return true;
114  }
115 
116  return false;
117 }
118 
119 bool GalleryUtil::IsMovie(const QString &filePath)
120 {
121  QFileInfo fi(filePath);
122  if (fi.isDir())
123  return false;
124 
125  QStringList filt = GetMovieFilter();
126  QStringList::const_iterator it = filt.begin();
127  for (; it != filt.end(); ++it)
128  {
129  if ((*it).contains(fi.suffix().toLower()))
130  return true;
131  }
132 
133  return false;
134 }
135 
136 long GalleryUtil::GetNaturalRotation(const unsigned char *buffer, int size)
137 {
138  long rotateAngle = 0;
139 
140 #ifdef EXIF_SUPPORT
141  try
142  {
143  ExifData *data = exif_data_new_from_data(buffer, size);
144  if (data)
145  {
146  rotateAngle = GetNaturalRotation(data);
147  exif_data_free(data);
148  }
149  else
150  {
151  LOG(VB_FILE, LOG_ERR, LOC + "Could not load exif data from buffer");
152  }
153  }
154  catch (...)
155  {
156  LOG(VB_GENERAL, LOG_ERR, LOC +
157  "Failed to extract EXIF headers from buffer");
158  }
159 #else
160  // Shut the compiler up about the unused argument
161  (void)buffer;
162  (void)size;
163 #endif
164 
165  return rotateAngle;
166 }
167 
168 long GalleryUtil::GetNaturalRotation(const QString &filePathString)
169 {
170  long rotateAngle = 0;
171 
172 #ifdef EXIF_SUPPORT
173  QByteArray filePathBA = filePathString.toLocal8Bit();
174  const char *filePath = filePathBA.constData();
175 
176  try
177  {
178  ExifData *data = exif_data_new_from_file(filePath);
179  if (data)
180  {
181  rotateAngle = GetNaturalRotation(data);
182  exif_data_free(data);
183  }
184  else
185  {
186  LOG(VB_FILE, LOG_ERR, LOC +
187  QString("Could not load exif data from '%1'") .arg(filePath));
188  }
189  }
190  catch (...)
191  {
192  LOG(VB_GENERAL, LOG_ERR, LOC +
193  QString("Failed to extract EXIF headers from '%1'") .arg(filePath));
194  }
195 #else
196  // Shut the compiler up about the unused argument
197  (void)filePathString;
198 #endif
199 
200  return rotateAngle;
201 }
202 
204 {
205  long rotateAngle = 0;
206 
207 #ifdef EXIF_SUPPORT
208  // Qt 5.4.1 automatically orientates images according to their EXIF data
209  if (strcmp(qVersion(), "5.4.1") == 0)
210  return 0;
211 
212  ExifData *data = (ExifData *)exifData;
213 
214  if (!data)
215  return 0;
216 
217  for (int i = 0; i < EXIF_IFD_COUNT; i++)
218  {
219  ExifEntry *entry = exif_content_get_entry(data->ifd[i],
221  ExifByteOrder byteorder = exif_data_get_byte_order(data);
222 
223  if (entry)
224  {
225  ExifShort v_short = exif_get_short(entry->data, byteorder);
226  LOG(VB_GENERAL, LOG_DEBUG,
227  QString("Exif entry=%1").arg(v_short));
228 
229  /* See http://sylvana.net/jpegcrop/exif_orientation.html*/
230  switch (v_short)
231  {
232  case 3:
233  rotateAngle = 180;
234  break;
235  case 6:
236  rotateAngle = 90;
237  break;
238  case 8:
239  rotateAngle = -90;
240  break;
241  default:
242  rotateAngle = 0;
243  break;
244  }
245  break;
246  }
247  }
248 #else
249  // Shut the compiler up about the unused argument
250  (void)exifData;
251 #endif // EXIF_SUPPORT
252 
253  return rotateAngle;
254 }
255 
256 bool GalleryUtil::LoadDirectory(ThumbList& itemList, const QString& dir,
257  const GalleryFilter& flt, bool recurse,
258  ThumbHash *itemHash, ThumbGenerator* thumbGen)
259 {
260  const QString& blah = dir;
261  QDir d(blah);
262  QString currDir = d.absolutePath();
263  QStringList splitFD;
264 
265  bool isGallery;
266  QFileInfoList gList = d.entryInfoList(QStringList("serial*.dat"),
267  QDir::Files);
268  isGallery = (gList.count() != 0);
269 
270  // Create .thumbcache dir if neccesary
271  if (thumbGen)
273 
274  QFileInfoList list = d.entryInfoList(GetMediaFilter(),
275  QDir::Files | QDir::AllDirs |
276  QDir::NoDotAndDotDot,
277  (QDir::SortFlag)flt.getSort());
278 
279  if (list.isEmpty())
280  return false;
281 
282  QFileInfoList::const_iterator it = list.begin();
283 
284  if (thumbGen)
285  {
286  thumbGen->cancel();
287  thumbGen->setDirectory(currDir, isGallery);
288  }
289 
290  if (!flt.getDirFilter().isEmpty())
291  {
292  splitFD = flt.getDirFilter().split(":");
293  }
294 
295  while (it != list.end())
296  {
297  const QFileInfo *fi = &(*it);
298  ++it;
299 
300  // remove these already-resized pictures.
301  if (isGallery && (
302  (fi->fileName().indexOf(".thumb.") > 0) ||
303  (fi->fileName().indexOf(".sized.") > 0) ||
304  (fi->fileName().indexOf(".highlight.") > 0)))
305  continue;
306 
307  // skip filtered directory
308  if (fi->isDir() &&
309  !splitFD.filter(fi->fileName(), Qt::CaseInsensitive).isEmpty())
310  continue;
311 
312  if (fi->isDir() && recurse)
313  {
314  LoadDirectory(itemList, QDir::cleanPath(fi->absoluteFilePath()),
315  flt, true, itemHash, thumbGen);
316  }
317  else
318  {
319  if ((GalleryUtil::IsImage(fi->absoluteFilePath()) &&
321  (GalleryUtil::IsMovie(fi->absoluteFilePath()) &&
323  continue;
324 
325  ThumbItem *item = new ThumbItem(fi->fileName(),
326  QDir::cleanPath(fi->absoluteFilePath()), fi->isDir());
327 
328  itemList.append(item);
329 
330  if (itemHash)
331  itemHash->insert(item->GetName(), item);
332 
333  if (thumbGen)
334  thumbGen->addFile(item->GetName());
335  }
336  }
337 
338  return isGallery;
339 }
340 
341 QString GalleryUtil::GetCaption(const QString &filePath)
342 {
343  QString caption("");
344 
345  try
346  {
347 #ifdef EXIF_SUPPORT
348 #if NEW_LIB_EXIF
349  char *exifvalue = new char[1024];
350 #endif
351  ExifData *data = exif_data_new_from_file(
352  filePath.toLocal8Bit().constData());
353  if (data)
354  {
355  for (int i = 0; i < EXIF_IFD_COUNT; i++)
356  {
357  ExifEntry *entry = exif_content_get_entry (data->ifd[i],
358  EXIF_TAG_USER_COMMENT);
359  if (entry)
360  {
361 #if NEW_LIB_EXIF
362  exif_entry_get_value(entry, exifvalue, 1024);
363  caption = exifvalue;
364 #else
365  caption = exif_entry_get_value(entry);
366 #endif
367  // Found one, done
368  if(!caption.trimmed().isEmpty())
369  break;
370  }
371 
372  entry = exif_content_get_entry (data->ifd[i],
373  EXIF_TAG_IMAGE_DESCRIPTION);
374  if (entry)
375  {
376 #if NEW_LIB_EXIF
377  exif_entry_get_value(entry, exifvalue, 1024);
378  caption = exifvalue;
379 #else
380  caption = exif_entry_get_value(entry);
381 #endif
382  // Found one, done
383  if(!caption.trimmed().isEmpty())
384  break;
385  }
386  }
387  exif_data_free(data);
388  }
389  else
390  {
391  LOG(VB_FILE, LOG_ERR, LOC +
392  QString("Could not load exif data from '%1'") .arg(filePath));
393  }
394 #if NEW_LIB_EXIF
395  delete [] exifvalue;
396 #endif
397 #endif // EXIF_SUPPORT
398  }
399  catch (...)
400  {
401  LOG(VB_GENERAL, LOG_ERR, LOC +
402  QString("Failed to extract EXIF headers from '%1'") .arg(filePath));
403  }
404 
405  return caption;
406 }
407 
408 QDateTime GalleryUtil::GetTimestamp(const QString &filePath)
409 {
410  QDateTime timestamp;
411 
412  try
413  {
414 #ifdef EXIF_SUPPORT
415 #if NEW_LIB_EXIF
416  char *exifvalue = new char[20];
417 #endif
418  ExifData *data = exif_data_new_from_file(
419  filePath.toLocal8Bit().constData());
420  if (data)
421  {
422  for (int i = 0; i < EXIF_IFD_COUNT; i++)
423  {
424  ExifEntry *entry = exif_content_get_entry (data->ifd[i],
425  EXIF_TAG_DATE_TIME_ORIGINAL);
426  if (entry)
427  {
428 #if NEW_LIB_EXIF
429  exif_entry_get_value(entry, exifvalue, 20);
430  QString formatted = exifvalue;
431 #else
432  QString formatted = exif_entry_get_value(entry);
433 #endif
434  timestamp = QDateTime::fromString(formatted,
435  "yyyy:MM:dd hh:mm:ss");
436  if (timestamp.isValid())
437  {
438  // Found one, done
439  break;
440  }
441  LOG(VB_FILE, LOG_ERR, LOC +
442  QString("Could not parse exif timestamp from '%1'")
443  .arg(filePath));
444  }
445  }
446  exif_data_free(data);
447  }
448  else
449  {
450  LOG(VB_FILE, LOG_ERR, LOC +
451  QString("Could not load exif data from '%1'") .arg(filePath));
452  }
453 #if NEW_LIB_EXIF
454  delete [] exifvalue;
455 #endif
456 #endif // EXIF_SUPPORT
457  }
458  catch (...)
459  {
460  LOG(VB_GENERAL, LOG_ERR, LOC +
461  QString("Failed to extract EXIF headers from '%1'") .arg(filePath));
462  }
463 
464  return timestamp;
465 }
466 
467 bool GalleryUtil::Copy(const QFileInfo &src, QFileInfo &dst)
468 {
469  if (src.isDir())
470  return CopyDirectory(src, dst);
471 
472  dst = MakeUnique(dst);
473 
474  if (!FileCopy(src, dst))
475  return false;
476 
477  MSqlQuery query(MSqlQuery::InitCon());
478  query.prepare("INSERT INTO gallerymetadata (image, angle) "
479  "SELECT :IMAGENEW , angle "
480  "FROM gallerymetadata "
481  "WHERE image = :IMAGEOLD");
482  query.bindValue(":IMAGENEW", dst.absoluteFilePath());
483  query.bindValue(":IMAGEOLD", src.absoluteFilePath());
484  if (query.exec())
485  return true;
486 
487  // try to undo copy on DB failure
488  FileDelete(dst);
489  return false;
490 }
491 
492 bool GalleryUtil::Move(const QFileInfo &src, QFileInfo &dst)
493 {
494  if (src.isDir())
495  return MoveDirectory(src, dst);
496 
497  dst = MakeUnique(dst);
498 
499  if (!FileMove(src, dst))
500  return false;
501 
502  MSqlQuery query(MSqlQuery::InitCon());
503  query.prepare("UPDATE gallerymetadata "
504  "SET image = :IMAGENEW "
505  "WHERE image = :IMAGEOLD");
506  query.bindValue(":IMAGENEW", dst.absoluteFilePath());
507  query.bindValue(":IMAGEOLD", src.absoluteFilePath());
508  if (query.exec())
509  return true;
510 
511  // try to undo move on DB failure
512  FileMove(dst, src);
513  return false;
514 }
515 
516 bool GalleryUtil::Delete(const QFileInfo &file)
517 {
518  if (!file.exists())
519  return false;
520 
521  if (file.isDir())
522  return DeleteDirectory(file);
523 
524  MSqlQuery query(MSqlQuery::InitCon());
525  query.prepare("DELETE FROM gallerymetadata "
526  "WHERE image = :IMAGE ;");
527  query.bindValue(":IMAGE", file.absoluteFilePath());
528  if (query.exec())
529  return FileDelete(file);
530 
531  return false;
532 }
533 
534 bool GalleryUtil::Rename(const QString &currDir, const QString &oldName,
535  const QString &newName)
536 {
537  // make sure there isn't already a file/directory with the same name
538  QFileInfo fi(currDir + '/' + newName);
539  if (fi.exists())
540  return false;
541 
542  fi.setFile(currDir + '/' + oldName);
543  if (fi.isDir())
544  return RenameDirectory(currDir, oldName, newName);
545 
546  // rename the file
547  QDir cdir(currDir);
548  if (!cdir.rename(oldName, newName))
549  return false;
550 
551  // rename the file's thumbnail if it exists
552  if (QFile::exists(currDir + "/.thumbcache/" + oldName))
553  {
554  QDir d(currDir + "/cache/gallery-thumbcache/");
555  d.rename(oldName, newName);
556  }
557 
558  int prefixLen = gCoreContext->GetSetting("GalleryDir").length();
559  QString path = GetConfDir() + "/MythGallery";
560  path += currDir.right(currDir.length() - prefixLen);
561  path += QString("/.thumbcache/");
562  if (QFile::exists(path + oldName))
563  {
564  QDir d(path);
565  d.rename(oldName, newName);
566  }
567 
568  // fix up the metadata in the database
569  MSqlQuery query(MSqlQuery::InitCon());
570  query.prepare("UPDATE gallerymetadata "
571  "SET image = :IMAGENEW "
572  "WHERE image = :IMAGEOLD");
573  query.bindValue(":IMAGENEW", currDir + '/' + newName);
574  query.bindValue(":IMAGEOLD", currDir + '/' + oldName);
575  if (query.exec())
576  return true;
577 
578  // try to undo rename on DB failure
579  cdir.rename(newName, oldName);
580  return false;
581 }
582 
583 QSize GalleryUtil::ScaleToDest(const QSize &src, const QSize &dest, ScaleMax scaleMax)
584 {
585  QSize sz = src;
586 
587  // calculate screen pixel aspect ratio
588  double pixelAspect = GetMythUI()->GetPixelAspectRatio();
589 
590  // calculate image aspect ratio
591  double imageAspect = 1.0;
592  if ((sz.width() > 0) && (sz.height() > 0))
593  imageAspect = (double)sz.width() / (double)sz.height();
594 
595  int scaleWidth = sz.width();
596  int scaleHeight = sz.height();
597 
598  switch (scaleMax)
599  {
600  case kScaleToFill:
601  // scale-max to dest width for most images
602  scaleWidth = dest.width();
603  scaleHeight = lround(dest.width() * pixelAspect / imageAspect);
604  if (scaleHeight < dest.height())
605  {
606  // scale-max to dest height for extra wide images
607  scaleWidth = lround(dest.height() * imageAspect / pixelAspect);
608  scaleHeight = dest.height();
609  }
610  break;
611 
612  case kReduceToFit:
613  // Reduce to fit (but never enlarge)
614  if (scaleWidth <= dest.width() && scaleHeight <= dest.height())
615  break;
616  [[clang::fallthrough]];
617 
618  case kScaleToFit:
619  // scale-min to dest height for most images
620  scaleWidth = lround(dest.height() * imageAspect / pixelAspect);
621  scaleHeight = dest.height();
622  if (scaleWidth > dest.width())
623  {
624  // scale-min to dest width for extra wide images
625  scaleWidth = dest.width();
626  scaleHeight = lround(dest.width() * pixelAspect / imageAspect);
627  }
628  break;
629 
630  default:
631  break;
632  }
633 
634  if (scaleWidth != sz.width() || scaleHeight != sz.height())
635  sz.scale(scaleWidth, scaleHeight, Qt::KeepAspectRatio);
636  return sz;
637 }
638 
639 bool GalleryUtil::CopyDirectory(const QFileInfo& src, QFileInfo &dst)
640 {
641  QDir srcDir(src.absoluteFilePath());
642 
643  dst = MakeUniqueDirectory(dst);
644  if (!dst.exists())
645  {
646  srcDir.mkdir(dst.absoluteFilePath());
647  dst.refresh();
648  }
649 
650  if (!dst.exists() || !dst.isDir())
651  return false;
652 
653  bool ok = true;
654  QDir dstDir(dst.absoluteFilePath());
655  srcDir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
656  QFileInfoList list = srcDir.entryInfoList();
657  QFileInfoList::const_iterator it = list.begin();
658  for (; it != list.end(); ++it)
659  {
660  const QString fn = it->fileName();
661  QFileInfo dfi(dstDir, fn);
662  ok &= Copy(*it, dfi);
663  }
664 
665  return ok;
666 }
667 
668 bool GalleryUtil::MoveDirectory(const QFileInfo& src, QFileInfo &dst)
669 {
670  QDir srcDir(src.absoluteFilePath());
671 
672  dst = MakeUniqueDirectory(dst);
673  if (!dst.exists())
674  {
675  srcDir.mkdir(dst.absoluteFilePath());
676  dst.refresh();
677  }
678 
679  if (!dst.exists() || !dst.isDir())
680  return false;
681 
682  bool ok = true;
683  QDir dstDir(dst.absoluteFilePath());
684  srcDir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
685  QFileInfoList list = srcDir.entryInfoList();
686  QFileInfoList::const_iterator it = list.begin();
687  for (; it != list.end(); ++it)
688  {
689  const QString fn = it->fileName();
690  QFileInfo dfi(dstDir, fn);
691  ok &= Move(*it, dfi);
692  }
693 
694  return ok && FileDelete(src);
695 }
696 
697 bool GalleryUtil::DeleteDirectory(const QFileInfo &dir)
698 {
699  if (!dir.exists())
700  return false;
701 
702  QDir srcDir(dir.absoluteFilePath());
703  srcDir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
704  QFileInfoList list = srcDir.entryInfoList();
705  QFileInfoList::const_iterator it = list.begin();
706  for (; it != list.end(); ++it)
707  {
708  const QString fn = it->fileName();
709  Delete(*it);
710  }
711 
712  return FileDelete(dir);
713 }
714 
715 bool GalleryUtil::RenameDirectory(const QString &currDir, const QString &oldName,
716  const QString &newName)
717 {
718  // rename the directory
719  QDir cdir(currDir);
720  if (!cdir.rename(oldName, newName))
721  return false;
722 
723  // rename the directory's thumbnail if it exists in the parent directory
724  if (QFile::exists(currDir + "/.thumbcache/" + oldName))
725  {
726  QDir d(currDir + "/cache/gallery-thumbcache/");
727  d.rename(oldName, newName);
728  }
729 
730  // also look in HOME directory for any thumbnails
731  int prefixLen = gCoreContext->GetSetting("GalleryDir").length();
732  QString path = GetConfDir() + "/MythGallery";
733  path += currDir.right(currDir.length() - prefixLen) + '/';
734  if (QFile::exists(path + oldName))
735  {
736  QDir d(path);
737  d.rename(oldName, newName);
738 
739  // rename this directory's thumbnail
740  path += QString(".thumbcache/");
741  if (QFile::exists(path + oldName))
742  {
743  QDir d2(path);
744  d2.rename(oldName, newName);
745  }
746  }
747 
748  // fix up the metadata in the database
749  MSqlQuery query(MSqlQuery::InitCon());
750  query.prepare("SELECT image, angle FROM gallerymetadata "
751  "WHERE image LIKE :IMAGEOLD");
752  query.bindValue(":IMAGEOLD", currDir + '/' + oldName + '%');
753  if (query.exec())
754  {
755  while (query.next())
756  {
757  QString oldImage = query.value(0).toString();
758  QString newImage = oldImage;
759  newImage = newImage.replace(currDir + '/' + oldName,
760  currDir + '/' + newName);
761 
762  MSqlQuery subquery(MSqlQuery::InitCon());
763  subquery.prepare("UPDATE gallerymetadata "
764  "SET image = :IMAGENEW "
765  "WHERE image = :IMAGEOLD");
766  subquery.bindValue(":IMAGENEW", newImage);
767  subquery.bindValue(":IMAGEOLD", oldImage);
768  if (!subquery.exec())
769  MythDB::DBError("GalleryUtil::RenameDirectory - update image",
770  subquery);
771  }
772  }
773 
774  return true;
775 }
776 
777 
778 void GalleryUtil::PlayVideo(const QString &filename)
779 {
780  // HACK begin - remove when everything is using mythui
781  vector<QWidget *> widgetList;
782  if (GetMythMainWindow()->currentWidget())
783  {
784  QWidget *widget = GetMythMainWindow()->currentWidget();
785 
786  while (widget)
787  {
788  widgetList.push_back(widget);
789  GetMythMainWindow()->detach(widget);
790  widget->hide();
791  widget = GetMythMainWindow()->currentWidget();
792  }
793 
794  GetMythMainWindow()->GetPaintWindow()->raise();
795  GetMythMainWindow()->GetPaintWindow()->setFocus();
796  //GetMythMainWindow()->ShowPainterWindow();
797  }
798  // HACK end
799 
800  GetMythMainWindow()->HandleMedia("Internal", filename);
801 
802 
803  // HACK begin - remove when everything is using mythui
804  vector<QWidget*>::reverse_iterator it;
805  for (it = widgetList.rbegin(); it != widgetList.rend(); ++it)
806  {
807  GetMythMainWindow()->attach(*it);
808  (*it)->show();
809  }
810  //GetMythMainWindow()->HidePainterWindow();
811  // HACK end
812 }
813 
814 static QFileInfo MakeUnique(const QFileInfo &dest)
815 {
816  QFileInfo newDest = dest;
817 
818  for (uint i = 0; newDest.exists(); i++)
819  {
820  QString basename = QString("%1_%2.%3")
821  .arg(dest.baseName()).arg(i).arg(dest.completeSuffix());
822 
823  newDest.setFile(dest.dir(), basename);
824 
825  LOG(VB_GENERAL, LOG_ERR, LOC +
826  QString("Need to find a new name for '%1' trying '%2'")
827  .arg(dest.absoluteFilePath()).arg(newDest.absoluteFilePath()));
828  }
829 
830  return newDest;
831 }
832 
833 static QFileInfo MakeUniqueDirectory(const QFileInfo &dest)
834 {
835  QFileInfo newDest = dest;
836 
837  for (uint i = 0; newDest.exists() && !newDest.isDir(); i++)
838  {
839  QString fullname = QString("%1_%2").arg(dest.absoluteFilePath()).arg(i);
840  newDest.setFile(fullname);
841 
842  LOG(VB_GENERAL, LOG_ERR, LOC +
843  QString("Need to find a new name for '%1' trying '%2'")
844  .arg(dest.absoluteFilePath()).arg(newDest.absoluteFilePath()));
845  }
846 
847  return newDest;
848 }
849 
850 static bool FileCopy(const QFileInfo &src, const QFileInfo &dst)
851 {
852  const int bufferSize = 16*1024;
853 
854  QFile s(src.absoluteFilePath());
855  QFile d(dst.absoluteFilePath());
856  char buffer[bufferSize];
857  int len;
858 
859  if (!s.open(QIODevice::ReadOnly))
860  return false;
861 
862  if (!d.open(QIODevice::WriteOnly))
863  {
864  s.close();
865  return false;
866  }
867 
868  len = s.read(buffer, bufferSize);
869  do
870  {
871  d.write(buffer, len);
872  len = s.read(buffer, bufferSize);
873  } while (len > 0);
874 
875  s.close();
876  d.close();
877 
878  return true;
879 }
880 
881 static bool FileMove(const QFileInfo &src, const QFileInfo &dst)
882 {
883  // attempt to rename the file,
884  // this will fail if files are on different partitions
885  QByteArray source = src.absoluteFilePath().toLocal8Bit();
886  QByteArray dest = dst.absoluteFilePath().toLocal8Bit();
887  if (rename(source.constData(), dest.constData()) == 0)
888  {
889  return true;
890  }
891 
892  // src and dst are on different mount points, move manually.
893  if (errno == EXDEV)
894  {
895  if (FileCopy(src, dst))
896  return FileDelete(src);
897  }
898 
899  return false;
900 }
901 
902 static bool FileDelete(const QFileInfo &file)
903 {
904  if (!file.isDir())
905  return QFile::remove(file.absoluteFilePath());
906 
907  // delete .thumbcache
908  QDir srcDir(file.absoluteFilePath());
909  QFileInfo tc(srcDir, ".thumbcache");
911 
912  srcDir.rmdir(srcDir.absolutePath());
913 
914  return true;
915 }
916 
917 /*
918  * vim:ts=4:sw=4:ai:et:si:sts=4
919  */
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
static long GetNaturalRotation(const unsigned char *buffer, int size)
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
static bool FileMove(const QFileInfo &src, const QFileInfo &dst)
QWidget * currentWidget(void)
static void PlayVideo(const QString &filename)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
#define LOC
Definition: galleryutil.cpp:50
void setDirectory(const QString &directory, bool isGallery=false)
int getTypeFilter() const
Definition: galleryfilter.h:52
static bool Rename(const QString &currDir, const QString &oldName, const QString &newName)
static bool LoadDirectory(ThumbList &itemList, const QString &dir, const GalleryFilter &flt, bool recurse, ThumbHash *itemHash, ThumbGenerator *thumbGen)
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QList< ThumbItem * > ThumbList
Definition: thumbview.h:78
static QStringList getFilters()
static bool RenameDirectory(const QString &currDir, const QString &oldName, const QString &newName)
#define EXIF_TAG_ORIENTATION
Definition: imagemetadata.h:21
QHash< QString, ThumbItem * > ThumbHash
Definition: thumbview.h:79
QString GetConfDir(void)
Definition: mythdirs.cpp:224
QVariant value(int i) const
Definition: mythdbcon.h:198
static bool IsMovie(const QString &filePath)
static bool Copy(const QFileInfo &src, QFileInfo &dst)
static bool IsImage(const QString &filePath)
double GetPixelAspectRatio(void) const
static QStringList GetMediaFilter(void)
Definition: galleryutil.cpp:95
QString GetName(void) const
Definition: thumbview.h:53
static bool Delete(const QFileInfo &file)
static QSize ScaleToDest(const QSize &src, const QSize &dest, ScaleMax scaleMax)
static QFileInfo MakeUniqueDirectory(const QFileInfo &dest)
static const uint16_t * d
QString GetSetting(const QString &key, const QString &defaultval="")
static QDateTime GetTimestamp(const QString &filePath)
QWidget * GetPaintWindow()
static QString getThumbcacheDir(const QString &inDir)
static bool MoveDirectory(const QFileInfo &src, QFileInfo &dst)
static QString GetCaption(const QString &filePath)
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
QString getDirFilter() const
Definition: galleryfilter.h:45
MythUIHelper * GetMythUI()
static QFileInfo MakeUnique(const QFileInfo &dest)
ScaleMax
Definition: galleryutil.h:28
MythMainWindow * GetMythMainWindow(void)
static bool DeleteDirectory(const QFileInfo &dir)
static QStringList GetMovieFilter(void)
Definition: galleryutil.cpp:74
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void detach(QWidget *child)
int getSort() const
Definition: galleryfilter.h:59
static QStringList GetImageFilter(void)
Definition: galleryutil.cpp:58
void addFile(const QString &filePath)
static bool CopyDirectory(const QFileInfo &src, QFileInfo &dst)
void attach(QWidget *child)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
static bool FileCopy(const QFileInfo &src, const QFileInfo &dst)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
bool HandleMedia(const QString &handler, const QString &mrl, const QString &plot="", const QString &title="", const QString &subtitle="", const QString &director="", int season=0, int episode=0, const QString &inetref="", int lenMins=120, const QString &year="1895", const QString &id="", bool useBookmarks=false)
static bool FileDelete(const QFileInfo &file)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
static bool Move(const QFileInfo &src, QFileInfo &dst)