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  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)
272  thumbGen->getThumbcacheDir(currDir);
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  else
442  {
443  LOG(VB_FILE, LOG_ERR, LOC +
444  QString("Could not parse exif timestamp from '%1'")
445  .arg(filePath));
446  }
447  }
448  }
449  exif_data_free(data);
450  }
451  else
452  {
453  LOG(VB_FILE, LOG_ERR, LOC +
454  QString("Could not load exif data from '%1'") .arg(filePath));
455  }
456 #if NEW_LIB_EXIF
457  delete [] exifvalue;
458 #endif
459 #endif // EXIF_SUPPORT
460  }
461  catch (...)
462  {
463  LOG(VB_GENERAL, LOG_ERR, LOC +
464  QString("Failed to extract EXIF headers from '%1'") .arg(filePath));
465  }
466 
467  return timestamp;
468 }
469 
470 bool GalleryUtil::Copy(const QFileInfo &src, QFileInfo &dst)
471 {
472  if (src.isDir())
473  return CopyDirectory(src, dst);
474 
475  dst = MakeUnique(dst);
476 
477  if (!FileCopy(src, dst))
478  return false;
479 
480  MSqlQuery query(MSqlQuery::InitCon());
481  query.prepare("INSERT INTO gallerymetadata (image, angle) "
482  "SELECT :IMAGENEW , angle "
483  "FROM gallerymetadata "
484  "WHERE image = :IMAGEOLD");
485  query.bindValue(":IMAGENEW", dst.absoluteFilePath());
486  query.bindValue(":IMAGEOLD", src.absoluteFilePath());
487  if (query.exec())
488  return true;
489 
490  // try to undo copy on DB failure
491  FileDelete(dst);
492  return false;
493 }
494 
495 bool GalleryUtil::Move(const QFileInfo &src, QFileInfo &dst)
496 {
497  if (src.isDir())
498  return MoveDirectory(src, dst);
499 
500  dst = MakeUnique(dst);
501 
502  if (!FileMove(src, dst))
503  return false;
504 
505  MSqlQuery query(MSqlQuery::InitCon());
506  query.prepare("UPDATE gallerymetadata "
507  "SET image = :IMAGENEW "
508  "WHERE image = :IMAGEOLD");
509  query.bindValue(":IMAGENEW", dst.absoluteFilePath());
510  query.bindValue(":IMAGEOLD", src.absoluteFilePath());
511  if (query.exec())
512  return true;
513 
514  // try to undo move on DB failure
515  FileMove(dst, src);
516  return false;
517 }
518 
519 bool GalleryUtil::Delete(const QFileInfo &file)
520 {
521  if (!file.exists())
522  return false;
523 
524  if (file.isDir())
525  return DeleteDirectory(file);
526 
527  MSqlQuery query(MSqlQuery::InitCon());
528  query.prepare("DELETE FROM gallerymetadata "
529  "WHERE image = :IMAGE ;");
530  query.bindValue(":IMAGE", file.absoluteFilePath());
531  if (query.exec())
532  return FileDelete(file);
533 
534  return false;
535 }
536 
537 bool GalleryUtil::Rename(const QString &currDir, const QString &oldName,
538  const QString &newName)
539 {
540  // make sure there isn't already a file/directory with the same name
541  QFileInfo fi(currDir + '/' + newName);
542  if (fi.exists())
543  return false;
544 
545  fi.setFile(currDir + '/' + oldName);
546  if (fi.isDir())
547  return RenameDirectory(currDir, oldName, newName);
548 
549  // rename the file
550  QDir cdir(currDir);
551  if (!cdir.rename(oldName, newName))
552  return false;
553 
554  // rename the file's thumbnail if it exists
555  if (QFile::exists(currDir + "/.thumbcache/" + oldName))
556  {
557  QDir d(currDir + "/cache/gallery-thumbcache/");
558  d.rename(oldName, newName);
559  }
560 
561  int prefixLen = gCoreContext->GetSetting("GalleryDir").length();
562  QString path = GetConfDir() + "/MythGallery";
563  path += currDir.right(currDir.length() - prefixLen);
564  path += QString("/.thumbcache/");
565  if (QFile::exists(path + oldName))
566  {
567  QDir d(path);
568  d.rename(oldName, newName);
569  }
570 
571  // fix up the metadata in the database
572  MSqlQuery query(MSqlQuery::InitCon());
573  query.prepare("UPDATE gallerymetadata "
574  "SET image = :IMAGENEW "
575  "WHERE image = :IMAGEOLD");
576  query.bindValue(":IMAGENEW", currDir + '/' + newName);
577  query.bindValue(":IMAGEOLD", currDir + '/' + oldName);
578  if (query.exec())
579  return true;
580 
581  // try to undo rename on DB failure
582  cdir.rename(newName, oldName);
583  return false;
584 }
585 
586 QSize GalleryUtil::ScaleToDest(const QSize &src, const QSize &dest, ScaleMax scaleMax)
587 {
588  QSize sz = src;
589 
590  // calculate screen pixel aspect ratio
591  double pixelAspect = GetMythUI()->GetPixelAspectRatio();
592 
593  // calculate image aspect ratio
594  double imageAspect = 1.0;
595  if ((sz.width() > 0) && (sz.height() > 0))
596  imageAspect = (double)sz.width() / (double)sz.height();
597 
598  int scaleWidth = sz.width();
599  int scaleHeight = sz.height();
600 
601  switch (scaleMax)
602  {
603  case kScaleToFill:
604  // scale-max to dest width for most images
605  scaleWidth = dest.width();
606  scaleHeight = lround(dest.width() * pixelAspect / imageAspect);
607  if (scaleHeight < dest.height())
608  {
609  // scale-max to dest height for extra wide images
610  scaleWidth = lround(dest.height() * imageAspect / pixelAspect);
611  scaleHeight = dest.height();
612  }
613  break;
614 
615  case kReduceToFit:
616  // Reduce to fit (but never enlarge)
617  if (scaleWidth <= dest.width() && scaleHeight <= dest.height())
618  break;
619  [[clang::fallthrough]];
620 
621  case kScaleToFit:
622  // scale-min to dest height for most images
623  scaleWidth = lround(dest.height() * imageAspect / pixelAspect);
624  scaleHeight = dest.height();
625  if (scaleWidth > dest.width())
626  {
627  // scale-min to dest width for extra wide images
628  scaleWidth = dest.width();
629  scaleHeight = lround(dest.width() * pixelAspect / imageAspect);
630  }
631  break;
632 
633  default:
634  break;
635  }
636 
637  if (scaleWidth != sz.width() || scaleHeight != sz.height())
638  sz.scale(scaleWidth, scaleHeight, Qt::KeepAspectRatio);
639  return sz;
640 }
641 
642 bool GalleryUtil::CopyDirectory(const QFileInfo src, QFileInfo &dst)
643 {
644  QDir srcDir(src.absoluteFilePath());
645 
646  dst = MakeUniqueDirectory(dst);
647  if (!dst.exists())
648  {
649  srcDir.mkdir(dst.absoluteFilePath());
650  dst.refresh();
651  }
652 
653  if (!dst.exists() || !dst.isDir())
654  return false;
655 
656  bool ok = true;
657  QDir dstDir(dst.absoluteFilePath());
658  srcDir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
659  QFileInfoList list = srcDir.entryInfoList();
660  QFileInfoList::const_iterator it = list.begin();
661  for (; it != list.end(); ++it)
662  {
663  const QString fn = it->fileName();
664  QFileInfo dfi(dstDir, fn);
665  ok &= Copy(*it, dfi);
666  }
667 
668  return ok;
669 }
670 
671 bool GalleryUtil::MoveDirectory(const QFileInfo src, QFileInfo &dst)
672 {
673  QDir srcDir(src.absoluteFilePath());
674 
675  dst = MakeUniqueDirectory(dst);
676  if (!dst.exists())
677  {
678  srcDir.mkdir(dst.absoluteFilePath());
679  dst.refresh();
680  }
681 
682  if (!dst.exists() || !dst.isDir())
683  return false;
684 
685  bool ok = true;
686  QDir dstDir(dst.absoluteFilePath());
687  srcDir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
688  QFileInfoList list = srcDir.entryInfoList();
689  QFileInfoList::const_iterator it = list.begin();
690  for (; it != list.end(); ++it)
691  {
692  const QString fn = it->fileName();
693  QFileInfo dfi(dstDir, fn);
694  ok &= Move(*it, dfi);
695  }
696 
697  return ok && FileDelete(src);
698 }
699 
700 bool GalleryUtil::DeleteDirectory(const QFileInfo &dir)
701 {
702  if (!dir.exists())
703  return false;
704 
705  QDir srcDir(dir.absoluteFilePath());
706  srcDir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
707  QFileInfoList list = srcDir.entryInfoList();
708  QFileInfoList::const_iterator it = list.begin();
709  for (; it != list.end(); ++it)
710  {
711  const QString fn = it->fileName();
712  Delete(*it);
713  }
714 
715  return FileDelete(dir);
716 }
717 
718 bool GalleryUtil::RenameDirectory(const QString &currDir, const QString &oldName,
719  const QString &newName)
720 {
721  // rename the directory
722  QDir cdir(currDir);
723  if (!cdir.rename(oldName, newName))
724  return false;
725 
726  // rename the directory's thumbnail if it exists in the parent directory
727  if (QFile::exists(currDir + "/.thumbcache/" + oldName))
728  {
729  QDir d(currDir + "/cache/gallery-thumbcache/");
730  d.rename(oldName, newName);
731  }
732 
733  // also look in HOME directory for any thumbnails
734  int prefixLen = gCoreContext->GetSetting("GalleryDir").length();
735  QString path = GetConfDir() + "/MythGallery";
736  path += currDir.right(currDir.length() - prefixLen) + '/';
737  if (QFile::exists(path + oldName))
738  {
739  QDir d(path);
740  d.rename(oldName, newName);
741 
742  // rename this directory's thumbnail
743  path += QString(".thumbcache/");
744  if (QFile::exists(path + oldName))
745  {
746  QDir d2(path);
747  d2.rename(oldName, newName);
748  }
749  }
750 
751  // fix up the metadata in the database
752  MSqlQuery query(MSqlQuery::InitCon());
753  query.prepare("SELECT image, angle FROM gallerymetadata "
754  "WHERE image LIKE :IMAGEOLD");
755  query.bindValue(":IMAGEOLD", currDir + '/' + oldName + '%');
756  if (query.exec())
757  {
758  while (query.next())
759  {
760  QString oldImage = query.value(0).toString();
761  QString newImage = oldImage;
762  newImage = newImage.replace(currDir + '/' + oldName,
763  currDir + '/' + newName);
764 
765  MSqlQuery subquery(MSqlQuery::InitCon());
766  subquery.prepare("UPDATE gallerymetadata "
767  "SET image = :IMAGENEW "
768  "WHERE image = :IMAGEOLD");
769  subquery.bindValue(":IMAGENEW", newImage);
770  subquery.bindValue(":IMAGEOLD", oldImage);
771  if (!subquery.exec())
772  MythDB::DBError("GalleryUtil::RenameDirectory - update image",
773  subquery);
774  }
775  }
776 
777  return true;
778 }
779 
780 
781 void GalleryUtil::PlayVideo(const QString &filename)
782 {
783  // HACK begin - remove when everything is using mythui
784  vector<QWidget *> widgetList;
785  if (GetMythMainWindow()->currentWidget())
786  {
787  QWidget *widget = GetMythMainWindow()->currentWidget();
788 
789  while (widget)
790  {
791  widgetList.push_back(widget);
792  GetMythMainWindow()->detach(widget);
793  widget->hide();
794  widget = GetMythMainWindow()->currentWidget();
795  }
796 
797  GetMythMainWindow()->GetPaintWindow()->raise();
798  GetMythMainWindow()->GetPaintWindow()->setFocus();
799  //GetMythMainWindow()->ShowPainterWindow();
800  }
801  // HACK end
802 
803  GetMythMainWindow()->HandleMedia("Internal", filename);
804 
805 
806  // HACK begin - remove when everything is using mythui
807  vector<QWidget*>::reverse_iterator it;
808  for (it = widgetList.rbegin(); it != widgetList.rend(); ++it)
809  {
810  GetMythMainWindow()->attach(*it);
811  (*it)->show();
812  }
813  //GetMythMainWindow()->HidePainterWindow();
814  // HACK end
815 }
816 
817 static QFileInfo MakeUnique(const QFileInfo &dest)
818 {
819  QFileInfo newDest = dest;
820 
821  for (uint i = 0; newDest.exists(); i++)
822  {
823  QString basename = QString("%1_%2.%3")
824  .arg(dest.baseName()).arg(i).arg(dest.completeSuffix());
825 
826  newDest.setFile(dest.dir(), basename);
827 
828  LOG(VB_GENERAL, LOG_ERR, LOC +
829  QString("Need to find a new name for '%1' trying '%2'")
830  .arg(dest.absoluteFilePath()).arg(newDest.absoluteFilePath()));
831  }
832 
833  return newDest;
834 }
835 
836 static QFileInfo MakeUniqueDirectory(const QFileInfo &dest)
837 {
838  QFileInfo newDest = dest;
839 
840  for (uint i = 0; newDest.exists() && !newDest.isDir(); i++)
841  {
842  QString fullname = QString("%1_%2").arg(dest.absoluteFilePath()).arg(i);
843  newDest.setFile(fullname);
844 
845  LOG(VB_GENERAL, LOG_ERR, LOC +
846  QString("Need to find a new name for '%1' trying '%2'")
847  .arg(dest.absoluteFilePath()).arg(newDest.absoluteFilePath()));
848  }
849 
850  return newDest;
851 }
852 
853 static bool FileCopy(const QFileInfo &src, const QFileInfo &dst)
854 {
855  const int bufferSize = 16*1024;
856 
857  QFile s(src.absoluteFilePath());
858  QFile d(dst.absoluteFilePath());
859  char buffer[bufferSize];
860  int len;
861 
862  if (!s.open(QIODevice::ReadOnly))
863  return false;
864 
865  if (!d.open(QIODevice::WriteOnly))
866  {
867  s.close();
868  return false;
869  }
870 
871  len = s.read(buffer, bufferSize);
872  do
873  {
874  d.write(buffer, len);
875  len = s.read(buffer, bufferSize);
876  } while (len > 0);
877 
878  s.close();
879  d.close();
880 
881  return true;
882 }
883 
884 static bool FileMove(const QFileInfo &src, const QFileInfo &dst)
885 {
886  // attempt to rename the file,
887  // this will fail if files are on different partitions
888  QByteArray source = src.absoluteFilePath().toLocal8Bit();
889  QByteArray dest = dst.absoluteFilePath().toLocal8Bit();
890  if (rename(source.constData(), dest.constData()) == 0)
891  {
892  return true;
893  }
894 
895  // src and dst are on different mount points, move manually.
896  if (errno == EXDEV)
897  {
898  if (FileCopy(src, dst))
899  return FileDelete(src);
900  }
901 
902  return false;
903 }
904 
905 static bool FileDelete(const QFileInfo &file)
906 {
907  if (!file.isDir())
908  return QFile::remove(file.absoluteFilePath());
909 
910  // delete .thumbcache
911  QDir srcDir(file.absoluteFilePath());
912  QFileInfo tc(srcDir, ".thumbcache");
914 
915  srcDir.rmdir(srcDir.absolutePath());
916 
917  return true;
918 }
919 
920 /*
921  * vim:ts=4:sw=4:ai:et:si:sts=4
922  */
static bool MoveDirectory(const QFileInfo src, QFileInfo &dst)
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:794
static long GetNaturalRotation(const unsigned char *buffer, int size)
void bindValue(const QString &placeholder, const QVariant &val)
Definition: mythdbcon.cpp:875
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 addFile(const QString &fileName)
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:80
static QStringList getFilters()
static bool CopyDirectory(const QFileInfo src, QFileInfo &dst)
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:81
QString GetConfDir(void)
Definition: mythdirs.cpp:224
QVariant value(int i) const
Definition: mythdbcon.h:182
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:55
static bool Delete(const QFileInfo &file)
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 QString GetCaption(const QString &filePath)
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:547
QString getDirFilter() const
Definition: galleryfilter.h:45
MythUIHelper * GetMythUI()
static QFileInfo MakeUnique(const QFileInfo &dest)
ScaleMax
Definition: galleryutil.h:28
MythMainWindow * GetMythMainWindow(void)
static QSize ScaleToDest(const QSize &sz, const QSize &dest, ScaleMax scaleMax)
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:819
#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 attach(QWidget *child)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:615
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)