MythTV  master
iconview.cpp
Go to the documentation of this file.
1 /* ============================================================
2  * File : iconview.cpp
3  * Description :
4  *
5  * This program is free software; you can redistribute it
6  * and/or modify it under the terms of the GNU General
7  * Public License as published bythe Free Software Foundation;
8  * either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * ============================================================ */
17 
18 // POSIX headers
19 #include <unistd.h>
20 
21 // ANSI C headers
22 #include <cmath>
23 
24 // C++ headers
25 #include <algorithm>
26 
27 using namespace std;
28 
29 // Qt headers
30 #include <QApplication>
31 #include <QEvent>
32 #include <QDir>
33 #include <QMatrix>
34 #include <QList>
35 #include <QFileInfo>
36 
37 // MythTV headers
38 #include <mythdate.h>
39 #include <mythdbcon.h>
40 #include <mythsystemlegacy.h>
41 #include <mythcontext.h>
42 #include <mythlogging.h>
43 #include <mythmainwindow.h>
44 #include <mythprogressdialog.h>
45 #include <mythmediamonitor.h>
46 
47 // MythGallery headers
48 #include "config.h"
49 #include "galleryutil.h"
50 #include "gallerysettings.h"
51 #include "galleryfilter.h"
52 #include "thumbgenerator.h"
53 #include "iconview.h"
54 #include "singleview.h"
55 #include "glsingleview.h"
56 
57 #define LOC QString("IconView: ")
58 
59 QEvent::Type ChildCountEvent::kEventType =
60  (QEvent::Type) QEvent::registerEventType();
61 
62 class FileCopyThread : public MThread
63 {
64  public:
65  FileCopyThread(IconView *parent, bool move);
66  void run() override; // MThread
67  int GetProgress(void) { return m_progress; }
68 
69  private:
70  bool m_move;
71  IconView *m_parent {nullptr};
72  volatile int m_progress {0};
73 };
74 
76  MThread("FileCopy"), m_move(move), m_parent(parent)
77 {
78 }
79 
81 {
82  RunProlog();
83 
84  QStringList::iterator it;
85  QFileInfo fi;
86  QFileInfo dest;
87 
88  m_progress = 0;
89 
90  for (it = m_parent->m_itemMarked.begin();
91  it != m_parent->m_itemMarked.end(); ++it)
92  {
93  fi.setFile(*it);
94  dest.setFile(QDir(m_parent->m_currDir), fi.fileName());
95 
96  if (fi.exists())
98 
99  m_progress++;
100  }
101 
102  RunEpilog();
103 }
104 
106 
108 {
109  RunProlog();
110  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Executing %1").arg(m_command));
112  RunEpilog();
113 }
114 
116 
118  const QString &galleryDir, MythMediaDevice *initialDevice)
119  : MythScreenType(parent, name),
120  m_galleryDir(galleryDir),
121  m_galleryFilter(new GalleryFilter()),
122  m_currDevice(initialDevice),
123  m_thumbGen(new ThumbGenerator(this, 0, 0)),
124  m_childCountThread(new ChildCountThread(this))
125 {
126  m_showcaption = gCoreContext->GetBoolSetting("GalleryOverlayCaption", false);
127  m_sortorder = gCoreContext->GetNumSetting("GallerySortOrder", 0);
128  m_useOpenGL = gCoreContext->GetBoolSetting("SlideshowUseOpenGL", false);
129  m_recurse = gCoreContext->GetBoolSetting("GalleryRecursiveSlideshow", false);
130  m_paths = gCoreContext->GetSetting("GalleryImportDirs").split(":");
131  m_allowImportScripts = gCoreContext->GetBoolSetting("GalleryAllowImportScripts", false);
132 
133  QDir dir(m_galleryDir);
134  if (!dir.exists() || !dir.isReadable())
135  {
136  m_errorStr = tr("MythGallery Directory '%1' does not exist "
137  "or is unreadable.").arg(m_galleryDir);
138  return;
139  }
140 
141  m_popupStack = GetMythMainWindow()->GetStack("popup stack");
142 }
143 
145 {
146  if (m_thumbGen)
147  {
148  delete m_thumbGen;
149  m_thumbGen = nullptr;
150  }
151  if (m_galleryFilter)
152  {
153  delete m_galleryFilter;
154  m_galleryFilter = nullptr;
155  }
156  if (m_childCountThread)
157  {
158  delete m_childCountThread;
159  m_childCountThread = nullptr;
160  }
161 }
162 
164 {
165  // Load the theme for this screen
166  bool foundtheme = LoadWindowFromXML("gallery-ui.xml", "gallery", this);
167  if (!foundtheme)
168  return false;
169 
170  bool err = false;
171  UIUtilE::Assign(this, m_imageList, "images", &err);
172  UIUtilW::Assign(this, m_captionText, "title");
173  UIUtilW::Assign(this, m_noImagesText, "noimages");
174  UIUtilW::Assign(this, m_selectedImage, "selectedimage");
175  UIUtilW::Assign(this, m_positionText, "position");
176  UIUtilW::Assign(this, m_crumbsText, "breadcrumbs");
177 
178  if (err)
179  {
180  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'gallery'");
181  return false;
182  }
183 
184  connect(m_imageList, SIGNAL(itemClicked( MythUIButtonListItem*)),
185  this, SLOT( HandleItemSelect(MythUIButtonListItem*)));
186  connect(m_imageList, SIGNAL(itemSelected( MythUIButtonListItem*)),
187  this, SLOT( UpdateText(MythUIButtonListItem*)));
188  connect(m_imageList, SIGNAL(itemSelected( MythUIButtonListItem*)),
189  this, SLOT( UpdateImage(MythUIButtonListItem*)));
190 
191  if (m_noImagesText)
192  {
193  m_noImagesText->SetText(tr("No images found in this folder."));
194  m_noImagesText->SetVisible(false);
195  }
196 
197  BuildFocusList();
198 
199  // TODO Not accurate, the image may be smaller than the button
200  int thumbWidth = m_imageList->ItemWidth();
201  int thumbHeight = m_imageList->ItemHeight();
202  if (m_selectedImage && (m_selectedImage->GetArea().width() > thumbWidth ||
203  m_selectedImage->GetArea().height() > thumbHeight))
204  {
205  thumbWidth = m_selectedImage->GetArea().width();
206  thumbHeight = m_selectedImage->GetArea().height();
207  }
208 
209  if (m_thumbGen)
210  m_thumbGen->setSize(thumbWidth, thumbHeight);
211 
213  if (!m_currDevice)
215 
216  return true;
217 }
218 
219 void IconView::LoadDirectory(const QString &dir)
220 {
221  if (m_thumbGen && m_thumbGen->isRunning())
222  m_thumbGen->cancel();
223 
226 
227  QDir d(dir);
228  if (!d.exists())
229  {
230  LOG(VB_GENERAL, LOG_ERR, LOC + "LoadDirectory called with " +
231  QString("non-existant directory: '%1'").arg(dir));
232  return;
233  }
234 
235  m_showDevices = false;
236 
237  m_currDir = d.absolutePath();
238 
239  while (!m_itemList.isEmpty())
240  delete m_itemList.takeFirst();
241 
242  m_itemHash.clear();
243  m_imageList->Reset();
244 
246  false, &m_itemHash, m_thumbGen);
247 
248  if (m_thumbGen && !m_thumbGen->isRunning())
249  m_thumbGen->start();
250 
251  for (int x = 0; x < m_itemList.size(); x++)
252  {
253  ThumbItem *thumbitem = m_itemList.at(x);
254 
255  thumbitem->InitCaption(m_showcaption);
256  MythUIButtonListItem* item =
257  new MythUIButtonListItem(m_imageList, thumbitem->GetCaption(), nullptr,
259  item->SetData(qVariantFromValue(thumbitem));
260  if (thumbitem->IsDir())
261  {
262  item->DisplayState("subfolder", "nodetype");
263  m_childCountThread->addFile(thumbitem->GetPath());
264  }
265 
266  LoadThumbnail(thumbitem);
267 
268  if (QFile(thumbitem->GetImageFilename()).exists())
269  item->SetImage(thumbitem->GetImageFilename());
270 
271  if (m_itemMarked.contains(thumbitem->GetPath()))
273  }
274 
277 
278  if (m_noImagesText)
280 
281  if (!m_itemList.isEmpty())
282  {
285  }
286 }
287 
289 {
290  if (!item)
291  return;
292 
293  bool canLoadGallery = m_isGallery;
294 
295  QString imagePath;
296  if (canLoadGallery)
297  {
298  if (item->IsDir())
299  {
300  // try to find a highlight
301  QDir subdir(item->GetPath(), "*.highlight.*",
302  QDir::Name, QDir::Files);
303 
304  if (subdir.count() > 0)
305  {
306  // check if the image format is understood
307  QFileInfoList::const_iterator it = subdir.entryInfoList().begin();
308  if (it != subdir.entryInfoList().end())
309  {
310  imagePath = it->absoluteFilePath();
311  }
312  }
313  }
314  else
315  {
316  QString fn = item->GetName();
317  int firstDot = fn.indexOf('.');
318  if (firstDot > 0)
319  {
320  fn.insert(firstDot, ".thumb");
321  imagePath = QString("%1/%2").arg(m_currDir).arg(fn);
322  }
323  }
324 
325  canLoadGallery = !(QFile(imagePath).exists());
326  }
327 
328  if (!canLoadGallery)
329  imagePath = QString("%1%2.jpg")
331  .arg(item->GetName());
332 
333  item->SetImageFilename(imagePath);
334 }
335 
337 {
338 #ifdef _WIN32
339  if (m_currDevice)
341 #else
343  if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice))
344  {
345  bool mounted = m_currDevice->isMounted();
346  if (!mounted)
347  mounted = m_currDevice->mount();
348 
349  if (mounted)
350  {
351  connect(m_currDevice,
352  SIGNAL(statusChanged(MythMediaStatus, MythMediaDevice*)),
354 
356 
357  mon->Unlock(m_currDevice);
358  return;
359  }
360 
361 // DialogBox *dlg = new DialogBox(GetMythMainWindow(),
362 // tr("Failed to mount device: ") +
363 // m_currDevice->getDevicePath() + "\n\n" +
364 // tr("Showing the default MythGallery directory."));
365 // dlg->AddButton(tr("OK"));
366 // dlg->exec();
367 // dlg->deleteLater();
368  mon->Unlock(m_currDevice);
369  }
370 #endif // _WIN32
371 }
372 
374 {
375  if (!item)
376  {
377  if (m_positionText)
379  return;
380  }
381 
382  if (m_positionText)
383  m_positionText->SetText(tr("%1 of %2")
384  .arg(m_imageList->IsEmpty() ? 0 : m_imageList->GetCurrentPos() + 1)
385  .arg(m_imageList->GetCount()));
386 
387  ThumbItem *thumbitem = item->GetData().value<ThumbItem *>();
388  if (!thumbitem)
389  return;
390 
391  if (m_crumbsText)
392  {
393  QString path = thumbitem->GetPath();
394  path.replace(m_galleryDir, tr("Gallery Home"));
395  path.replace("/", " > ");
396  m_crumbsText->SetText(path);
397  }
398 
399  if (m_captionText)
400  {
401  QString caption;
402  caption = thumbitem->GetCaption();
403  caption = (caption.isNull()) ? "" : caption;
404  m_captionText->SetText(caption);
405  }
406 }
407 
409 {
410  if (!m_selectedImage)
411  return;
412 
413  ThumbItem *thumbitem = item->GetData().value<ThumbItem *>();
414 
415  QString selectedimage;
416  if (thumbitem)
417  {
418  selectedimage = thumbitem->GetImageFilename();
419  selectedimage = (selectedimage.isNull()) ? "" : selectedimage;
420  }
421  m_selectedImage->SetFilename(selectedimage);
423 }
424 
425 
426 bool IconView::keyPressEvent(QKeyEvent *event)
427 {
428  if (GetFocusWidget()->keyPressEvent(event))
429  return true;
430 
431  QStringList actions;
432  bool handled = GetMythMainWindow()->TranslateKeyPress("Gallery", event, actions);
433 
434  for (int i = 0; i < actions.size() && !handled; i++)
435  {
436  QString action = actions[i];
437  handled = true;
438 
439  if (!m_itemList.isEmpty())
440  {
441  if (action == "ROTRIGHT")
442  HandleRotateCW();
443  else if (action == "ROTLEFT")
444  HandleRotateCCW();
445  else if (action == "DELETE")
446  HandleDelete();
447  else if (action == "EDIT")
448  HandleRename();
449  else if (action == "MARK")
450  {
451  ThumbItem *thumbitem = GetCurrentThumb();
453 
454  if (thumbitem)
455  {
456  if (!m_itemMarked.contains(thumbitem->GetPath()))
457  {
458  m_itemMarked.append(thumbitem->GetPath());
460  }
461  else
462  {
463  m_itemMarked.removeAll(thumbitem->GetPath());
465  }
466  }
467  }
468  else if (action == "SLIDESHOW")
469  HandleSlideShow();
470  else if (action == "RANDOMSHOW")
472  else if (action == "SEASONALSHOW")
474  else
475  handled = false;
476  }
477 
478  if (action == "ESCAPE")
479  {
480  if (GetMythMainWindow()->IsExitingToMain())
481  {
482  while ( m_currDir != m_galleryDir &&
484  }
485  handled = HandleEscape();
486  }
487  else if (action == "MENU")
488  {
489  HandleMainMenu();
490  }
491  }
492 
493  if (!handled && MythScreenType::keyPressEvent(event))
494  handled = true;
495 
496  return handled;
497 }
498 
500 {
501  bool handled = false;
502 
503  ThumbItem *thumbitem = item->GetData().value<ThumbItem *>();
504 
505  if (!thumbitem)
506  return;
507 
508  // if the selected thumbitem is a Media Device
509  // attempt to mount it if it isn't already
510  if (thumbitem->GetMediaDevice())
511  handled = HandleMediaDeviceSelect(thumbitem);
512 
513  if (!handled && thumbitem->IsDir())
514  {
515  m_history.push_back(m_imageList->GetCurrentPos());
516  LoadDirectory(thumbitem->GetPath());
517 
518  handled = true;
519  }
520 
521  if (!handled)
522  HandleImageSelect("SELECT");
523 }
524 
526 {
528  if (mon && mon->ValidateAndLock(item->GetMediaDevice()))
529  {
530  m_currDevice = item->GetMediaDevice();
531 
532 #ifdef _WIN32
534 #else
535  if (!m_currDevice->isMounted(false))
536  m_currDevice->mount();
537 
538  item->SetPath(m_currDevice->getMountPath(), true);
539 
540  connect(m_currDevice,
541  SIGNAL(statusChanged(MythMediaStatus,
542  MythMediaDevice*)),
544  MythMediaDevice*)));
545 
547 #endif
548 
549  mon->Unlock(m_currDevice);
550  }
551  else
552  {
553  // device was removed
554  QString msg = tr("Error") + '\n' +
555  tr("The selected device is no longer available");
556  ShowOkPopup(msg, this, SLOT(HandleShowDevices()));
557  }
558 
559  return true;
560 }
561 
563 {
564  HandleImageSelect("SLIDESHOW");
565 
567 }
568 
570 {
571  HandleImageSelect("RANDOMSHOW");
572 
574 }
575 
577 {
578  HandleImageSelect("SEASONALSHOW");
579 
581 }
582 
584 {
585  ThumbItem *thumbitem = GetCurrentThumb();
586 
587  if (!thumbitem || (thumbitem->IsDir() && !m_recurse))
588  return false;
589 
590  int slideShow = ((action == "PLAY" || action == "SLIDESHOW") ? 1 :
591  (action == "RANDOMSHOW") ? 2 :
592  (action == "SEASONALSHOW" ? 3 : 0));
593 
594  int pos = m_imageList->GetCurrentPos();
595 
596 #ifdef USING_OPENGL
597  if (m_useOpenGL && QGLFormat::hasOpenGL())
598  {
599  GLSDialog gv(m_itemList, &pos,
600  slideShow, m_sortorder,
602  gv.exec();
603  }
604  else
605 #endif
606  {
607  SingleView sv(m_itemList, &pos, slideShow, m_sortorder,
609  sv.exec();
610  }
611 
612  // if the user deleted files while in single view mode
613  // the cached contents of the directory will be out of
614  // sync, reload the current directory to refresh the view
616 
618 
619  return true;
620 }
621 
623 {
624  bool handled = false;
625  QDir curdir(m_currDir);
626  QList<MythMediaDevice*> removables = mon->GetMedias(MEDIATYPE_DATA|MEDIATYPE_MGALLERY|MEDIATYPE_MVIDEO);
627  QList<MythMediaDevice*>::iterator it = removables.begin();
628  for (; !handled && (it != removables.end()); ++it)
629  {
630  if (!mon->ValidateAndLock(*it))
631  continue;
632 
633  if (curdir == QDir((*it)->getMountPath()))
634  {
636 
637  // Make sure previous devices are visible and selected
638  ThumbItem *item = nullptr;
639  if (!(*it)->getVolumeID().isEmpty())
640  item = m_itemHash.value((*it)->getVolumeID());
641  else
642  item = m_itemHash.value((*it)->getDevicePath());
643 
644  if (item)
645  {
646  int pos = m_itemList.indexOf(item);
648  }
649 
650  handled = true;
651  }
652  else
653  {
654  handled = HandleSubDirEscape((*it)->getMountPath());
655  }
656 
657  mon->Unlock(*it);
658  }
659 
660  return handled;
661 }
662 
663 static bool is_subdir(const QDir &parent, const QDir &subdir)
664 {
665  QString pstr = QDir::cleanPath(parent.path());
666  QString cstr = QDir::cleanPath(subdir.path());
667  return cstr.startsWith(pstr);
668 }
669 
670 bool IconView::HandleSubDirEscape(const QString &parent)
671 {
672  bool handled = false;
673 
674  QDir curdir(m_currDir);
675  QDir pdir(parent);
676  if ((curdir != pdir) && is_subdir(pdir, curdir) && !m_history.empty())
677  {
678  QString oldDirName = curdir.dirName();
679  curdir.cdUp();
680  LoadDirectory(curdir.absolutePath());
681 
682  int pos = m_history.back();
683  m_history.pop_back();
685  handled = true;
686  }
687 
688  return handled;
689 }
690 
692 {
693 #if 0
694  LOG(VB_GENERAL, LOG_INFO, LOC + "HandleEscape() " +
695  QString("showDevices: %1").arg(m_showDevices));
696 #endif
697 
698  bool handled = false;
699 
700  // If we are showing the attached devices, ESCAPE should always exit..
701  if (m_showDevices)
702  {
703 #if 0
704  LOG(VB_GENERAL, LOG_INFO, LOC +
705  "HandleEscape() exiting on showDevices");
706 #endif
707  return false;
708  }
709 
710  // If we are viewing an attached device we should show the attached devices
712  if (mon && m_currDevice)
713  handled = HandleMediaEscape(mon);
714 
715  // If we are viewing a subdirectory of the gallery directory, we should
716  // move up the directory tree, otherwise ESCAPE should exit..
717  if (!handled)
718  handled = HandleSubDirEscape(m_galleryDir);
719 
720 #if 0
721  LOG(VB_GENERAL, LOG_INFO, LOC + QString("HandleEscape() handled: %1")
722  .arg(handled));
723 #endif
724 
725  return handled;
726 }
727 
728 void IconView::customEvent(QEvent *event)
729 {
730  if (event->type() == ThumbGenEvent::kEventType)
731  {
732  ThumbGenEvent *tge = dynamic_cast<ThumbGenEvent *>(event);
733 
734  if (!tge)
735  return;
736 
737  ThumbData *td = tge->m_thumbData;
738  if (!td)
739  return;
740 
741  ThumbItem *thumbitem = m_itemHash.value(td->fileName);
742  if (thumbitem)
743  {
744  int rotateAngle = thumbitem->GetRotationAngle();
745 
746  if (rotateAngle)
747  {
748  QMatrix matrix;
749  matrix.rotate(rotateAngle);
750  td->thumb = td->thumb.transformed(
751  matrix, Qt::SmoothTransformation);
752  }
753 
754  int pos = m_itemList.indexOf(thumbitem);
755 
756  LoadThumbnail(thumbitem);
757 
759  if (QFile(thumbitem->GetImageFilename()).exists())
760  item->SetImage(thumbitem->GetImageFilename());
761 
762  if (m_imageList->GetCurrentPos() == pos)
763  UpdateImage(item);
764  }
765  delete td;
766  }
767  else if (event->type() == ChildCountEvent::kEventType)
768  {
769  ChildCountEvent *cce = dynamic_cast<ChildCountEvent *>(event);
770 
771  if (!cce)
772  return;
773 
774  ChildCountData *ccd = cce->childCountData;
775  if (!ccd)
776  return;
777 
778  ThumbItem *thumbitem = m_itemHash.value(ccd->fileName);
779  if (thumbitem)
780  {
781  int pos = m_itemList.indexOf(thumbitem);
783  if (item)
784  item->SetText(QString("%1").arg(ccd->count), "childcount");
785  }
786  delete ccd;
787  }
788  else if (event->type() == DialogCompletionEvent::kEventType)
789  {
791 
792  QString resultid = dce->GetId();
793  int resultdata = dce->GetData().toInt();
794 
795  if (resultid == "mainmenu")
796  {
797  switch (resultdata)
798  {
799  case 0:
800  HandleSlideShow();
801  break;
802  case 1:
804  break;
805  case 2:
806  break;
807  case 3:
808  break;
809  case 4:
811  break;
812  case 5:
813  break;
814  case 6:
815  HandleSettings();
816  break;
817  case 7:
819  break;
820  }
821  }
822  else if (resultid == "metadatamenu")
823  {
824  switch (resultdata)
825  {
826  case 0:
827  HandleRotateCW();
828  break;
829  case 1:
830  HandleRotateCCW();
831  break;
832  }
833  }
834  else if (resultid == "markingmenu")
835  {
836  switch (resultdata)
837  {
838  case 0:
839  HandleSelectOne();
840  break;
841  case 1:
843  break;
844  case 2:
845  HandleSelectAll();
846  break;
847  case 3:
849  break;
850  }
851  }
852  else if (resultid == "filemenu")
853  {
854  switch (resultdata)
855  {
856  case 0:
858  break;
859  case 1:
860  HandleEject();
861  break;
862  case 2:
863  HandleImport();
864  break;
865  case 3:
866  HandleCopyHere();
867  break;
868  case 4:
869  HandleMoveHere();
870  break;
871  case 5:
872  HandleDelete();
873  break;
874  case 6:
875  HandleMkDir();
876  break;
877  case 7:
878  HandleRename();
879  break;
880  }
881  }
882 
883  m_menuPopup = nullptr;
884 
885  }
886 
887 }
888 
890 {
892 }
893 
895 {
896  QString label = tr("Gallery Options");
897 
898  MythMenu *menu = new MythMenu(label, this, "mainmenu");
899 
900  if (!m_itemList.isEmpty())
901  {
902  menu->AddItem(tr("SlideShow"), nullptr);
903  menu->AddItem(tr("Random"), 1);
904 #ifdef EXIF_SUPPORT
905  menu->AddItem(tr("Seasonal"), 7);
906 #endif // EXIF_SUPPORT
907  menu->AddItem(tr("Meta Data Options"), 2, CreateMetadataMenu());
908  }
909 
910  menu->AddItem(tr("Marking Options"), 3, CreateMarkingMenu());
911  menu->AddItem(tr("Filter / Sort..."), 4);
912  menu->AddItem(tr("File Options"), 5, CreateFileMenu());
913  menu->AddItem(tr("Settings..."), 6);
914 // if (m_showDevices)
915 // {
916 // QDir d(m_currDir);
917 // if (!d.exists())
918 // m_currDir = m_galleryDir;
919 //
920 // LoadDirectory(m_currDir);
921 // m_showDevices = false;
922 // }
923 
924  m_menuPopup = new MythDialogBox(menu, m_popupStack, "mythgallerymenupopup");
925 
926  if (!m_menuPopup->Create())
927  {
928  delete m_menuPopup;
929  m_menuPopup = nullptr;
930  return;
931  }
932 
934 }
935 
937 {
938  QString label = tr("Metadata Options");
939 
940  MythMenu *menu = new MythMenu(label, this, "metadatamenu");
941 
942  menu->AddItem(tr("Rotate CW"), nullptr);
943  menu->AddItem(tr("Rotate CCW"), 1);
944 
945  return menu;
946 }
947 
949 {
950  QString label = tr("Marking Options");
951 
952  MythMenu *menu = new MythMenu(label, this, "markingmenu");
953 
954  menu->AddItem(tr("Select One"), nullptr);
955  menu->AddItem(tr("Clear One Marked"), 1);
956  menu->AddItem(tr("Select All"), 2);
957  menu->AddItem(tr("Clear Marked"), 3);
958 
959  return menu;
960 }
961 
963 {
964  MythScreenStack *mainStack = GetScreenStack();
965 
966  GalleryFilterDialog *filterdialog =
967  new GalleryFilterDialog(mainStack, "galleryfilter", m_galleryFilter);
968 
969  if (filterdialog->Create())
970  mainStack->AddScreen(filterdialog);
971 
972  connect(filterdialog, SIGNAL(filterChanged()), SLOT(reloadData()));
973 }
974 
976 {
977  QString label = tr("File Options");
978 
979  MythMenu *menu = new MythMenu(label, this, "filemenu");
980 
981  menu->AddItem(tr("Show Devices"), nullptr);
982  menu->AddItem(tr("Eject"), 1);
983  menu->AddItem(tr("Import"), 2);
984 
985  if (!m_itemMarked.isEmpty())
986  {
987  menu->AddItem(tr("Copy here"), 3);
988  menu->AddItem(tr("Move here"), 4);
989  }
990 
991  if (!m_imageList->IsEmpty())
992  menu->AddItem(tr("Delete"), 5);
993 
994  menu->AddItem(tr("Create folder"), 6);
995 
996  if (!m_imageList->IsEmpty())
997  menu->AddItem(tr("Rename"), 7);
998 
999  return menu;
1000 }
1001 
1003 {
1004  ThumbItem *thumbitem = GetCurrentThumb();
1005 
1006  if (!thumbitem || thumbitem->IsDir())
1007  return;
1008 
1009  int rotAngle = thumbitem->GetRotationAngle();
1010 
1011  rotAngle += 90;
1012 
1013  if (rotAngle >= 360)
1014  rotAngle -= 360;
1015 
1016  if (rotAngle < 0)
1017  rotAngle += 360;
1018 
1019  thumbitem->SetRotationAngle(rotAngle);
1020 }
1021 
1023 {
1024  ThumbItem *thumbitem = GetCurrentThumb();
1025 
1026  if (!thumbitem || thumbitem->IsDir())
1027  return;
1028 
1029  int rotAngle = thumbitem->GetRotationAngle();
1030 
1031  rotAngle -= 90;
1032 
1033  if (rotAngle >= 360)
1034  rotAngle -= 360;
1035 
1036  if (rotAngle < 0)
1037  rotAngle += 360;
1038 
1039  thumbitem->SetRotationAngle(rotAngle);
1040 }
1041 
1043 {
1044  ThumbItem *thumbitem = GetCurrentThumb();
1045 
1046  if (!thumbitem)
1047  return;
1048 
1049  QString title = tr("Delete Current File or Folder");
1050  QString msg = (thumbitem->IsDir()) ?
1051  tr("Deleting 1 folder, including any subfolders and files.") :
1052  tr("Deleting 1 image.");
1053 
1054  ShowOkPopup(title + '\n' + msg, this, SLOT(DoDeleteCurrent(bool)), true);
1055 }
1056 
1057 void IconView::DoDeleteCurrent(bool doDelete)
1058 {
1059  if (doDelete)
1060  {
1061  ThumbItem *thumbitem = GetCurrentThumb();
1062 
1063  int currPos = 0;
1065  if (item)
1066  currPos = m_imageList->GetCurrentPos();
1067 
1068  if (!thumbitem)
1069  return;
1070 
1071  QFileInfo fi;
1072  fi.setFile(thumbitem->GetPath());
1073  GalleryUtil::Delete(fi);
1074 
1076 
1077  m_imageList->SetItemCurrent(currPos);
1078  }
1079 }
1080 
1082 {
1084  StandardSettingDialog *ssd =
1085  new StandardSettingDialog(mainStack, "gallerysettings",
1086  new GallerySettings());
1087 
1088  if (ssd->Create())
1089  {
1090  mainStack->AddScreen(ssd);
1091 // connect(ssd, SIGNAL(Close()), this, SLOT(ReloadSettings()));
1092  }
1093  else
1094  delete ssd;
1095 
1096 }
1097 
1099 {
1101 
1102  // reload settings
1103  m_showcaption = gCoreContext->GetBoolSetting("GalleryOverlayCaption", false);
1104  m_sortorder = gCoreContext->GetNumSetting("GallerySortOrder", 0);
1105  m_useOpenGL = gCoreContext->GetBoolSetting("SlideshowUseOpenGL", false);
1106  m_recurse = gCoreContext->GetBoolSetting("GalleryRecursiveSlideshow", false);
1107  m_paths = gCoreContext->GetSetting("GalleryImportDirs").split(":");
1108  m_allowImportScripts = gCoreContext->GetBoolSetting("GalleryAllowImportScripts", false);
1109 
1110  // reload directory
1112  if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice))
1113  {
1114 #ifdef _WIN32
1116 #else
1118 #endif
1119  mon->Unlock(m_currDevice);
1120  }
1121  else
1122  {
1123  m_currDevice = nullptr;
1125  }
1126 
1128 }
1129 
1131 {
1133 }
1134 
1136 {
1137  QFileInfo path;
1138  QDir importdir;
1139 
1140  // Makes import directory samba/windows friendly (no colon)
1141  QString idirname = m_currDir + "/" +
1142  MythDate::current().toString("yyyy-MM-dd_hh-mm-ss");
1143 
1144  importdir.mkdir(idirname);
1145  importdir.setPath(idirname);
1146 
1147  for (QStringList::const_iterator it = m_paths.begin();
1148  it != m_paths.end(); ++it)
1149  {
1150  path.setFile(*it);
1151  if (path.isDir() && path.isReadable())
1152  {
1153  ImportFromDir(*it, importdir.absolutePath());
1154  }
1155  else if (path.isFile() && path.isExecutable())
1156  {
1158  {
1159  QString cmd = *it + " " + importdir.absolutePath();
1160 
1161  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1162  MythUIBusyDialog *busy =
1163  new MythUIBusyDialog(tr("Importing images from camera. Please wait..."),
1164  popupStack,
1165  "importbusydialog");
1166 
1167  if (busy->Create())
1168  {
1169  popupStack->AddScreen(busy, false);
1170  }
1171  else
1172  {
1173  delete busy;
1174  busy = nullptr;
1175  }
1176 
1177  ImportThread *import = new ImportThread(cmd);
1178  import->start();
1179 
1180  while (!import->isFinished())
1181  {
1182  usleep(500);
1183  qApp->processEvents();
1184  }
1185 
1186  delete import;
1187 
1188  if (busy)
1189  busy->Close();
1190  }
1191  else
1192  {
1193  ShowOkPopup(tr("Found an import script (%1) but running them has been disabled in the settings!")
1194  .arg(*it));
1195  importdir.rmdir(importdir.absolutePath());
1196  return;
1197  }
1198  }
1199  else
1200  {
1201  LOG(VB_GENERAL, LOG_ERR, LOC +
1202  QString("Could not read or execute %1").arg(*it));
1203 
1204  ShowOkPopup(tr("Could not read or execute %1").arg(*it));
1205  }
1206  }
1207 
1208  importdir.setFilter(QDir::Files | QDir::Readable | QDir::NoDotAndDotDot);
1209  importdir.refresh();
1210  if (importdir.count() == 0)
1211  {
1212  ShowOkPopup(tr("Nothing found to import"));
1213  importdir.rmdir(importdir.absolutePath());
1214  return;
1215  }
1216  ShowOkPopup(tr("Found %n image(s)", "", importdir.count()));
1217 
1219 }
1220 
1222 {
1224 #ifndef _WIN32
1225  if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice))
1226  {
1227  m_currDevice->disconnect(this);
1228  mon->Unlock(m_currDevice);
1229  }
1230  else
1232 #endif
1233 
1234  m_currDevice = nullptr;
1235 
1236  m_showDevices = true;
1237 
1238  while (!m_itemList.isEmpty())
1239  delete m_itemList.takeFirst();
1240 
1241  m_itemHash.clear();
1242  m_imageList->Reset();
1243 
1244  m_thumbGen->cancel();
1246 
1247  // add gallery directory
1248  ThumbItem *item = new ThumbItem("Gallery", m_galleryDir, true);
1249  m_itemList.append(item);
1250  m_itemHash.insert(item->GetName(), item);
1251 
1252  if (mon)
1253  {
1255  QList<MythMediaDevice*> removables = mon->GetMedias(type);
1256  QList<MythMediaDevice*>::Iterator it = removables.begin();
1257  for (; it != removables.end(); ++it)
1258  {
1259  if (mon->ValidateAndLock(*it))
1260  {
1261  ThumbItem *item2 = new ThumbItem(
1262  (*it)->getVolumeID().isEmpty() ?
1263  (*it)->getDevicePath() : (*it)->getVolumeID(),
1264  (*it)->getMountPath(), true, *it);
1265 
1266  m_itemList.append(item2);
1267  m_itemHash.insert(item2->GetName(), item2);
1268 
1269  mon->Unlock(*it);
1270  }
1271  }
1272  }
1273 
1274  for (int x = 0; x < m_itemList.size(); x++)
1275  {
1276  ThumbItem *item3 = m_itemList.at(x);
1277 
1278  item3->InitCaption(m_showcaption);
1279  MythUIButtonListItem* menuitem =
1280  new MythUIButtonListItem(m_imageList, item3->GetCaption(), nullptr,
1282  menuitem->SetData(qVariantFromValue(item3));
1283  }
1284 
1285  // exit from menu on show devices action..
1287 }
1288 
1290 {
1291  CopyMarkedFiles(false);
1293 }
1294 
1296 {
1297  CopyMarkedFiles(true);
1299 }
1300 
1302 {
1303  if (m_itemMarked.isEmpty())
1305  else
1307 }
1308 
1310 {
1311  QString msg = /*tr("Delete Marked Files") + "\n\n" +*/
1312  tr("Deleting %1 images and folders, including "
1313  "any subfolders and files.").arg(m_itemMarked.count());
1314  ShowOkPopup(msg, this, SLOT(DoDeleteMarked(bool)), true);
1315 }
1316 
1317 void IconView::DoDeleteMarked(bool doDelete)
1318 {
1319  if (doDelete)
1320  {
1321  QStringList::iterator it;
1322  QFileInfo fi;
1323 
1324  for (it = m_itemMarked.begin(); it != m_itemMarked.end(); ++it)
1325  {
1326  fi.setFile(*it);
1327 
1328  GalleryUtil::Delete(fi);
1329  }
1330 
1331  m_itemMarked.clear();
1332 
1334  }
1335 }
1336 
1338 {
1340  if (!item)
1341  return;
1343 }
1344 
1346 {
1348  if (!item)
1349  return;
1351 }
1352 
1354 {
1355  m_itemMarked.clear();
1357 }
1358 
1360 {
1361  for (int x = 0; x < m_itemList.size(); x++)
1362  {
1363  ThumbItem *item = m_itemList.at(x);
1364 
1365  if (!m_itemMarked.contains(item->GetPath()))
1366  m_itemMarked.append(item->GetPath());
1367  }
1368 
1370 }
1371 
1373 {
1374  QString folderName = tr("New Folder");
1375 
1376  QString message = tr("Create New Folder");
1377 
1378  MythTextInputDialog *dialog = new MythTextInputDialog(m_popupStack, message);
1379 
1380  if (dialog->Create())
1381  m_popupStack->AddScreen(dialog);
1382 
1383  connect(dialog, SIGNAL(haveResult(QString)),
1384  SLOT(DoMkDir(QString)), Qt::QueuedConnection);
1385 }
1386 
1387 void IconView::DoMkDir(const QString& folderName)
1388 {
1389  QDir cdir(m_currDir);
1390  cdir.mkdir(folderName);
1391 
1393 }
1394 
1395 
1397 {
1398  ThumbItem *thumbitem = GetCurrentThumb();
1399 
1400  if (!thumbitem)
1401  return;
1402 
1403  QString folderName = thumbitem->GetName();
1404 
1405  QString message = tr("Rename");
1406 
1408  message, FilterNone, false, folderName);
1409 
1410  if (dialog->Create())
1411  m_popupStack->AddScreen(dialog);
1412 
1413  connect(dialog, SIGNAL(haveResult(QString)),
1414  SLOT(DoRename(QString)), Qt::QueuedConnection);
1415 }
1416 
1417 void IconView::DoRename(const QString& folderName)
1418 {
1419  if (folderName.isEmpty() || folderName == "." || folderName == "..")
1420  return;
1421 
1422  ThumbItem *thumbitem = GetCurrentThumb();
1423 
1424  int currPos = 0;
1426  if (item)
1427  {
1428  currPos = m_imageList->GetCurrentPos() + 1;
1429 
1430  if (currPos >= m_imageList->GetCount())
1431  currPos = m_imageList->GetCount() - 1;
1432  }
1433 
1434  if (!thumbitem)
1435  return;
1436 
1437  if (!GalleryUtil::Rename(m_currDir, thumbitem->GetName(), folderName))
1438  {
1439  QString msg;
1440  if (thumbitem->IsDir())
1441  msg = tr("Failed to rename folder");
1442  else
1443  msg = tr("Failed to rename file");
1444 
1445  ShowOkPopup(msg);
1446 
1447  return;
1448  }
1449 
1451 
1452  m_imageList->SetItemCurrent(currPos);
1453 }
1454 
1455 void IconView::ImportFromDir(const QString &fromDir, const QString &toDir)
1456 {
1457  QDir d(fromDir);
1458 
1459  if (!d.exists())
1460  return;
1461 
1462  d.setNameFilters(GalleryUtil::GetMediaFilter());
1463  d.setSorting((QDir::SortFlag)m_sortorder);
1464  d.setFilter(QDir::Files | QDir::AllDirs |
1465  QDir::NoSymLinks | QDir::Readable |
1466  QDir::NoDotAndDotDot);
1467  QFileInfoList list = d.entryInfoList();
1468  QFileInfoList::const_iterator it = list.begin();
1469 
1470  while (it != list.end())
1471  {
1472  const QFileInfo *fi = &(*it);
1473  ++it;
1474 
1475  if (fi->isDir())
1476  {
1477  QString newdir(toDir + "/" + fi->fileName());
1478  d.mkdir(newdir);
1479  ImportFromDir(fi->absoluteFilePath(), newdir);
1480  }
1481  else
1482  {
1483  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Copying %1 to %2")
1484  .arg(fi->absoluteFilePath())
1485  .arg(toDir));
1486 
1487  // TODO FIXME, we shouldn't need a myth_system call here
1488  QString cmd = QString("cp \"%1\" \"%2\"")
1489  .arg(fi->absoluteFilePath()).arg(toDir);
1490  cmd = QString(cmd.toLocal8Bit().constData());
1491  myth_system(cmd);
1492  }
1493  }
1494 }
1495 
1497 {
1498  if (m_itemMarked.isEmpty())
1499  return;
1500 
1501  QString msg = (move) ?
1502  tr("Moving marked images...") : tr("Copying marked images...");
1503 
1504  MythUIProgressDialog *copy_progress = new MythUIProgressDialog(msg,
1505  m_popupStack,
1506  "copyprogressdialog");
1507 
1508  if (copy_progress->Create())
1509  {
1510  m_popupStack->AddScreen(copy_progress, false);
1511  copy_progress->SetTotal(m_itemMarked.count());
1512  }
1513  else
1514  {
1515  delete copy_progress;
1516  copy_progress = nullptr;
1517  }
1518 
1519  FileCopyThread *filecopy = new FileCopyThread(this, move);
1520  int progress = -1;
1521  filecopy->start();
1522 
1523  while (!filecopy->isFinished())
1524  {
1525  if (copy_progress)
1526  {
1527  if (progress != filecopy->GetProgress())
1528  {
1529  progress = filecopy->GetProgress();
1530  copy_progress->SetProgress(progress);
1531  }
1532  }
1533 
1534  usleep(500);
1535  qApp->processEvents();
1536  }
1537 
1538  delete filecopy;
1539 
1540  if (copy_progress)
1541  copy_progress->Close();
1542 
1544 }
1545 
1547  MythMediaDevice *pMedia)
1548 {
1549  (void) oldStatus;
1550  if (m_currDevice == pMedia)
1551  {
1553 
1554  // UpdateText();
1555  }
1556 }
1557 
1559 {
1561  if (item)
1562  return item->GetData().value<ThumbItem *>();
1563  return nullptr;
1564 }
1565 
1567 
1569 {
1570  cancel();
1571  wait();
1572 }
1573 
1574 void ChildCountThread::addFile(const QString& filePath)
1575 {
1576  m_mutex.lock();
1577  m_fileList.append(filePath);
1578  m_mutex.unlock();
1579 }
1580 
1582 {
1583  m_mutex.lock();
1584  m_fileList.clear();
1585  m_mutex.unlock();
1586 }
1587 
1589 {
1590  RunProlog();
1591 
1592  while (moreWork())
1593  {
1594  QString file;
1595 
1596  m_mutex.lock();
1597  file = m_fileList.first();
1598  if (!m_fileList.isEmpty())
1599  m_fileList.pop_front();
1600  m_mutex.unlock();
1601 
1602  if (file.isEmpty())
1603  continue;
1604  int count = getChildCount(file);
1605 
1606  ChildCountData *ccd = new ChildCountData;
1607  ccd->fileName = file.section('/', -1);
1608  ccd->count = count;
1609 
1610  // inform parent we have got a count ready for it
1611  QApplication::postEvent(m_parent, new ChildCountEvent(ccd));
1612  }
1613 
1614  RunEpilog();
1615 }
1616 
1618 {
1619  bool result;
1620  m_mutex.lock();
1621  result = !m_fileList.isEmpty();
1622  m_mutex.unlock();
1623  return result;
1624 }
1625 
1626 int ChildCountThread::getChildCount(const QString &filepath)
1627 {
1628  QDir d(filepath);
1629 
1630  bool isGallery;
1631  QFileInfoList gList = d.entryInfoList(QStringList("serial*.dat"),
1632  QDir::Files);
1633  isGallery = (gList.count() != 0);
1634 
1635  QFileInfoList list = d.entryInfoList(GalleryUtil::GetMediaFilter(),
1636  QDir::Files | QDir::AllDirs |
1637  QDir::NoDotAndDotDot);
1638 
1639  if (list.isEmpty())
1640  return 0;
1641 
1642  QFileInfoList::const_iterator it = list.begin();
1643 
1644  int count = 0;
1645  while (it != list.end())
1646  {
1647  const QFileInfo *fi = &(*it);
1648  ++it;
1649 
1650  // remove these already-resized pictures.
1651  if (isGallery && (
1652  (fi->fileName().indexOf(".thumb.") > 0) ||
1653  (fi->fileName().indexOf(".sized.") > 0) ||
1654  (fi->fileName().indexOf(".highlight.") > 0)))
1655  continue;
1656 
1657  count++;
1658  }
1659 
1660  return count;
1661 }
1662 
1663 /*
1664  * vim:ts=4:sw=4:ai:et:si:sts=4
1665  */
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:215
void HandleRotateCW(void)
Definition: iconview.cpp:1002
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
QString GetCaption(void) const
Definition: thumbview.h:55
void DoMkDir(const QString &folderName)
Definition: iconview.cpp:1387
void DoRename(const QString &folderName)
Definition: iconview.cpp:1417
MythScreenStack * GetScreenStack() const
QMutex m_mutex
Definition: iconview.h:204
void UpdateText(MythUIButtonListItem *)
Definition: iconview.cpp:373
void HandleClearMarked(void)
Definition: iconview.cpp:1353
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
const QString & getDevicePath() const
Definition: mythmedia.h:61
QString fileName
void HandleSettings(void)
Definition: iconview.cpp:1081
void HandleSeasonalShow(void)
Definition: iconview.cpp:576
MythMediaType
Definition: mythmedia.h:24
QImage thumb
QString m_errorStr
Definition: iconview.h:149
void HandleCopyHere(void)
Definition: iconview.cpp:1289
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
void mediaStatusChanged(MythMediaStatus oldStatus, MythMediaDevice *pMedia)
Definition: iconview.cpp:1546
QObject * m_parent
Definition: iconview.h:202
void SetProgress(uint count)
bool HandleImageSelect(const QString &action)
Definition: iconview.cpp:583
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
bool Create(void) override
void HandleItemSelect(MythUIButtonListItem *)
Definition: iconview.cpp:499
void addFile(const QString &filePath)
Definition: iconview.cpp:1574
vector< int > m_history
Definition: iconview.h:123
int getChildCount(const QString &filepath)
Definition: iconview.cpp:1626
void SetData(QVariant data)
bool Create(void) override
Definition: iconview.cpp:163
static void ejectOpticalDisc(void)
Eject a disk, unmount a drive, open a tray.
void HandleMoveHere(void)
Definition: iconview.cpp:1295
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:311
Basic menu dialog, message and a list of options.
void customEvent(QEvent *) override
Definition: iconview.cpp:728
MythMediaDevice * GetMediaDevice(void)
Definition: thumbview.h:66
static bool Rename(const QString &currDir, const QString &oldName, const QString &newName)
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: iconview.cpp:1588
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:136
friend class FileCopyThread
Definition: iconview.h:162
bool m_recurse
Definition: iconview.h:146
bool HandleMediaDeviceSelect(ThumbItem *item)
Definition: iconview.cpp:525
static bool LoadDirectory(ThumbList &itemList, const QString &dir, const GalleryFilter &flt, bool recurse, ThumbHash *itemHash, ThumbGenerator *thumbGen)
MythScreenStack * GetStack(const QString &stackname)
void HandleSelectAll(void)
Definition: iconview.cpp:1359
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythScreenStack * GetMainStack()
void HandleShowDevices(void)
Definition: iconview.cpp:1221
MythUIText * m_positionText
Definition: iconview.h:129
MythUIButtonListItem * GetItemAt(int pos) const
int matrix[4][2]
void HandleDeleteCurrent(void)
Definition: iconview.cpp:1042
static MythThemedMenu * menu
ChildCountData * childCountData
Definition: iconview.h:178
void HandleEject(void)
Definition: iconview.cpp:1130
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void BuildFocusList(void)
MythScreenStack * m_popupStack
Definition: iconview.h:133
static Type kEventType
Definition: mythdialogbox.h:50
bool HandleSubDirEscape(const QString &parent)
Definition: iconview.cpp:670
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
void LoadDirectory(const QString &dir)
Definition: iconview.cpp:219
void HandleSubMenuFilter(void)
Definition: iconview.cpp:962
MythUIButtonList * m_imageList
Definition: iconview.h:126
ThumbItem * GetCurrentThumb(void)
Definition: iconview.cpp:1558
bool m_isGallery
Definition: iconview.h:135
virtual void Close()
volatile int m_progress
Definition: iconview.cpp:72
void CopyMarkedFiles(bool move=false)
Definition: iconview.cpp:1496
QString m_galleryDir
Definition: iconview.h:122
static bool CopyMove(const QFileInfo &src, QFileInfo &dst, bool move)
Definition: galleryutil.h:56
FileCopyThread(IconView *parent, bool move)
Definition: iconview.cpp:75
bool Create(void) override
static int run(MythMediaDevice *dev=nullptr, bool startRandomShow=false)
virtual void SetVisible(bool visible)
IconView(MythScreenStack *parent, const char *name, const QString &galleryDir, MythMediaDevice *initialDevice)
Definition: iconview.cpp:117
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
static QStringList GetMediaFilter(void)
Definition: galleryutil.cpp:95
QString GetName(void) const
Definition: thumbview.h:53
long GetRotationAngle(void)
Definition: thumbview.cpp:80
GalleryFilter * m_galleryFilter
Definition: iconview.h:124
bool IsDir(void) const
Definition: thumbview.h:60
bool Create(void) override
MythUIText * m_crumbsText
Definition: iconview.h:128
static bool Delete(const QFileInfo &file)
MythDialogBox * m_menuPopup
Definition: iconview.h:132
IconView * m_parent
Definition: iconview.cpp:71
ChildCountThread * m_childCountThread
Definition: iconview.h:141
bool m_allowImportScripts
Definition: iconview.h:151
static const uint16_t * d
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
Definition: mythuitype.cpp:863
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSetting(const QString &key, const QString &defaultval="")
void reloadData()
Definition: iconview.cpp:889
static MediaMonitor * GetMediaMonitor(void)
static QString getThumbcacheDir(const QString &inDir)
MythUIText * m_noImagesText
Definition: iconview.h:130
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:84
bool isRunning(void) const
Definition: mthread.cpp:274
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: iconview.cpp:107
QList< MythMediaDevice * > GetMedias(unsigned mediatypes)
Ask for available media.
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
void HandleClearOneMarked(void)
Definition: iconview.cpp:1337
ThumbData * m_thumbData
bool m_showcaption
Definition: iconview.h:143
void SetText(const QString &text, const QString &name="", const QString &state="")
void SetAllChecked(MythUIButtonListItem::CheckState state)
void HandleSelectOne(void)
Definition: iconview.cpp:1345
const char * name
Definition: ParseText.cpp:328
void SetImageFilename(const QString &filename)
Definition: thumbview.h:45
void DoDeleteCurrent(bool doDelete)
Definition: iconview.cpp:1057
void Unlock(MythMediaDevice *pMedia)
decrements the MythMediaDevices reference count
uint myth_system(const QString &command, uint flags, uint timeout)
DialogCode exec(void)
int GetProgress(void)
Definition: iconview.cpp:67
int m_sortorder
Definition: iconview.h:144
MythMenu * CreateFileMenu(void)
Definition: iconview.cpp:975
void SetPath(const QString &path, bool isDir)
Definition: thumbview.h:43
bool Create() override
void UpdateImage(MythUIButtonListItem *)
Definition: iconview.cpp:408
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
MythUIType * GetFocusWidget(void) const
void ReloadSettings(void)
Definition: iconview.cpp:1098
QHash< QString, ThumbItem * > m_itemHash
Definition: iconview.h:120
void HandleMainMenu(void)
Definition: iconview.cpp:894
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
MythMainWindow * GetMythMainWindow(void)
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: iconview.cpp:80
MythUIText * m_captionText
Definition: iconview.h:127
QString m_currDir
Definition: iconview.h:137
QStringList m_itemMarked
Definition: iconview.h:121
void HandleRandomShow(void)
Definition: iconview.cpp:569
QString GetPath(void) const
Definition: thumbview.h:59
static Type kEventType
int GetNumSetting(const QString &key, int defaultval=0)
Dialog prompting the user to enter a text string.
QString GetImageFilename(void) const
Definition: thumbview.h:58
bool HandleMediaEscape(MediaMonitor *)
Definition: iconview.cpp:622
void DoDeleteMarked(bool doDelete)
Definition: iconview.cpp:1317
void LoadThumbnail(ThumbItem *item)
Definition: iconview.cpp:288
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QStringList m_paths
Definition: iconview.h:147
MythMenu * CreateMarkingMenu(void)
Definition: iconview.cpp:948
bool Create(void) override
bool ValidateAndLock(MythMediaDevice *pMedia)
Validates the MythMediaDevice and increments its reference count.
ThumbGenerator * m_thumbGen
Definition: iconview.h:140
bool GetBoolSetting(const QString &key, bool defaultval=false)
void HandleDeleteMarked(void)
Definition: iconview.cpp:1309
void InitCaption(bool get_caption)
Definition: thumbview.cpp:44
#define LOC
Definition: iconview.cpp:57
void SetRotationAngle(int angle)
Definition: thumbview.cpp:58
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
const QString & getMountPath() const
Definition: mythmedia.h:58
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:202
void HandleRotateCCW(void)
Definition: iconview.cpp:1022
void HandleSlideShow(void)
Definition: iconview.cpp:562
bool m_showDevices
Definition: iconview.h:136
void HandleImport(void)
Definition: iconview.cpp:1135
void ClearSettingsCache(const QString &myKey=QString(""))
bool isMounted(bool bVerify=true)
Tells us if m_DevicePath is a mounted device.
Definition: mythmedia.cpp:356
void SetItemCurrent(MythUIButtonListItem *item)
bool isFinished(void) const
Definition: mthread.cpp:269
QString m_command
Definition: iconview.h:214
bool SetFocusWidget(MythUIType *widget=nullptr)
MythMediaStatus
Definition: mythmedia.h:12
bool m_useOpenGL
Definition: iconview.h:145
MythMediaDevice * m_currDevice
Definition: iconview.h:138
Screen in which all other widgets are contained and rendered.
void HandleMkDir(void)
Definition: iconview.cpp:1372
int GetCurrentPos() const
bool HandleEscape(void)
Definition: iconview.cpp:691
static Type kEventType
Definition: iconview.h:180
QStringList m_fileList
Definition: iconview.h:203
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:37
void DisplayState(const QString &state, const QString &name)
QList< ThumbItem * > m_itemList
Definition: iconview.h:119
void HandleRename(void)
Definition: iconview.cpp:1396
MythMenu * CreateMetadataMenu(void)
Definition: iconview.cpp:936
void SetupMediaMonitor(void)
Definition: iconview.cpp:336
static bool is_subdir(const QDir &parent, const QDir &subdir)
Definition: iconview.cpp:663
void setSize(int w, int h)
QString fileName
Definition: iconview.h:167
void setChecked(CheckState state)
void HandleDelete(void)
Definition: iconview.cpp:1301
MythUIButtonListItem * GetItemCurrent() const
MythUIImage * m_selectedImage
Definition: iconview.h:131
bool Create(void) override
bool keyPressEvent(QKeyEvent *) override
Key event handler.
Definition: iconview.cpp:426
void ImportFromDir(const QString &fromDir, const QString &toDir)
Definition: iconview.cpp:1455