00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <unistd.h>
00020
00021
00022 #include <cmath>
00023
00024
00025 #include <algorithm>
00026
00027 using namespace std;
00028
00029
00030 #include <QApplication>
00031 #include <QEvent>
00032 #include <QDir>
00033 #include <QMatrix>
00034 #include <QList>
00035 #include <QFileInfo>
00036
00037
00038 #include <mythmiscutil.h>
00039 #include <mythdbcon.h>
00040 #include <httpcomms.h>
00041 #include <mythcontext.h>
00042 #include <mythlogging.h>
00043 #include <mythmainwindow.h>
00044 #include <mythprogressdialog.h>
00045 #include <mythmediamonitor.h>
00046
00047
00048 #include "galleryutil.h"
00049 #include "gallerysettings.h"
00050 #include "galleryfilter.h"
00051 #include "thumbgenerator.h"
00052 #include "iconview.h"
00053 #include "singleview.h"
00054 #include "glsingleview.h"
00055
00056 #define LOC QString("IconView: ")
00057
00058 QEvent::Type ChildCountEvent::kEventType =
00059 (QEvent::Type) QEvent::registerEventType();
00060
00061 class FileCopyThread : public MThread
00062 {
00063 public:
00064 FileCopyThread(IconView *parent, bool move);
00065 virtual void run();
00066 int GetProgress(void) { return m_progress; }
00067
00068 private:
00069 bool m_move;
00070 IconView *m_parent;
00071 volatile int m_progress;
00072 };
00073
00074 FileCopyThread::FileCopyThread(IconView *parent, bool move) :
00075 MThread("FileCopy"), m_move(move), m_parent(parent), m_progress(0)
00076 {
00077 }
00078
00079 void FileCopyThread::run()
00080 {
00081 RunProlog();
00082
00083 QStringList::iterator it;
00084 QFileInfo fi;
00085 QFileInfo dest;
00086
00087 m_progress = 0;
00088
00089 for (it = m_parent->m_itemMarked.begin();
00090 it != m_parent->m_itemMarked.end(); ++it)
00091 {
00092 fi.setFile(*it);
00093 dest.setFile(QDir(m_parent->m_currDir), fi.fileName());
00094
00095 if (fi.exists())
00096 GalleryUtil::CopyMove(fi, dest, m_move);
00097
00098 m_progress++;
00099 }
00100
00101 RunEpilog();
00102 }
00103
00105
00106 IconView::IconView(MythScreenStack *parent, const char *name,
00107 const QString &galleryDir, MythMediaDevice *initialDevice)
00108 : MythScreenType(parent, name)
00109 {
00110 m_galleryDir = galleryDir;
00111 m_galleryFilter = new GalleryFilter();
00112
00113 m_isGallery = false;
00114 m_showDevices = false;
00115 m_currDevice = initialDevice;
00116
00117 m_thumbGen = new ThumbGenerator(this, 0, 0);
00118 m_childCountThread = new ChildCountThread(this);
00119
00120 m_showcaption = gCoreContext->GetNumSetting("GalleryOverlayCaption", 0);
00121 m_sortorder = gCoreContext->GetNumSetting("GallerySortOrder", 0);
00122 m_useOpenGL = gCoreContext->GetNumSetting("SlideshowUseOpenGL", 0);
00123 m_recurse = gCoreContext->GetNumSetting("GalleryRecursiveSlideshow", 0);
00124 m_paths = gCoreContext->GetSetting("GalleryImportDirs").split(":");
00125 m_errorStr = QString::null;
00126
00127 m_captionText = NULL;
00128 m_noImagesText = NULL;
00129 m_selectedImage = NULL;
00130
00131 m_menuPopup = NULL;
00132
00133 QDir dir(m_galleryDir);
00134 if (!dir.exists() || !dir.isReadable())
00135 {
00136 m_errorStr = tr("MythGallery Directory '%1' does not exist "
00137 "or is unreadable.").arg(m_galleryDir);
00138 return;
00139 }
00140
00141 m_popupStack = GetMythMainWindow()->GetStack("popup stack");
00142 }
00143
00144 IconView::~IconView()
00145 {
00146 if (m_thumbGen)
00147 {
00148 delete m_thumbGen;
00149 m_thumbGen = NULL;
00150 }
00151 if (m_galleryFilter)
00152 {
00153 delete m_galleryFilter;
00154 m_galleryFilter = NULL;
00155 }
00156 if (m_childCountThread)
00157 {
00158 delete m_childCountThread;
00159 m_childCountThread = NULL;
00160 }
00161 }
00162
00163 bool IconView::Create(void)
00164 {
00165 bool foundtheme = false;
00166
00167
00168 foundtheme = LoadWindowFromXML("gallery-ui.xml", "gallery", this);
00169
00170 if (!foundtheme)
00171 return false;
00172
00173 bool err = false;
00174 UIUtilE::Assign(this, m_imageList, "images", &err);
00175 UIUtilW::Assign(this, m_captionText, "title");
00176 UIUtilW::Assign(this, m_noImagesText, "noimages");
00177 UIUtilW::Assign(this, m_selectedImage, "selectedimage");
00178 UIUtilW::Assign(this, m_positionText, "position");
00179 UIUtilW::Assign(this, m_crumbsText, "breadcrumbs");
00180
00181 if (err)
00182 {
00183 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'gallery'");
00184 return false;
00185 }
00186
00187 connect(m_imageList, SIGNAL(itemClicked( MythUIButtonListItem*)),
00188 this, SLOT( HandleItemSelect(MythUIButtonListItem*)));
00189 connect(m_imageList, SIGNAL(itemSelected( MythUIButtonListItem*)),
00190 this, SLOT( UpdateText(MythUIButtonListItem*)));
00191 connect(m_imageList, SIGNAL(itemSelected( MythUIButtonListItem*)),
00192 this, SLOT( UpdateImage(MythUIButtonListItem*)));
00193
00194 if (m_noImagesText)
00195 {
00196 m_noImagesText->SetText(tr("No images found in this folder."));
00197 m_noImagesText->SetVisible(false);
00198 }
00199
00200 BuildFocusList();
00201
00202
00203 int thumbWidth = m_imageList->ItemWidth();
00204 int thumbHeight = m_imageList->ItemHeight();
00205 if (m_selectedImage && (m_selectedImage->GetArea().width() > thumbWidth ||
00206 m_selectedImage->GetArea().height() > thumbHeight))
00207 {
00208 thumbWidth = m_selectedImage->GetArea().width();
00209 thumbHeight = m_selectedImage->GetArea().height();
00210 }
00211
00212 if (m_thumbGen)
00213 m_thumbGen->setSize(thumbWidth, thumbHeight);
00214
00215 SetupMediaMonitor();
00216 if (!m_currDevice)
00217 LoadDirectory(m_galleryDir);
00218
00219 return true;
00220 }
00221
00222 void IconView::LoadDirectory(const QString &dir)
00223 {
00224 if (m_thumbGen && m_thumbGen->isRunning())
00225 m_thumbGen->cancel();
00226
00227 if (m_childCountThread && m_childCountThread->isRunning())
00228 m_childCountThread->cancel();
00229
00230 QDir d(dir);
00231 if (!d.exists())
00232 {
00233 LOG(VB_GENERAL, LOG_ERR, LOC + "LoadDirectory called with " +
00234 QString("non-existant directory: '%1'").arg(dir));
00235 return;
00236 }
00237
00238 m_showDevices = false;
00239
00240 m_currDir = d.absolutePath();
00241
00242 while (!m_itemList.isEmpty())
00243 delete m_itemList.takeFirst();
00244
00245 m_itemHash.clear();
00246 m_imageList->Reset();
00247
00248 m_isGallery = GalleryUtil::LoadDirectory(m_itemList, dir, *m_galleryFilter,
00249 false, &m_itemHash, m_thumbGen);
00250
00251 if (m_thumbGen && !m_thumbGen->isRunning())
00252 m_thumbGen->start();
00253
00254 ThumbItem *thumbitem;
00255 for (int x = 0; x < m_itemList.size(); x++)
00256 {
00257 thumbitem = m_itemList.at(x);
00258
00259 thumbitem->InitCaption(m_showcaption);
00260 MythUIButtonListItem* item =
00261 new MythUIButtonListItem(m_imageList, thumbitem->GetCaption(), 0,
00262 true, MythUIButtonListItem::NotChecked);
00263 item->SetData(qVariantFromValue(thumbitem));
00264 if (thumbitem->IsDir())
00265 {
00266 item->DisplayState("subfolder", "nodetype");
00267 m_childCountThread->addFile(thumbitem->GetPath());
00268 }
00269
00270 LoadThumbnail(thumbitem);
00271
00272 if (QFile(thumbitem->GetImageFilename()).exists())
00273 item->SetImage(thumbitem->GetImageFilename());
00274
00275 if (m_itemMarked.contains(thumbitem->GetPath()))
00276 item->setChecked(MythUIButtonListItem::FullChecked);
00277 }
00278
00279 if (m_childCountThread && !m_childCountThread->isRunning())
00280 m_childCountThread->start();
00281
00282 if (m_noImagesText)
00283 m_noImagesText->SetVisible(m_itemList.isEmpty());
00284
00285 if (!m_itemList.isEmpty())
00286 {
00287 UpdateText(m_imageList->GetItemCurrent());
00288 UpdateImage(m_imageList->GetItemCurrent());
00289 }
00290 }
00291
00292 void IconView::LoadThumbnail(ThumbItem *item)
00293 {
00294 if (!item)
00295 return;
00296
00297 bool canLoadGallery = m_isGallery;
00298
00299 QString imagePath;
00300 if (canLoadGallery)
00301 {
00302 if (item->IsDir())
00303 {
00304
00305 QDir subdir(item->GetPath(), "*.highlight.*",
00306 QDir::Name, QDir::Files);
00307
00308 if (subdir.count() > 0)
00309 {
00310
00311 QFileInfoList::const_iterator it = subdir.entryInfoList().begin();
00312 if (it != subdir.entryInfoList().end())
00313 {
00314 imagePath = it->absoluteFilePath();
00315 }
00316 }
00317 }
00318 else
00319 {
00320 QString fn = item->GetName();
00321 int firstDot = fn.indexOf('.');
00322 if (firstDot > 0)
00323 {
00324 fn.insert(firstDot, ".thumb");
00325 imagePath = QString("%1/%2").arg(m_currDir).arg(fn);
00326 }
00327 }
00328
00329 canLoadGallery = !(QFile(imagePath).exists());
00330 }
00331
00332 if (!canLoadGallery)
00333 imagePath = QString("%1%2.jpg")
00334 .arg(ThumbGenerator::getThumbcacheDir(m_currDir))
00335 .arg(item->GetName());
00336
00337 item->SetImageFilename(imagePath);
00338 }
00339
00340 void IconView::SetupMediaMonitor(void)
00341 {
00342 #ifdef _WIN32
00343 if (m_currDevice)
00344 LoadDirectory(m_currDevice->getDevicePath());
00345 #else
00346 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
00347 if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice))
00348 {
00349 bool mounted = m_currDevice->isMounted();
00350 if (!mounted)
00351 mounted = m_currDevice->mount();
00352
00353 if (mounted)
00354 {
00355 connect(m_currDevice,
00356 SIGNAL(statusChanged(MythMediaStatus, MythMediaDevice*)),
00357 SLOT(mediaStatusChanged(MythMediaStatus, MythMediaDevice*)));
00358
00359 LoadDirectory(m_currDevice->getMountPath());
00360
00361 mon->Unlock(m_currDevice);
00362 return;
00363 }
00364 else
00365 {
00366
00367
00368
00369
00370
00371
00372
00373 mon->Unlock(m_currDevice);
00374 }
00375 }
00376 #endif // _WIN32
00377 }
00378
00379 void IconView::UpdateText(MythUIButtonListItem *item)
00380 {
00381 if (!item)
00382 {
00383 if (m_positionText)
00384 m_positionText->Reset();
00385 return;
00386 }
00387
00388 if (m_positionText)
00389 m_positionText->SetText(QString(tr("%1 of %2"))
00390 .arg(m_imageList->GetCurrentPos() + 1)
00391 .arg(m_imageList->GetCount()));
00392
00393 ThumbItem *thumbitem = qVariantValue<ThumbItem *>(item->GetData());
00394 if (!thumbitem)
00395 return;
00396
00397 if (m_crumbsText)
00398 {
00399 QString path = thumbitem->GetPath();
00400 path.replace(m_galleryDir, tr("Gallery Home"));
00401 path.replace("/", " > ");
00402 m_crumbsText->SetText(path);
00403 }
00404
00405 if (m_captionText)
00406 {
00407 QString caption;
00408 caption = thumbitem->GetCaption();
00409 caption = (caption.isNull()) ? "" : caption;
00410 m_captionText->SetText(caption);
00411 }
00412 }
00413
00414 void IconView::UpdateImage(MythUIButtonListItem *item)
00415 {
00416 if (!m_selectedImage)
00417 return;
00418
00419 ThumbItem *thumbitem = qVariantValue<ThumbItem *>(item->GetData());
00420
00421 QString selectedimage;
00422 if (thumbitem)
00423 {
00424 selectedimage = thumbitem->GetImageFilename();
00425 selectedimage = (selectedimage.isNull()) ? "" : selectedimage;
00426 }
00427 m_selectedImage->SetFilename(selectedimage);
00428 m_selectedImage->Load();
00429 }
00430
00431
00432 bool IconView::keyPressEvent(QKeyEvent *event)
00433 {
00434 if (GetFocusWidget()->keyPressEvent(event))
00435 return true;
00436
00437 bool handled = false;
00438 QStringList actions;
00439 handled = GetMythMainWindow()->TranslateKeyPress("Gallery", event, actions);
00440
00441 for (int i = 0; i < actions.size() && !handled; i++)
00442 {
00443 QString action = actions[i];
00444 handled = true;
00445
00446 if (!m_itemList.isEmpty())
00447 {
00448 if (action == "MENU")
00449 {
00450 HandleMainMenu();
00451 }
00452 else if (action == "ROTRIGHT")
00453 HandleRotateCW();
00454 else if (action == "ROTLEFT")
00455 HandleRotateCCW();
00456 else if (action == "DELETE")
00457 HandleDelete();
00458 else if (action == "MARK")
00459 {
00460 ThumbItem *thumbitem = GetCurrentThumb();
00461 MythUIButtonListItem *item = m_imageList->GetItemCurrent();
00462
00463 if (thumbitem)
00464 {
00465 if (!m_itemMarked.contains(thumbitem->GetPath()))
00466 {
00467 m_itemMarked.append(thumbitem->GetPath());
00468 item->setChecked(MythUIButtonListItem::FullChecked);
00469 }
00470 else
00471 {
00472 m_itemMarked.removeAll(thumbitem->GetPath());
00473 item->setChecked(MythUIButtonListItem::NotChecked);
00474 }
00475 }
00476 }
00477 else if (action == "SLIDESHOW")
00478 HandleSlideShow();
00479 else if (action == "RANDOMSHOW")
00480 HandleRandomShow();
00481 else
00482 handled = false;
00483 }
00484
00485 if (action == "ESCAPE")
00486 {
00487 if (GetMythMainWindow()->IsExitingToMain())
00488 {
00489 while ( m_currDir != m_galleryDir &&
00490 HandleSubDirEscape(m_galleryDir) );
00491 }
00492 handled = HandleEscape();
00493 }
00494 }
00495
00496 if (!handled && MythScreenType::keyPressEvent(event))
00497 handled = true;
00498
00499 return handled;
00500 }
00501
00502 void IconView::HandleItemSelect(MythUIButtonListItem *item)
00503 {
00504 bool handled = false;
00505
00506 ThumbItem *thumbitem = qVariantValue<ThumbItem *>(item->GetData());
00507
00508 if (!thumbitem)
00509 return;
00510
00511
00512
00513 if (thumbitem->GetMediaDevice())
00514 handled = HandleMediaDeviceSelect(thumbitem);
00515
00516 if (!handled && thumbitem->IsDir())
00517 {
00518 m_history.push_back(m_imageList->GetCurrentPos());
00519 LoadDirectory(thumbitem->GetPath());
00520
00521 handled = true;
00522 }
00523
00524 if (!handled)
00525 HandleImageSelect("SELECT");
00526 }
00527
00528 bool IconView::HandleMediaDeviceSelect(ThumbItem *item)
00529 {
00530 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
00531 if (mon && mon->ValidateAndLock(item->GetMediaDevice()))
00532 {
00533 m_currDevice = item->GetMediaDevice();
00534
00535 #ifdef _WIN32
00536 LoadDirectory(m_currDevice->getDevicePath());
00537 #else
00538 if (!m_currDevice->isMounted(false))
00539 m_currDevice->mount();
00540
00541 item->SetPath(m_currDevice->getMountPath(), true);
00542
00543 connect(m_currDevice,
00544 SIGNAL(statusChanged(MythMediaStatus,
00545 MythMediaDevice*)),
00546 SLOT(mediaStatusChanged(MythMediaStatus,
00547 MythMediaDevice*)));
00548
00549 LoadDirectory(m_currDevice->getMountPath());
00550 #endif
00551
00552 mon->Unlock(m_currDevice);
00553 }
00554 else
00555 {
00556
00557 QString msg = tr("Error") + '\n' +
00558 tr("The selected device is no longer available");
00559 ShowOkPopup(msg, this, SLOT(HandleShowDevices()));
00560 }
00561
00562 return true;
00563 }
00564
00565 void IconView::HandleSlideShow(void)
00566 {
00567 HandleImageSelect("SLIDESHOW");
00568
00569 SetFocusWidget(m_imageList);
00570 }
00571
00572 void IconView::HandleRandomShow(void)
00573 {
00574 HandleImageSelect("RANDOMSHOW");
00575
00576 SetFocusWidget(m_imageList);
00577 }
00578
00579 bool IconView::HandleImageSelect(const QString &action)
00580 {
00581 ThumbItem *thumbitem = GetCurrentThumb();
00582
00583 if (!thumbitem || (thumbitem->IsDir() && !m_recurse))
00584 return false;
00585
00586 int slideShow = ((action == "PLAY" || action == "SLIDESHOW") ? 1 :
00587 (action == "RANDOMSHOW") ? 2 : 0);
00588
00589 int pos = m_imageList->GetCurrentPos();
00590
00591 #ifdef USING_OPENGL
00592 if (m_useOpenGL && QGLFormat::hasOpenGL())
00593 {
00594 GLSDialog gv(m_itemList, &pos,
00595 slideShow, m_sortorder,
00596 GetMythMainWindow());
00597 gv.exec();
00598 }
00599 else
00600 #endif
00601 {
00602 SingleView sv(m_itemList, &pos, slideShow, m_sortorder,
00603 GetMythMainWindow());
00604 sv.exec();
00605 }
00606
00607
00608
00609
00610 LoadDirectory(m_currDir);
00611
00612 m_imageList->SetItemCurrent(pos);
00613
00614 return true;
00615 }
00616
00617 bool IconView::HandleMediaEscape(MediaMonitor *mon)
00618 {
00619 bool handled = false;
00620 QDir curdir(m_currDir);
00621 QList<MythMediaDevice*> removables = mon->GetMedias(MEDIATYPE_DATA);
00622 QList<MythMediaDevice*>::iterator it = removables.begin();
00623 for (; !handled && (it != removables.end()); ++it)
00624 {
00625 if (!mon->ValidateAndLock(*it))
00626 continue;
00627
00628 if (curdir == QDir((*it)->getMountPath()))
00629 {
00630 HandleShowDevices();
00631
00632
00633 ThumbItem *item = NULL;
00634 if (!(*it)->getVolumeID().isEmpty())
00635 item = m_itemHash.value((*it)->getVolumeID());
00636 else
00637 item = m_itemHash.value((*it)->getDevicePath());
00638
00639 if (item)
00640 {
00641 int pos = m_itemList.indexOf(item);
00642 m_imageList->SetItemCurrent(pos);
00643 }
00644
00645 handled = true;
00646 }
00647 else
00648 {
00649 handled = HandleSubDirEscape((*it)->getMountPath());
00650 }
00651
00652 mon->Unlock(*it);
00653 }
00654
00655 return handled;
00656 }
00657
00658 static bool is_subdir(const QDir &parent, const QDir &subdir)
00659 {
00660 QString pstr = QDir::cleanPath(parent.path());
00661 QString cstr = QDir::cleanPath(subdir.path());
00662 bool ret = !cstr.indexOf(pstr);
00663
00664 return ret;
00665 }
00666
00667 bool IconView::HandleSubDirEscape(const QString &parent)
00668 {
00669 bool handled = false;
00670
00671 QDir curdir(m_currDir);
00672 QDir pdir(parent);
00673 if ((curdir != pdir) && is_subdir(pdir, curdir) && !m_history.empty())
00674 {
00675 QString oldDirName = curdir.dirName();
00676 curdir.cdUp();
00677 LoadDirectory(curdir.absolutePath());
00678
00679 int pos = m_history.back();
00680 m_history.pop_back();
00681 m_imageList->SetItemCurrent(pos);
00682 handled = true;
00683 }
00684
00685 return handled;
00686 }
00687
00688 bool IconView::HandleEscape(void)
00689 {
00690 #if 0
00691 LOG(VB_GENERAL, LOG_INFO, LOC + "HandleEscape() " +
00692 QString("showDevices: %1").arg(m_showDevices));
00693 #endif
00694
00695 bool handled = false;
00696
00697
00698 if (m_showDevices)
00699 {
00700 #if 0
00701 LOG(VB_GENERAL, LOG_INFO, LOC +
00702 "HandleEscape() exiting on showDevices");
00703 #endif
00704 return false;
00705 }
00706
00707
00708 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
00709 if (mon && m_currDevice)
00710 handled = HandleMediaEscape(mon);
00711
00712
00713
00714 if (!handled)
00715 handled = HandleSubDirEscape(m_galleryDir);
00716
00717 #if 0
00718 LOG(VB_GENERAL, LOG_INFO, LOC + QString("HandleEscape() handled: %1")
00719 .arg(handled));
00720 #endif
00721
00722 return handled;
00723 }
00724
00725 void IconView::customEvent(QEvent *event)
00726 {
00727 if (event->type() == ThumbGenEvent::kEventType)
00728 {
00729 ThumbGenEvent *tge = dynamic_cast<ThumbGenEvent *>(event);
00730
00731 if (!tge)
00732 return;
00733
00734 ThumbData *td = tge->thumbData;
00735 if (!td)
00736 return;
00737
00738 ThumbItem *thumbitem = m_itemHash.value(td->fileName);
00739 if (thumbitem)
00740 {
00741 int rotateAngle = thumbitem->GetRotationAngle();
00742
00743 if (rotateAngle)
00744 {
00745 QMatrix matrix;
00746 matrix.rotate(rotateAngle);
00747 td->thumb = td->thumb.transformed(
00748 matrix, Qt::SmoothTransformation);
00749 }
00750
00751 int pos = m_itemList.indexOf(thumbitem);
00752
00753 LoadThumbnail(thumbitem);
00754
00755 MythUIButtonListItem *item = m_imageList->GetItemAt(pos);
00756 if (QFile(thumbitem->GetImageFilename()).exists())
00757 item->SetImage(thumbitem->GetImageFilename());
00758
00759 if (m_imageList->GetCurrentPos() == pos)
00760 UpdateImage(item);
00761 }
00762 delete td;
00763 }
00764 else if (event->type() == ChildCountEvent::kEventType)
00765 {
00766 ChildCountEvent *cce = dynamic_cast<ChildCountEvent *>(event);
00767
00768 if (!cce)
00769 return;
00770
00771 ChildCountData *ccd = cce->childCountData;
00772 if (!ccd)
00773 return;
00774
00775 ThumbItem *thumbitem = m_itemHash.value(ccd->fileName);
00776 if (thumbitem)
00777 {
00778 int pos = m_itemList.indexOf(thumbitem);
00779 MythUIButtonListItem *item = m_imageList->GetItemAt(pos);
00780 if (item)
00781 item->SetText(QString("%1").arg(ccd->count), "childcount");
00782 }
00783 delete ccd;
00784 }
00785 else if (event->type() == DialogCompletionEvent::kEventType)
00786 {
00787 DialogCompletionEvent *dce = (DialogCompletionEvent*)(event);
00788
00789 QString resultid = dce->GetId();
00790 int buttonnum = dce->GetResult();
00791
00792 if (resultid == "mainmenu")
00793 {
00794 switch (buttonnum)
00795 {
00796 case 0:
00797 HandleSlideShow();
00798 break;
00799 case 1:
00800 HandleRandomShow();
00801 break;
00802 case 2:
00803 break;
00804 case 3:
00805 break;
00806 case 4:
00807 HandleSubMenuFilter();
00808 break;
00809 case 5:
00810 break;
00811 case 6:
00812 HandleSettings();
00813 break;
00814 }
00815 }
00816 else if (resultid == "metadatamenu")
00817 {
00818 switch (buttonnum)
00819 {
00820 case 0:
00821 HandleRotateCW();
00822 break;
00823 case 1:
00824 HandleRotateCCW();
00825 break;
00826 }
00827 }
00828 else if (resultid == "markingmenu")
00829 {
00830 switch (buttonnum)
00831 {
00832 case 0:
00833 HandleSelectOne();
00834 break;
00835 case 1:
00836 HandleClearOneMarked();
00837 break;
00838 case 2:
00839 HandleSelectAll();
00840 break;
00841 case 3:
00842 HandleClearMarked();
00843 break;
00844 }
00845 }
00846 else if (resultid == "filemenu")
00847 {
00848 switch (buttonnum)
00849 {
00850 case 0:
00851 HandleShowDevices();
00852 break;
00853 case 1:
00854 HandleEject();
00855 break;
00856 case 2:
00857 HandleImport();
00858 break;
00859 case 3:
00860 HandleCopyHere();
00861 break;
00862 case 4:
00863 HandleMoveHere();
00864 break;
00865 case 5:
00866 HandleDelete();
00867 break;
00868 case 6:
00869 HandleMkDir();
00870 break;
00871 case 7:
00872 HandleRename();
00873 break;
00874 }
00875 }
00876
00877 m_menuPopup = NULL;
00878
00879 }
00880
00881 }
00882
00883 void IconView::reloadData()
00884 {
00885 LoadDirectory(m_galleryDir);
00886 }
00887
00888 void IconView::HandleMainMenu(void)
00889 {
00890 QString label = tr("Gallery Options");
00891
00892 MythMenu *menu = new MythMenu(label, this, "mainmenu");
00893
00894 menu->AddItem(tr("SlideShow"));
00895 menu->AddItem(tr("Random"));
00896 menu->AddItem(tr("Meta Data Options"), NULL, CreateMetadataMenu());
00897 menu->AddItem(tr("Marking Options"), NULL, CreateMarkingMenu());
00898 menu->AddItem(tr("Filter / Sort..."));
00899 menu->AddItem(tr("File Options"), NULL, CreateFileMenu());
00900 menu->AddItem(tr("Settings..."));
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911 m_menuPopup = new MythDialogBox(menu, m_popupStack, "mythgallerymenupopup");
00912
00913 if (!m_menuPopup->Create())
00914 {
00915 delete m_menuPopup;
00916 m_menuPopup = NULL;
00917 return;
00918 }
00919
00920 m_popupStack->AddScreen(m_menuPopup);
00921 }
00922
00923 MythMenu* IconView::CreateMetadataMenu(void)
00924 {
00925 QString label = tr("Metadata Options");
00926
00927 MythMenu *menu = new MythMenu(label, this, "metadatamenu");
00928
00929 menu->AddItem(tr("Rotate CW"));
00930 menu->AddItem(tr("Rotate CCW"));
00931
00932 return menu;
00933 }
00934
00935 MythMenu* IconView::CreateMarkingMenu(void)
00936 {
00937 QString label = tr("Marking Options");
00938
00939 MythMenu *menu = new MythMenu(label, this, "markingmenu");
00940
00941 menu->AddItem(tr("Select One"));
00942 menu->AddItem(tr("Clear One Marked"));
00943 menu->AddItem(tr("Select All"));
00944 menu->AddItem(tr("Clear Marked"));
00945
00946 return menu;
00947 }
00948
00949 void IconView::HandleSubMenuFilter(void)
00950 {
00951 MythScreenStack *mainStack = GetScreenStack();
00952
00953 GalleryFilterDialog *filterdialog =
00954 new GalleryFilterDialog(mainStack, "galleryfilter", m_galleryFilter);
00955
00956 if (filterdialog->Create())
00957 mainStack->AddScreen(filterdialog);
00958
00959 connect(filterdialog, SIGNAL(filterChanged()), SLOT(reloadData()));
00960 }
00961
00962 MythMenu* IconView::CreateFileMenu(void)
00963 {
00964 QString label = tr("File Options");
00965
00966 MythMenu *menu = new MythMenu(label, this, "filemenu");
00967
00968 menu->AddItem(tr("Show Devices"));
00969 menu->AddItem(tr("Eject"));
00970 menu->AddItem(tr("Import"));
00971 menu->AddItem(tr("Copy here"));
00972 menu->AddItem(tr("Move here"));
00973 menu->AddItem(tr("Delete"));
00974 menu->AddItem(tr("Create folder"));
00975 menu->AddItem(tr("Rename"));
00976
00977 return menu;
00978 }
00979
00980 void IconView::HandleRotateCW(void)
00981 {
00982 ThumbItem *thumbitem = GetCurrentThumb();
00983
00984 if (!thumbitem || thumbitem->IsDir())
00985 return;
00986
00987 int rotAngle = thumbitem->GetRotationAngle();
00988
00989 rotAngle += 90;
00990
00991 if (rotAngle >= 360)
00992 rotAngle -= 360;
00993
00994 if (rotAngle < 0)
00995 rotAngle += 360;
00996
00997 thumbitem->SetRotationAngle(rotAngle);
00998 }
00999
01000 void IconView::HandleRotateCCW(void)
01001 {
01002 ThumbItem *thumbitem = GetCurrentThumb();
01003
01004 if (!thumbitem || thumbitem->IsDir())
01005 return;
01006
01007 int rotAngle = thumbitem->GetRotationAngle();
01008
01009 rotAngle -= 90;
01010
01011 if (rotAngle >= 360)
01012 rotAngle -= 360;
01013
01014 if (rotAngle < 0)
01015 rotAngle += 360;
01016
01017 thumbitem->SetRotationAngle(rotAngle);
01018 }
01019
01020 void IconView::HandleDeleteCurrent(void)
01021 {
01022 ThumbItem *thumbitem = GetCurrentThumb();
01023
01024 if (!thumbitem)
01025 return;
01026
01027 QString title = tr("Delete Current File or Folder");
01028 QString msg = (thumbitem->IsDir()) ?
01029 tr("Deleting 1 folder, including any subfolders and files.") :
01030 tr("Deleting 1 image.");
01031
01032 ShowOkPopup(title + '\n' + msg, this, SLOT(DoDeleteCurrent(bool)), true);
01033 }
01034
01035 void IconView::DoDeleteCurrent(bool doDelete)
01036 {
01037 if (doDelete)
01038 {
01039 ThumbItem *thumbitem = GetCurrentThumb();
01040
01041 if (!thumbitem)
01042 return;
01043
01044 QFileInfo fi;
01045 fi.setFile(thumbitem->GetPath());
01046 GalleryUtil::Delete(fi);
01047
01048 LoadDirectory(m_currDir);
01049 }
01050 }
01051
01052 void IconView::HandleSettings(void)
01053 {
01054 GallerySettings settings;
01055 settings.exec();
01056 gCoreContext->ClearSettingsCache();
01057
01058
01059 m_showcaption = gCoreContext->GetNumSetting("GalleryOverlayCaption", 0);
01060 m_sortorder = gCoreContext->GetNumSetting("GallerySortOrder", 0);
01061 m_useOpenGL = gCoreContext->GetNumSetting("SlideshowUseOpenGL", 0);
01062 m_recurse = gCoreContext->GetNumSetting("GalleryRecursiveSlideshow", 0);
01063 m_paths = gCoreContext->GetSetting("GalleryImportDirs").split(":");
01064
01065
01066 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
01067 if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice))
01068 {
01069 #ifdef _WIN32
01070 LoadDirectory(m_currDevice->getDevicePath());
01071 #else
01072 LoadDirectory(m_currDevice->getMountPath());
01073 #endif
01074 mon->Unlock(m_currDevice);
01075 }
01076 else
01077 {
01078 m_currDevice = NULL;
01079 LoadDirectory(m_galleryDir);
01080 }
01081
01082 SetFocusWidget(m_imageList);
01083 }
01084
01085 void IconView::HandleEject(void)
01086 {
01087 MediaMonitor::ejectOpticalDisc();
01088 }
01089
01090 void IconView::HandleImport(void)
01091 {
01092 QFileInfo path;
01093 QDir importdir;
01094
01095 #if 0
01096 DialogBox *importDlg = new DialogBox(GetMythMainWindow(),
01097 tr("Import pictures?"));
01098
01099 importDlg->AddButton(tr("No"));
01100 importDlg->AddButton(tr("Yes"));
01101 DialogCode code = importDlg->exec();
01102 importDlg->deleteLater();
01103 if (kDialogCodeButton1 != code)
01104 return;
01105 #endif
01106
01107
01108 QString idirname = m_currDir + "/" +
01109 QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss");
01110
01111 importdir.mkdir(idirname);
01112 importdir.setPath(idirname);
01113
01114 for (QStringList::const_iterator it = m_paths.begin();
01115 it != m_paths.end(); ++it)
01116 {
01117 path.setFile(*it);
01118 if (path.isDir() && path.isReadable())
01119 {
01120 ImportFromDir(*it, importdir.absolutePath());
01121 }
01122 #if 0
01123 else if (path.isFile() && path.isExecutable())
01124 {
01125
01126 QString cmd = *it + " " + importdir.absolutePath();
01127 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Executing %1").arg(cmd));
01128 myth_system(cmd);
01129 }
01130 #endif
01131 else
01132 {
01133 LOG(VB_GENERAL, LOG_ERR, LOC +
01134 QString("Could not read or execute %1").arg(*it));
01135 }
01136 }
01137
01138 importdir.refresh();
01139 if (importdir.count() == 0)
01140 {
01141 #if 0
01142 DialogBox *nopicsDlg = new DialogBox(GetMythMainWindow(),
01143 tr("Nothing found to import"));
01144
01145 nopicsDlg->AddButton(tr("OK"));
01146 nopicsDlg->exec();
01147 nopicsDlg->deleteLater();
01148 #endif
01149
01150 return;
01151 }
01152
01153 LoadDirectory(m_currDir);
01154 }
01155
01156 void IconView::HandleShowDevices(void)
01157 {
01158 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
01159 #ifndef _WIN32
01160 if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice))
01161 {
01162 m_currDevice->disconnect(this);
01163 mon->Unlock(m_currDevice);
01164 }
01165 else
01166 m_currDir = m_galleryDir;
01167 #endif
01168
01169 m_currDevice = NULL;
01170
01171 m_showDevices = true;
01172
01173 while (!m_itemList.isEmpty())
01174 delete m_itemList.takeFirst();
01175
01176 m_itemHash.clear();
01177 m_imageList->Reset();
01178
01179 m_thumbGen->cancel();
01180 m_childCountThread->cancel();
01181
01182
01183 ThumbItem *item = new ThumbItem("Gallery", m_galleryDir, true);
01184 m_itemList.append(item);
01185 m_itemHash.insert(item->GetName(), item);
01186
01187 if (mon)
01188 {
01189 MythMediaType type = MythMediaType(MEDIATYPE_DATA | MEDIATYPE_MGALLERY);
01190 QList<MythMediaDevice*> removables = mon->GetMedias(type);
01191 QList<MythMediaDevice*>::Iterator it = removables.begin();
01192 for (; it != removables.end(); ++it)
01193 {
01194 if (mon->ValidateAndLock(*it))
01195 {
01196 item = new ThumbItem(
01197 (*it)->getVolumeID().isEmpty() ?
01198 (*it)->getDevicePath() : (*it)->getVolumeID(),
01199 (*it)->getMountPath(), true, *it);
01200
01201 m_itemList.append(item);
01202 m_itemHash.insert(item->GetName(), item);
01203
01204 mon->Unlock(*it);
01205 }
01206 }
01207 }
01208
01209 ThumbItem *thumbitem;
01210 for (int x = 0; x < m_itemList.size(); x++)
01211 {
01212 thumbitem = m_itemList.at(x);
01213
01214 thumbitem->InitCaption(m_showcaption);
01215 MythUIButtonListItem* item =
01216 new MythUIButtonListItem(m_imageList, thumbitem->GetCaption(), 0,
01217 true, MythUIButtonListItem::NotChecked);
01218 item->SetData(qVariantFromValue(thumbitem));
01219 }
01220
01221
01222 SetFocusWidget(m_imageList);
01223 }
01224
01225 void IconView::HandleCopyHere(void)
01226 {
01227 CopyMarkedFiles(false);
01228 HandleClearMarked();
01229 }
01230
01231 void IconView::HandleMoveHere(void)
01232 {
01233 CopyMarkedFiles(true);
01234 HandleClearMarked();
01235 }
01236
01237 void IconView::HandleDelete(void)
01238 {
01239 if (m_itemMarked.isEmpty())
01240 HandleDeleteCurrent();
01241 else
01242 HandleDeleteMarked();
01243 }
01244
01245 void IconView::HandleDeleteMarked(void)
01246 {
01247 QString msg =
01248 tr("Deleting %1 images and folders, including "
01249 "any subfolders and files.").arg(m_itemMarked.count());
01250 ShowOkPopup(msg, this, SLOT(DoDeleteMarked(bool)), true);
01251 }
01252
01253 void IconView::DoDeleteMarked(bool doDelete)
01254 {
01255 if (doDelete)
01256 {
01257 QStringList::iterator it;
01258 QFileInfo fi;
01259
01260 for (it = m_itemMarked.begin(); it != m_itemMarked.end(); ++it)
01261 {
01262 fi.setFile(*it);
01263
01264 GalleryUtil::Delete(fi);
01265 }
01266
01267 m_itemMarked.clear();
01268
01269 LoadDirectory(m_currDir);
01270 }
01271 }
01272
01273 void IconView::HandleClearOneMarked(void)
01274 {
01275 MythUIButtonListItem *item = m_imageList->GetItemCurrent();
01276 if (!item)
01277 return;
01278 item->setChecked(MythUIButtonListItem::NotChecked);
01279 }
01280
01281 void IconView::HandleSelectOne(void)
01282 {
01283 MythUIButtonListItem *item = m_imageList->GetItemCurrent();
01284 if (!item)
01285 return;
01286 item->setChecked(MythUIButtonListItem::FullChecked);
01287 }
01288
01289 void IconView::HandleClearMarked(void)
01290 {
01291 m_itemMarked.clear();
01292 m_imageList->SetAllChecked(MythUIButtonListItem::NotChecked);
01293 }
01294
01295 void IconView::HandleSelectAll(void)
01296 {
01297 ThumbItem *item;
01298 for (int x = 0; x < m_itemList.size(); x++)
01299 {
01300 item = m_itemList.at(x);
01301
01302 if (!m_itemMarked.contains(item->GetPath()))
01303 m_itemMarked.append(item->GetPath());
01304 }
01305
01306 m_imageList->SetAllChecked(MythUIButtonListItem::FullChecked);
01307 }
01308
01309 void IconView::HandleMkDir(void)
01310 {
01311 QString folderName = tr("New Folder");
01312
01313 QString message = tr("Create New Folder");
01314
01315 MythTextInputDialog *dialog = new MythTextInputDialog(m_popupStack, message);
01316
01317 if (dialog->Create())
01318 m_popupStack->AddScreen(dialog);
01319
01320 connect(dialog, SIGNAL(haveResult(QString)),
01321 SLOT(DoMkDir(QString)), Qt::QueuedConnection);
01322 }
01323
01324 void IconView::DoMkDir(QString folderName)
01325 {
01326 QDir cdir(m_currDir);
01327 cdir.mkdir(folderName);
01328
01329 LoadDirectory(m_currDir);
01330 }
01331
01332
01333 void IconView::HandleRename(void)
01334 {
01335 ThumbItem *thumbitem = GetCurrentThumb();
01336
01337 if (!thumbitem)
01338 return;
01339
01340 QString folderName = thumbitem->GetName();
01341
01342 QString message = tr("Rename");
01343
01344 MythTextInputDialog *dialog = new MythTextInputDialog(m_popupStack,
01345 message, FilterNone, false, folderName);
01346
01347 if (dialog->Create())
01348 m_popupStack->AddScreen(dialog);
01349
01350 connect(dialog, SIGNAL(haveResult(QString)),
01351 SLOT(DoRename(QString)), Qt::QueuedConnection);
01352 }
01353
01354 void IconView::DoRename(QString folderName)
01355 {
01356 if (folderName.isEmpty() || folderName == "." || folderName == "..")
01357 return;
01358
01359 ThumbItem *thumbitem = GetCurrentThumb();
01360
01361 if (!thumbitem)
01362 return;
01363
01364 if (!GalleryUtil::Rename(m_currDir, thumbitem->GetName(), folderName))
01365 {
01366 QString msg;
01367 if (thumbitem->IsDir())
01368 msg = tr("Failed to rename folder");
01369 else
01370 msg = tr("Failed to rename file");
01371
01372 ShowOkPopup(msg, NULL, NULL);
01373
01374 return;
01375 }
01376
01377 LoadDirectory(m_currDir);
01378 }
01379
01380 void IconView::ImportFromDir(const QString &fromDir, const QString &toDir)
01381 {
01382 QDir d(fromDir);
01383
01384 if (!d.exists())
01385 return;
01386
01387 d.setNameFilters(GalleryUtil::GetMediaFilter());
01388 d.setSorting((QDir::SortFlag)m_sortorder);
01389 d.setFilter(QDir::Files | QDir::AllDirs |
01390 QDir::NoSymLinks | QDir::Readable);
01391 QFileInfoList list = d.entryInfoList();
01392 QFileInfoList::const_iterator it = list.begin();
01393 const QFileInfo *fi;
01394
01395 while (it != list.end())
01396 {
01397 fi = &(*it);
01398 ++it;
01399 if (fi->fileName() == "." || fi->fileName() == "..")
01400 continue;
01401
01402 if (fi->isDir())
01403 {
01404 QString newdir(toDir + "/" + fi->fileName());
01405 d.mkdir(newdir);
01406 ImportFromDir(fi->absoluteFilePath(), newdir);
01407 }
01408 else
01409 {
01410 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Copying %1 to %2")
01411 .arg(fi->absoluteFilePath())
01412 .arg(toDir));
01413
01414
01415 QString cmd = QString("cp \"%1\" \"%2\"")
01416 .arg(fi->absoluteFilePath()).arg(toDir);
01417 cmd = QString(cmd.toLocal8Bit().constData());
01418 myth_system(cmd);
01419 }
01420 }
01421 }
01422
01423 void IconView::CopyMarkedFiles(bool move)
01424 {
01425 if (m_itemMarked.isEmpty())
01426 return;
01427
01428 QString msg = (move) ?
01429 tr("Moving marked images...") : tr("Copying marked images...");
01430
01431 MythUIProgressDialog *copy_progress = new MythUIProgressDialog(msg,
01432 m_popupStack,
01433 "copyprogressdialog");
01434
01435 if (copy_progress->Create())
01436 {
01437 m_popupStack->AddScreen(copy_progress, false);
01438 copy_progress->SetTotal(m_itemMarked.count());
01439 }
01440 else
01441 {
01442 delete copy_progress;
01443 copy_progress = NULL;
01444 }
01445
01446 FileCopyThread *filecopy = new FileCopyThread(this, move);
01447 int progress = -1;
01448 filecopy->start();
01449
01450 while (!filecopy->isFinished())
01451 {
01452 if (copy_progress)
01453 {
01454 if (progress != filecopy->GetProgress())
01455 {
01456 progress = filecopy->GetProgress();
01457 copy_progress->SetProgress(progress);
01458 }
01459 }
01460
01461 usleep(500);
01462 qApp->processEvents();
01463 }
01464
01465 delete filecopy;
01466
01467 if (copy_progress)
01468 copy_progress->Close();
01469
01470 LoadDirectory(m_currDir);
01471 }
01472
01473 void IconView::mediaStatusChanged(MythMediaStatus oldStatus,
01474 MythMediaDevice *pMedia)
01475 {
01476 (void) oldStatus;
01477 if (m_currDevice == pMedia)
01478 {
01479 HandleShowDevices();
01480
01481
01482 }
01483 }
01484
01485 ThumbItem *IconView::GetCurrentThumb(void)
01486 {
01487 MythUIButtonListItem *item = m_imageList->GetItemCurrent();
01488 if (item)
01489 return qVariantValue<ThumbItem *>(item->GetData());
01490 return NULL;
01491 }
01492
01494
01495 ChildCountThread::ChildCountThread(QObject *parent) :
01496 MThread("ChildCountThread"), m_parent(parent)
01497 {
01498 }
01499
01500 ChildCountThread::~ChildCountThread()
01501 {
01502 cancel();
01503 wait();
01504 }
01505
01506 void ChildCountThread::addFile(const QString& filePath)
01507 {
01508 m_mutex.lock();
01509 m_fileList.append(filePath);
01510 m_mutex.unlock();
01511 }
01512
01513 void ChildCountThread::cancel()
01514 {
01515 m_mutex.lock();
01516 m_fileList.clear();
01517 m_mutex.unlock();
01518 }
01519
01520 void ChildCountThread::run()
01521 {
01522 RunProlog();
01523
01524 while (moreWork())
01525 {
01526 QString file;
01527
01528 m_mutex.lock();
01529 file = m_fileList.first();
01530 if (!m_fileList.isEmpty())
01531 m_fileList.pop_front();
01532 m_mutex.unlock();
01533
01534 if (file.isEmpty())
01535 continue;
01536 int count = getChildCount(file);
01537
01538 ChildCountData *ccd = new ChildCountData;
01539 ccd->fileName = file.section('/', -1);
01540 ccd->count = count;
01541
01542
01543 QApplication::postEvent(m_parent, new ChildCountEvent(ccd));
01544 }
01545
01546 RunEpilog();
01547 }
01548
01549 bool ChildCountThread::moreWork()
01550 {
01551 bool result;
01552 m_mutex.lock();
01553 result = !m_fileList.isEmpty();
01554 m_mutex.unlock();
01555 return result;
01556 }
01557
01558 int ChildCountThread::getChildCount(const QString &filepath)
01559 {
01560 QDir d(filepath);
01561
01562 bool isGallery;
01563 QFileInfoList gList = d.entryInfoList(QStringList("serial*.dat"),
01564 QDir::Files);
01565 isGallery = (gList.count() != 0);
01566
01567 QFileInfoList list = d.entryInfoList(GalleryUtil::GetMediaFilter(),
01568 QDir::Files | QDir::AllDirs);
01569
01570 if (list.isEmpty())
01571 return 0;
01572
01573 QFileInfoList::const_iterator it = list.begin();
01574 const QFileInfo *fi;
01575
01576 int count = 0;
01577 while (it != list.end())
01578 {
01579 fi = &(*it);
01580 ++it;
01581 if (fi->fileName() == "." || fi->fileName() == "..")
01582 continue;
01583
01584
01585 if (isGallery && (
01586 (fi->fileName().indexOf(".thumb.") > 0) ||
01587 (fi->fileName().indexOf(".sized.") > 0) ||
01588 (fi->fileName().indexOf(".highlight.") > 0)))
01589 continue;
01590
01591 count++;
01592 }
01593
01594 return count;
01595 }
01596
01597
01598
01599