Ticket #603: gallery_removable_v5.diff

File gallery_removable_v5.diff, 39.7 KB (added by Aaron McCarthy <mccarthy.aaron@…>, 14 years ago)
  • mythgallery/mythgallery/glsingleview.cpp

     
    405405        {
    406406            ThumbItem *item = m_itemList.at(m_pos);
    407407            if (item) {
    408                 if( item->Remove() ) {
     408                if( GalleryUtil::Delete(item->path) ) {
    409409                    m_zoom = 1.0;
    410410                    m_sx   = 0;
    411411                    m_sy   = 0;
  • mythgallery/mythgallery/galleryutil.h

     
     1// -*- Mode: c++ -*-
    12/* ============================================================
    23 * File  : exifutil.h
    34 * Description :
     
    2324
    2425class GalleryUtil
    2526{
    26 
    2727 public:
    2828    static bool isImage(const char* filePath);
    2929    static bool isMovie(const char* filePath);
     
    3434    static bool loadDirectory(ThumbList& itemList,
    3535                              const QString& dir, bool recurse,
    3636                              ThumbDict *itemDict, ThumbGenerator* thumbGen);
     37
     38    static bool CopyMove(const QFileInfo &src, QFileInfo &dst, bool move)
     39        { if (move) return Move(src, dst); else return Copy(src, dst); }
     40
     41    static bool Copy(const QFileInfo &src, QFileInfo &dst);
     42    static bool Move(const QFileInfo &src, QFileInfo &dst);
     43    static bool Delete(const QFileInfo &file);
     44
     45  private:
     46    static bool CopyDirectory(const QFileInfo src, QFileInfo &dst);
     47    static bool MoveDirectory(const QFileInfo src, QFileInfo &dst);
     48    static bool DeleteDirectory(const QFileInfo &dir);
    3749};
    3850
    3951#endif /* EXIFUTIL_H */
  • mythgallery/mythgallery/singleview.cpp

     
    450450        {
    451451            ThumbItem *item = m_itemList.at(m_pos);
    452452            if (item) {
    453                 if( item->Remove() ) {
     453                if( GalleryUtil::Delete(item->path) ) {
    454454                    m_zoom = 1.0;
    455455                    m_sx   = 0;
    456456                    m_sy   = 0;
  • mythgallery/mythgallery/iconview.cpp

     
    3131#include <mythtv/xmlparse.h>
    3232#include <mythtv/dialogbox.h>
    3333#include <mythtv/mythdbcon.h>
     34#include <mythtv/mythdialogs.h>
    3435
     36#ifndef _WIN32
     37#include <mythtv/mythmediamonitor.h>
     38#endif
     39
    3540#include "galleryutil.h"
    3641#include "gallerysettings.h"
    3742#include "thumbgenerator.h"
     
    4550#include "glsingleview.h"
    4651#endif
    4752
    48 
    4953int ThumbItem::GetRotationAngle()
    5054{
    5155    MSqlQuery query(MSqlQuery::InitCon());
     
    8488    return false;
    8589}
    8690
    87 IconView::IconView(const QString& galleryDir, MythMainWindow* parent,
    88                    const char* name )
     91IconView::IconView(const QString& galleryDir, MythMediaDevice *initialDevice,
     92                   MythMainWindow* parent, const char* name )
    8993    : MythDialog(parent, name)
    9094{
    9195    m_galleryDir = galleryDir;   
    9296
    9397    m_inMenu     = false;
     98    m_inSubMenu = false;
    9499    m_itemList.setAutoDelete(true);
    95100    m_itemDict.setAutoDelete(false);
    96101
     
    108113    m_lastCol = 0;
    109114    m_topRow  = 0;
    110115    m_isGallery  = false;
     116    m_showDevices = false;
     117    m_currDevice = initialDevice;
    111118
    112119    srand(time(NULL));
    113     loadDirectory(galleryDir);
     120
     121    MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
     122    if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice))
     123    {
     124        if (!m_currDevice->isMounted(true))
     125            m_currDevice->mount();
     126
     127        connect(m_currDevice, SIGNAL(statusChanged(MediaStatus, MythMediaDevice*)),
     128                SLOT(mediaStatusChanged(MediaStatus, MythMediaDevice*)));
     129
     130        loadDirectory(m_currDevice->getMountPath());
     131
     132        mon->Unlock(m_currDevice);
     133    }
     134    else
     135    {
     136        m_currDevice = NULL;
     137        loadDirectory(galleryDir);
     138    }
    114139}
    115140
    116141IconView::~IconView()
    117142{
    118     UIListBtnTypeItem* item = m_menuType->GetItemFirst();
    119     while (item) {
    120         Action *act = (Action*) item->getData();
    121         if (act)
    122             delete act;
    123         item = m_menuType->GetItemNext(item);
    124     }
     143    clearMenu(m_submenuType);
     144    clearMenu(m_menuType);
    125145   
    126146    delete m_thumbGen;
    127147    delete m_theme;
     
    258278                                 item->pixmap->height()/2-bh2+sh,
    259279                                 bw-2*sw, bh-2*sh-(int)(15*hmult));
    260280
     281                if (m_itemMarked.contains(item->path))
     282                    p.drawPixmap(xpos, ypos, m_MrkPix);
     283
    261284            }
    262285            else {
    263286
     
    272295                                 item->pixmap->width()/2-bw2+sw,
    273296                                 item->pixmap->height()/2-bh2+sh,
    274297                                 bw-2*sw, bh-2*sh);
     298
     299                if (m_itemMarked.contains(item->path))
     300                    p.drawPixmap(xpos, ypos, m_MrkPix);
    275301            }
    276302           
    277303            curPos++;
     
    299325        QString action = actions[i];
    300326        if (action == "MENU") {
    301327            m_inMenu = !m_inMenu;
    302             m_menuType->SetActive(m_inMenu);
     328            m_menuType->SetActive(m_inMenu & !m_inSubMenu);
     329            m_submenuType->SetActive(m_inMenu & m_inSubMenu);
    303330            menuHandled = true;
    304331        }
     332        else if (action == "ESCAPE") {
     333            if (m_inMenu & m_inSubMenu) {
     334                actionMainMenu();
     335                m_menuType->SetActive(m_inMenu & !m_inSubMenu);
     336                m_submenuType->SetActive(m_inMenu & m_inSubMenu);
     337                menuHandled = true;
     338            }
     339        }
    305340        else if (action == "UP") {
    306             if (m_inMenu) {
     341            if (m_inMenu & !m_inSubMenu) {
    307342                m_menuType->MoveUp();
    308343                menuHandled = true;
    309344            }
     345            else if (m_inMenu & m_inSubMenu) {
     346                m_submenuType->MoveUp();
     347                menuHandled = true;
     348            }
    310349            else
    311350                handled = moveUp();
    312351        }
    313352        else if (action == "DOWN") {
    314             if (m_inMenu) {
     353            if (m_inMenu & !m_inSubMenu) {
    315354                m_menuType->MoveDown();
    316355                menuHandled = true;
    317356            }
     357            else if (m_inMenu & m_inSubMenu) {
     358                m_submenuType->MoveDown();
     359                menuHandled = true;
     360            }
    318361            else
    319362                handled = moveDown();
    320363        }
     
    363406            actionDelete();
    364407            handled = true;
    365408        }
     409        else if (action == "MARK")
     410        {
     411            int pos = m_currRow * m_nCols + m_currCol;
     412            ThumbItem *item = m_itemList.at(pos);
     413            if (!item) {
     414                std::cerr << "The impossible happened" << std::endl;
     415                break;
     416            }
     417
     418            if (!m_itemMarked.contains(item->path))
     419                m_itemMarked.append(item->path);
     420            else
     421                m_itemMarked.remove(item->path);
     422
     423            handled = true;
     424        }
    366425        else if (action == "SELECT" || action == "PLAY" || action == "SLIDESHOW" || action == "RANDOMSHOW" )
    367426        {
    368427            if (m_inMenu && (action == "SELECT" || action == "PLAY") ) {
     
    378437                }
    379438       
    380439                QFileInfo fi(item->path);
    381                 if (item->isDir && (action == "SELECT" || action == "PLAY") ) {
     440
     441                // if the selected item is a Media Device
     442                // attempt to mount it if it isn't already
     443                if (item->mediaDevice && (action == "SELECT" || action == "PLAY") )
     444                {
     445
     446                    MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
     447                    if (mon && mon->ValidateAndLock(item->mediaDevice))
     448                    {
     449                        m_currDevice = item->mediaDevice;
     450
     451                        if (!m_currDevice->isMounted())
     452                            m_currDevice->mount();
     453
     454                        item->path = m_currDevice->getMountPath();
     455
     456                        connect(m_currDevice,
     457                                SIGNAL(statusChanged(MediaStatus, MythMediaDevice*)),
     458                                SLOT(mediaStatusChanged(MediaStatus, MythMediaDevice*)));
     459
     460                        mon->Unlock(m_currDevice);
     461                    }
     462                    else
     463                    {
     464                        // device was removed
     465                        MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     466                                                  tr("Error"),
     467                                                  tr("The selected device is no longer available"));
     468
     469                        actionShowDevices();
     470                        m_currRow = 0;
     471                        m_currCol = 0;
     472                        handled = true;
     473                        break;
     474                    }
     475                }
     476
     477                if (!handled && item->isDir &&
     478                    (action == "SELECT" || action == "PLAY") ) {
    382479                    loadDirectory(item->path);
    383480                    handled = true;
    384481                }
     
    414511                                      gContext->GetMainWindow());
    415512                        sv.exec();
    416513                    }                         
     514
     515                    // if the user deleted files while in single view mode
     516                    // the cached contents of the directory will be out of
     517                    // sync, reload the current directory to refresh the view
     518                    loadDirectory(m_currDir);
    417519                }
    418520            }
    419521        }
     
    426528        {
    427529            QString action = actions[i];
    428530            if (action == "ESCAPE") {
     531                if (m_showDevices)
     532                {
     533                    loadDirectory(m_galleryDir);
     534                    handled = true;
     535                }
     536                else
     537                {
    429538                QDir d(m_currDir);
     539#ifndef _WIN32
     540                    MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
     541                    if (mon)
     542                    {
     543                        QValueList<MythMediaDevice*> removables =
     544                            mon->GetMedias(MEDIATYPE_DATA);
     545
     546                        QValueList<MythMediaDevice*>::Iterator it =
     547                            removables.begin();
     548                        for (; it != removables.end(); it++)
     549                        {
     550                            if (mon->ValidateAndLock(*it))
     551                            {
     552                                if (d == QDir((*it)->getMountPath()))
     553                                {
     554                                    actionShowDevices();
     555
     556                                    // make sure previous devies is visible and selected
     557                                    ThumbItem *item;
     558                                    if ((*it)->getVolumeID() != "")
     559                                        item = m_itemDict.find((*it)->getVolumeID());
     560                                    else
     561                                        item = m_itemDict.find((*it)->getDevicePath());
     562
     563                                    if (item)
     564                                    {
     565                                        int pos = m_itemList.find(item);
     566                                        if (pos != -1)
     567                                        {
     568                                            m_currRow = pos/m_nCols;
     569                                            m_currCol = pos-m_currRow*m_nCols;
     570                                            m_topRow = QMAX(0, m_currRow-(m_nRows-1));
     571                                        }
     572                                    }
     573                                    handled = true;
     574                                    mon->Unlock(*it);
     575                                    break;
     576                                }
     577                                mon->Unlock(*it);
     578                            }
     579                        }
     580                    }
     581
     582                    if (!handled)
     583                    {
     584#endif
    430585                if (d != QDir(m_galleryDir)) {
    431586
    432587                    QString oldDirName = d.dirName();
     
    445600                    }
    446601                    handled = true;
    447602                }
     603#ifndef _WIN32
     604                    }
     605                }
     606#endif
    448607            }
    449608        }
    450609    }
     
    456615    {
    457616        MythDialog::keyPressEvent(e);
    458617    }
    459 
    460618}
    461619
    462620void IconView::customEvent(QCustomEvent *e)
     
    547705        exit(-1);
    548706    }
    549707
     708    m_submenuType = (UIListBtnType*)container->GetType("submenu");
     709    if (!m_menuType) {
     710        std::cerr << "MythGallery: Failed to get submenu area."
     711                  << std::endl;
     712        exit(-1);
     713    }
     714
    550715    // Menu Actions
    551716
    552717    UIListBtnTypeItem* item;
     
    554719    item->setData(new Action(&IconView::actionSlideShow));
    555720    item = new UIListBtnTypeItem(m_menuType, tr("Random"));
    556721    item->setData(new Action(&IconView::actionRandomShow));
    557     item = new UIListBtnTypeItem(m_menuType, tr("Rotate CW"));
    558     item->setData(new Action(&IconView::actionRotateCW));
    559     item = new UIListBtnTypeItem(m_menuType, tr("Rotate CCW"));
    560     item->setData(new Action(&IconView::actionRotateCCW));
    561     item = new UIListBtnTypeItem(m_menuType, tr("Delete"));
    562     item->setData(new Action(&IconView::actionDelete));
    563     item = new UIListBtnTypeItem(m_menuType, tr("Import"));
    564     item->setData(new Action(&IconView::actionImport));
     722    item = new UIListBtnTypeItem(m_menuType, tr("Meta Data..."));
     723    item->setData(new Action(&IconView::actionSubMenuMetadata));
     724    item = new UIListBtnTypeItem(m_menuType, tr("Marking..."));
     725    item->setData(new Action(&IconView::actionSubMenuMark));
     726    item = new UIListBtnTypeItem(m_menuType, tr("File..."));
     727    item->setData(new Action(&IconView::actionSubMenuFile));
    565728    item = new UIListBtnTypeItem(m_menuType, tr("Settings"));
    566729    item->setData(new Action(&IconView::actionSettings));
    567730   
     
    618781        m_folderSelPix = QPixmap(*img);
    619782        delete img;
    620783
     784        img = gContext->LoadScaleImage("gallery-mark.png");
     785        if (!img) {
     786            std::cerr << "Failed to load gallery-mark.png"
     787                      << std::endl;
     788            exit(-1);
     789        }
     790        m_MrkPix = QPixmap(*img);
     791        delete img;
     792
    621793        m_thumbW = m_backRegPix.width();
    622794        m_thumbH = m_backRegPix.height();
    623795        m_nCols  = m_viewRect.width()/m_thumbW - 1;
     
    634806    if (!d.exists())
    635807        return;
    636808
     809    m_showDevices = false;
     810
    637811    m_currDir = d.absPath();
    638812    m_itemList.clear();
    639813    m_itemDict.clear();
     
    778952
    779953void IconView::pressMenu()
    780954{
    781     UIListBtnTypeItem* item = m_menuType->GetItemCurrent();
     955    UIListBtnTypeItem* item;
    782956
     957    if (m_inSubMenu)
     958        item = m_submenuType->GetItemCurrent();
     959    else
     960        item = m_menuType->GetItemCurrent();
     961
    783962    if (!item || !item->getData())
    784963        return;
    785964
    786965    Action *act = (Action*) item->getData();
    787966    (this->*(*act))();
     967
     968    m_menuType->SetActive(m_inMenu & !m_inSubMenu);
     969    m_submenuType->SetActive(m_inMenu & m_inSubMenu);
    788970}
    789971
     972void IconView::actionMainMenu()
     973{
     974    clearMenu(m_submenuType);
     975    m_submenuType->Reset();
     976
     977    m_inSubMenu = false;
     978}
     979
     980void IconView::actionSubMenuMetadata()
     981{
     982    clearMenu(m_submenuType);
     983    m_submenuType->Reset();
     984
     985    UIListBtnTypeItem *item;
     986    item = new UIListBtnTypeItem(m_submenuType, tr("Return"));
     987    item->setData(new Action(&IconView::actionMainMenu));
     988    item = new UIListBtnTypeItem(m_submenuType, tr("Rotate CW"));
     989    item->setData(new Action(&IconView::actionRotateCW));
     990    item = new UIListBtnTypeItem(m_submenuType, tr("Rotate CCW"));
     991    item->setData(new Action(&IconView::actionRotateCCW));
     992
     993    m_inSubMenu = true;
     994}
     995
     996void IconView::actionSubMenuMark()
     997{
     998    clearMenu(m_submenuType);
     999    m_submenuType->Reset();
     1000
     1001    UIListBtnTypeItem *item;
     1002    item = new UIListBtnTypeItem(m_submenuType, tr("Return"));
     1003    item->setData(new Action(&IconView::actionMainMenu));
     1004    item = new UIListBtnTypeItem(m_submenuType, tr("Clear Marked"));
     1005    item->setData(new Action(&IconView::actionClearMarked));
     1006    item = new UIListBtnTypeItem(m_submenuType, tr("Select All"));
     1007    item->setData(new Action(&IconView::actionSelectAll));
     1008
     1009    m_inSubMenu = true;
     1010}
     1011
     1012void IconView::actionSubMenuFile()
     1013{
     1014    clearMenu(m_submenuType);
     1015    m_submenuType->Reset();
     1016
     1017    UIListBtnTypeItem *item;
     1018    item = new UIListBtnTypeItem(m_submenuType, tr("Return"));
     1019    item->setData(new Action(&IconView::actionMainMenu));
     1020    item = new UIListBtnTypeItem(m_submenuType, tr("Show Devices"));
     1021    item->setData(new Action(&IconView::actionShowDevices));
     1022    item = new UIListBtnTypeItem(m_submenuType, tr("Import"));
     1023    item->setData(new Action(&IconView::actionImport));
     1024    item = new UIListBtnTypeItem(m_submenuType, tr("Copy here"));
     1025    item->setData(new Action(&IconView::actionCopyHere));
     1026    item = new UIListBtnTypeItem(m_submenuType, tr("Move here"));
     1027    item->setData(new Action(&IconView::actionMoveHere));
     1028    item = new UIListBtnTypeItem(m_submenuType, tr("Delete"));
     1029    item->setData(new Action(&IconView::actionDelete));
     1030    item = new UIListBtnTypeItem(m_submenuType, tr("Create Dir"));
     1031    item->setData(new Action(&IconView::actionMkDir));
     1032
     1033    m_inSubMenu = true;
     1034}
     1035
    7901036void IconView::actionRotateCW()
    7911037{
    7921038    ThumbItem* item = m_itemList.at(m_currRow * m_nCols +
     
    8331079    }
    8341080}
    8351081
    836 void IconView::actionDelete()
     1082void IconView::actionDeleteCurrent()
    8371083{
    838     ThumbItem* item = m_itemList.at(m_currRow * m_nCols +
    839                                     m_currCol);
    840     if (!item || item->isDir)
     1084    ThumbItem* item = m_itemList.at(m_currRow * m_nCols + m_currCol);
     1085
     1086    if (!item)
    8411087        return;
    8421088
    843     if( item->Remove() ) {
    844         loadDirectory(m_currDir, false);
     1089    bool cont = MythPopupBox::showOkCancelPopup(gContext->GetMainWindow(),
     1090                    tr("Delete Current File or Folder"),
     1091                    (item->isDir) ?
     1092                        QString(tr("Deleting 1 folder, including any "
     1093                                   "subfolders and files.")) :
     1094                        QString(tr("Deleting 1 image.")),
     1095                    false);
     1096
     1097    if (cont)
     1098    {
     1099        QFileInfo fi;
     1100        fi.setFile(item->path);
     1101        GalleryUtil::Delete(fi);
     1102
     1103        loadDirectory(m_currDir);
    8451104    }
    8461105}
    8471106
     
    9801239    }
    9811240}
    9821241
     1242void IconView::actionShowDevices()
     1243{
     1244#ifndef _WIN32
     1245    MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
     1246    if (m_currDevice && mon && mon->ValidateAndLock(m_currDevice))
     1247    {
     1248        m_currDevice->disconnect(this);
     1249        mon->Unlock(m_currDevice);
     1250    }
     1251#endif
     1252
     1253    m_currDevice = NULL;
     1254
     1255    m_showDevices = true;
     1256
     1257    m_itemList.clear();
     1258    m_itemDict.clear();
     1259
     1260    m_thumbGen->cancel();
     1261
     1262    // add gallery directory
     1263    ThumbItem *item = new ThumbItem;
     1264    item->name = QString("Gallery");
     1265    item->path = m_galleryDir;
     1266    item->isDir = true;
     1267    m_itemList.append(item);
     1268    m_itemDict.insert(item->name, item);
     1269
     1270#ifndef _WIN32
     1271    if (mon)
     1272    {
     1273        QValueList<MythMediaDevice*> removables = mon->GetMedias(MEDIATYPE_DATA);
     1274        QValueList<MythMediaDevice*>::Iterator it = removables.begin();
     1275        for (; it != removables.end(); it++)
     1276        {
     1277            if (mon->ValidateAndLock(*it))
     1278            {
     1279                item = new ThumbItem;
     1280                if ((*it)->getVolumeID() != "")
     1281                    item->name = (*it)->getVolumeID();
     1282                else
     1283                    item->name = (*it)->getDevicePath();
     1284                item->path = (*it)->getMountPath();
     1285                item->isDir = true;
     1286                item->mediaDevice = *it;
     1287                m_itemList.append(item);
     1288                m_itemDict.insert(item->name, item);
     1289
     1290                mon->Unlock(*it);
     1291            }
     1292        }
     1293    }
     1294#endif
     1295
     1296    m_lastRow = QMAX((int)ceilf((float)m_itemList.count()/(float)m_nCols)-1,0);
     1297    m_lastCol = QMAX(m_itemList.count()-m_lastRow*m_nCols-1,0);
     1298}
     1299
     1300void IconView::actionCopyHere()
     1301{
     1302    CopyMarkedFiles(false);
     1303    actionClearMarked();
     1304}
     1305
     1306void IconView::actionMoveHere()
     1307{
     1308    CopyMarkedFiles(true);
     1309    actionClearMarked();
     1310}
     1311
     1312void IconView::actionDelete()
     1313{
     1314    if (m_itemMarked.isEmpty())
     1315        actionDeleteCurrent();
     1316    else
     1317        actionDeleteMarked();
     1318}
     1319
     1320void IconView::actionDeleteMarked()
     1321{
     1322    bool cont = MythPopupBox::showOkCancelPopup(gContext->GetMainWindow(),
     1323                    tr("Delete Marked Files"),
     1324                    QString(tr("Deleting %1 images and folders, including "
     1325                               "any subfolders and files."))
     1326                            .arg(m_itemMarked.count()),
     1327                    false);
     1328
     1329    if (cont)
     1330    {
     1331        QStringList::iterator it;
     1332        QFileInfo fi;
     1333
     1334        for (it = m_itemMarked.begin(); it != m_itemMarked.end(); it++)
     1335        {
     1336            fi.setFile(*it);
     1337
     1338            GalleryUtil::Delete(fi);
     1339        }
     1340
     1341        m_itemMarked.clear();
     1342
     1343        loadDirectory(m_currDir);
     1344    }
     1345}
     1346
     1347void IconView::actionClearMarked()
     1348{
     1349    m_itemMarked.clear();
     1350}
     1351
     1352void IconView::actionSelectAll()
     1353{
     1354    ThumbItem *item;
     1355    for (item = m_itemList.first(); item; item = m_itemList.next())
     1356    {
     1357        if (!m_itemMarked.contains(item->path))
     1358            m_itemMarked.append(item->path);
     1359    }
     1360}
     1361
     1362void IconView::actionMkDir()
     1363{
     1364    QString folderName = tr("New Folder");
     1365
     1366    bool res = MythPopupBox::showGetTextPopup(gContext->GetMainWindow(), tr("Create New Folder"),
     1367                                              tr("Create New Folder"), folderName);
     1368
     1369    if (res)
     1370    {
     1371        QDir cdir(m_currDir);
     1372        cdir.mkdir(folderName);
     1373
     1374        loadDirectory(m_currDir);
     1375    }
     1376}
     1377
    9831378void IconView::importFromDir(const QString &fromDir, const QString &toDir)
    9841379{
    9851380    QDir d(fromDir);
     
    10191414        }
    10201415    }
    10211416}
     1417
     1418void IconView::CopyMarkedFiles(bool move)
     1419{
     1420    if (m_itemMarked.isEmpty())
     1421        return;
     1422
     1423    QStringList::iterator it;
     1424    QFileInfo fi;
     1425    QFileInfo dest;
     1426    int count = 0;
     1427
     1428
     1429    MythProgressDialog *progress =
     1430        new MythProgressDialog((move) ? tr("Moving marked images...") :
     1431                                        tr("Copying marked images..."),
     1432                               m_itemMarked.count());
     1433
     1434    for (it = m_itemMarked.begin(); it != m_itemMarked.end(); it++)
     1435    {
     1436        fi.setFile(*it);
     1437        dest.setFile(QDir(m_currDir), fi.fileName());
     1438
     1439        if (fi.exists())
     1440            GalleryUtil::CopyMove(fi, dest, move);
     1441
     1442        progress->setProgress(++count);
     1443    }
     1444
     1445    progress->Close();
     1446    delete progress;
     1447
     1448    loadDirectory(m_currDir);
     1449}
     1450
     1451void IconView::clearMenu(UIListBtnType *menu)
     1452{
     1453    UIListBtnTypeItem* item = menu->GetItemFirst();
     1454    while (item)
     1455    {
     1456        Action *act = (Action*) item->getData();
     1457        if (act)
     1458            delete act;
     1459        item = menu->GetItemNext(item);
     1460    }
     1461}
     1462
     1463void IconView::mediaStatusChanged(MediaStatus oldStatus,
     1464                                  MythMediaDevice *pMedia)
     1465{
     1466    (void) oldStatus;
     1467    if (m_currDevice == pMedia)
     1468    {
     1469        actionShowDevices();
     1470
     1471        m_currRow = 0;
     1472        m_currCol = 0;
     1473
     1474        updateView();
     1475        updateText();
     1476    }
     1477}
  • mythgallery/mythgallery/main.cpp

     
    1414#include <mythtv/mythdialogs.h>
    1515#include <mythtv/mythplugin.h>
    1616#include <mythtv/dialogbox.h>
     17#include <mythtv/mythmedia.h>
    1718
    1819extern "C" {
    1920int mythplugin_init(const char *libversion);
     
    3334        diag.AddButton(QObject::tr("Ok"));
    3435        diag.exec();
    3536    }
    36     else {
    37         IconView icv(startdir, gContext->GetMainWindow(), "IconView");
     37    else
     38    {
     39        IconView icv(startdir, NULL, gContext->GetMainWindow(), "IconView");
    3840        icv.exec();
    3941    }
    4042    gContext->removeCurrentLocation();
    4143}
    4244
     45void handleMedia(MythMediaDevice *dev)
     46{
     47    QString galleryDir = gContext->GetSetting("GalleryDir");
     48    QDir dir(galleryDir);
     49    if (!dir.exists() || !dir.isReadable())
     50    {
     51        DialogBox diag(gContext->GetMainWindow(),
     52                       QObject::tr("Gallery Directory does not "
     53                                   "exist or is unreadable."));
     54        diag.AddButton(QObject::tr("Ok"));
     55        diag.exec();
     56    }
     57    else
     58    {
     59        IconView icv(galleryDir, dev, gContext->GetMainWindow(), "IconView");
     60        icv.exec();
     61    }
     62}
     63
     64
    4365void setupKeys(void)
    4466{
    4567    REG_JUMP("MythGallery", "Image viewer / slideshow", "", runGallery);
     
    6789    REG_KEY("Gallery", "LOWRIGHT", "Go to the lower-right corner of the image",
    6890            "PgDown");
    6991    REG_KEY("Gallery", "INFO", "Toggle Showing Information about Image", "I");
    70     REG_KEY("Gallery", "DELETE", "Delete current image", "D");
     92    REG_KEY("Gallery", "DELETE", "Delete marked images or current image if none are marked", "D");
     93    REG_KEY("Gallery", "MARK", "Mark image", "T");
     94
     95    REG_MEDIA_HANDLER("MythGallery Media Handler", "", "", handleMedia, MEDIATYPE_DATA | MEDIATYPE_MIXED);
    7196}
    7297
    7398int mythplugin_init(const char *libversion)
  • mythgallery/mythgallery/thumbgenerator.cpp

     
    308308
    309309QString ThumbGenerator::getThumbcacheDir(const QString& inDir)
    310310{
     311    QString galleryDir = gContext->GetSetting("GalleryDir");
     312
    311313    // For directory "/my/images/january", this function either returns
    312314    // "/my/images/january/.thumbcache" or "~/.mythtv/mythgallery/january/.thumbcache"
    313315    QString aPath = inDir + QString("/.thumbcache/");
    314316    if ( gContext->GetNumSetting("GalleryThumbnailLocation")
    315             && ! QDir(aPath).exists() )
     317            && ! QDir(aPath).exists() && inDir.startsWith(galleryDir))
    316318    {
    317319        mkpath(aPath);
    318320    }
    319     if ( ! gContext->GetNumSetting("GalleryThumbnailLocation") || ! QDir(aPath).exists() )
     321    if ( ! gContext->GetNumSetting("GalleryThumbnailLocation") || ! QDir(aPath).exists() || ! inDir.startsWith(galleryDir))
    320322    {
    321323        // Arrive here if storing thumbs in home dir,
    322324        // OR failed to create thumb dir in gallery pics location
  • mythgallery/mythgallery/iconview.h

     
    2626#include <qpixmap.h>
    2727
    2828#include <mythtv/mythdialogs.h>
     29#include <mythtv/mythmedia.h>
    2930
    3031class XMLParse;
    3132class UIListBtnType;
     
    4243        caption= "";
    4344        path   = "";
    4445        isDir  = false;
     46        mediaDevice = NULL;
    4547    }
    4648
    4749    ~ThumbItem() {
     
    5860    QString  caption;
    5961    QString  path;
    6062    bool     isDir;
     63    MythMediaDevice *mediaDevice;
    6164};
    6265
    6366typedef QPtrList<ThumbItem> ThumbList;
     
    6972
    7073public:
    7174
    72     IconView(const QString& galleryDir, MythMainWindow* parent,
    73              const char* name = 0);
     75    IconView(const QString& galleryDir, MythMediaDevice *initialDevice,
     76             MythMainWindow* parent, const char* name = 0);
    7477    ~IconView();
    7578
    7679protected:
     
    9396    bool moveLeft();
    9497    bool moveRight();
    9598
     99    void actionMainMenu();
     100    void actionSubMenuMetadata();
     101    void actionSubMenuMark();
     102    void actionSubMenuFile();
     103
    96104    void actionRotateCW();
    97105    void actionRotateCCW();
    98     void actionDelete();
     106    void actionDeleteCurrent();
    99107    void actionSlideShow();
    100108    void actionRandomShow();
    101109    void actionSettings();
    102110    void actionImport();
     111#ifndef _WIN32
     112    void actionShowDevices();
     113#endif
     114    void actionCopyHere();
     115    void actionMoveHere();
     116    void actionDelete();
     117    void actionDeleteMarked();
     118    void actionClearMarked();
     119    void actionSelectAll();
     120    void actionMkDir();
    103121
    104122    void pressMenu();
    105123
    106124    void loadThumbnail(ThumbItem *item);
    107125    void importFromDir(const QString &fromDir, const QString &toDir);
     126    void CopyMarkedFiles(bool move = false);
     127
     128    void clearMenu(UIListBtnType *menu);
    108129   
    109130    QPtrList<ThumbItem> m_itemList;
    110131    QDict<ThumbItem>    m_itemDict;
     132    QStringList         m_itemMarked;
    111133    QString             m_galleryDir;
    112134
    113135    XMLParse           *m_theme;
     
    116138    QRect               m_viewRect;
    117139
    118140    bool                m_inMenu;
     141    bool                m_inSubMenu;
    119142    UIListBtnType      *m_menuType;
     143    UIListBtnType      *m_submenuType;
    120144   
    121145    QPixmap             m_backRegPix;
    122146    QPixmap             m_backSelPix;
    123147    QPixmap             m_folderRegPix;
    124148    QPixmap             m_folderSelPix;
     149    QPixmap             m_MrkPix;
    125150
    126151    QString             m_currDir;
    127152    bool                m_isGallery;
     153    bool                m_showDevices;
     154    MythMediaDevice    *m_currDevice;
    128155
    129156    int                 m_currRow;
    130157    int                 m_currCol;
     
    143170    int                 m_showcaption;
    144171
    145172    typedef void (IconView::*Action)();
     173
     174public slots:
     175    void mediaStatusChanged( MediaStatus oldStatus, MythMediaDevice* pMedia);
    146176};
    147177
    148178
  • mythgallery/mythgallery/gallery-ui.xml

     
    2121    </font>
    2222
    2323    <container name="menu">
    24       <area>20,20,140,240</area>
     24      <area>20,20,140,500</area>
    2525
    2626      <listbtnarea name="menu" draworder="0">
    2727        <area>0,0,140,240</area>
     
    3535        <showscrollarrows>no</showscrollarrows>
    3636      </listbtnarea>
    3737
     38      <listbtnarea name="submenu" draworder="0">
     39        <area>0,260,140,240</area>
     40        <gradient type="unselected" start="#000000" end="#505050" alpha="100">
     41        </gradient>
     42        <gradient type="selected" start="#52CA38" end="#349838" alpha="255">
     43        </gradient>
     44        <fcnfont name="active" function="active"></fcnfont>
     45        <fcnfont name="inactive" function="inactive"></fcnfont>
     46        <showarrow>no</showarrow>
     47        <showscrollarrows>no</showscrollarrows>
     48      </listbtnarea>
     49
    3850    </container>
    3951
    4052    <container name="text">
  • mythgallery/mythgallery/galleryutil.cpp

     
    1616 *
    1717 * ============================================================ */
    1818
    19 #include <iostream>
    2019#include <qfileinfo.h>
    2120#include <qdir.h>
    2221
     22#include <mythtv/mythcontext.h>
     23#include <mythtv/mythdbcon.h>
     24#include <mythtv/util.h>
     25
    2326#include "config.h"
    2427#include "constants.h"
    2528#include "galleryutil.h"
     
    3134// include "exif.hpp"
    3235#endif // EXIF_SUPPORT
    3336
     37#define LOC QString("GalleryUtil:")
     38#define LOC_ERR QString("GalleryUtil, Error:")
     39
     40static QFileInfo MakeUnique(const QFileInfo &dest);
     41static QFileInfo MakeUniqueDirectory(const QFileInfo &dest);
     42static bool FileCopy(const QFileInfo &src, const QFileInfo &dst);
     43static bool FileMove(const QFileInfo &src, const QFileInfo &dst);
     44static bool FileDelete(const QFileInfo &file);
     45
    3446bool GalleryUtil::isImage(const char* filePath)
    3547{
    3648    QFileInfo fi(filePath);
     
    8193        }
    8294        else
    8395        {
    84                 std::cerr << "Could not load exif data from " << filePath << std::endl;
     96            VERBOSE(VB_IMPORTANT, LOC_ERR +
     97                    QString("Could not load exif data from '%1'")
     98                    .arg(filePath));
    8599        }
    86100       
    87101        delete [] exifvalue;
     
    115129    }
    116130    catch (...)
    117131    {
    118         std::cerr << "GalleryUtil: Failed to extract EXIF headers from "
    119         << filePath << std::endl;
     132        VERBOSE(VB_IMPORTANT, LOC_ERR +
     133                QString("Failed to extract EXIF headers from '%1'")
     134                .arg(filePath));
    120135    }
    121136
    122137    return rotateAngle;
     
    249264        }
    250265        else
    251266        {
    252            std::cerr << "Could not load exif data from " << filePath << std::endl;
     267           VERBOSE(VB_IMPORTANT, LOC_ERR +
     268                   QString("Could not load exif data from '%1'")
     269                   .arg(filePath));
    253270        }
    254271       
    255272        delete [] exifvalue;
     
    257274    }
    258275    catch (...)
    259276    {
    260         std::cerr << "GalleryUtil: Failed to extract EXIF headers from "
    261         << filePath << std::endl;
     277        VERBOSE(VB_IMPORTANT, LOC_ERR +
     278                QString("Failed to extract EXIF headers from '%1'")
     279                .arg(filePath));
    262280    }
    263281
    264282    return caption;
    265283}
     284
     285bool GalleryUtil::Copy(const QFileInfo &src, QFileInfo &dst)
     286{
     287    if (src.isDir())
     288        return CopyDirectory(src, dst);
     289
     290    dst = MakeUnique(dst);
     291
     292    if (!FileCopy(src, dst))
     293        return false;
     294
     295    MSqlQuery query(MSqlQuery::InitCon());
     296    query.prepare("INSERT INTO gallerymetadata (image, keywords, angle) "
     297                  "SELECT :IMAGENEW , keywords, angle "
     298                  "FROM gallerymetadata "
     299                  "WHERE image = :IMAGEOLD");
     300    query.bindValue(":IMAGENEW", dst.absFilePath().utf8());
     301    query.bindValue(":IMAGEOLD", src.absFilePath().utf8());
     302    if (query.exec())
     303        return true;
     304
     305    // try to undo copy on DB failure
     306    FileDelete(dst);
     307    return false;
     308}
     309
     310bool GalleryUtil::Move(const QFileInfo &src, QFileInfo &dst)
     311{
     312    if (src.isDir())
     313        return MoveDirectory(src, dst);
     314
     315    dst = MakeUnique(dst);
     316
     317    if (!FileMove(src, dst))
     318        return false;
     319
     320    MSqlQuery query(MSqlQuery::InitCon());
     321    query.prepare("UPDATE gallerymetadata "
     322                  "SET image = :IMAGENEW "
     323                  "WHERE image = :IMAGEOLD");
     324    query.bindValue(":IMAGENEW", dst.absFilePath().utf8());
     325    query.bindValue(":IMAGEOLD", src.absFilePath().utf8());
     326    if (query.exec())
     327        return true;
     328
     329    // try to undo move on DB failure
     330    FileMove(dst, src);
     331    return false;
     332}
     333
     334bool GalleryUtil::Delete(const QFileInfo &file)
     335{
     336    if (!file.exists())
     337        return false;
     338
     339    if (file.isDir())
     340        return DeleteDirectory(file);
     341
     342    MSqlQuery query(MSqlQuery::InitCon());
     343    query.prepare("DELETE FROM gallerymetadata "
     344                  "WHERE image = :IMAGE ;");
     345    query.bindValue(":IMAGE", file.absFilePath().utf8());
     346    if (query.exec())
     347        return FileDelete(file);
     348
     349    return false;
     350}
     351
     352bool GalleryUtil::CopyDirectory(const QFileInfo src, QFileInfo &dst)
     353{
     354    QDir srcDir(src.absFilePath());
     355
     356    dst = MakeUniqueDirectory(dst);
     357    if (!dst.exists())
     358    {
     359        srcDir.mkdir(dst.absFilePath());
     360        dst.refresh();
     361    }
     362
     363    if (!dst.exists() || !dst.isDir())
     364        return false;
     365
     366    bool ok = true;
     367    QDir dstDir(dst.absFilePath());
     368    QFileInfoListIterator it(*srcDir.entryInfoList());
     369    for (; it.current(); ++it)
     370    {
     371        const QString fn = (it.current())->fileName();
     372        if (fn != "." && fn != "..")
     373        {
     374            QFileInfo dfi(dstDir, fn);
     375            ok &= Copy(*(it.current()), dfi);
     376        }
     377    }
     378
     379    return ok;
     380}
     381
     382bool GalleryUtil::MoveDirectory(const QFileInfo src, QFileInfo &dst)
     383{
     384    QDir srcDir(src.absFilePath());
     385
     386    dst = MakeUniqueDirectory(dst);
     387    if (!dst.exists())
     388    {
     389        srcDir.mkdir(dst.absFilePath());
     390        dst.refresh();
     391    }
     392
     393    if (!dst.exists() || !dst.isDir())
     394        return false;
     395
     396    bool ok = true;
     397    QDir dstDir(dst.absFilePath());
     398    QFileInfoListIterator it(*srcDir.entryInfoList());
     399    for (; it.current(); ++it)
     400    {
     401        const QString fn = (it.current())->fileName();
     402        if (fn != "." && fn != "..")
     403        {
     404            QFileInfo dfi(dstDir, fn);
     405            ok &= Move(*(it.current()), dfi);
     406        }
     407    }
     408
     409    return ok && FileDelete(src);
     410}
     411
     412bool GalleryUtil::DeleteDirectory(const QFileInfo &dir)
     413{
     414    if (!dir.exists())
     415        return false;
     416
     417    QDir srcDir(dir.absFilePath());
     418    QFileInfoListIterator it(*srcDir.entryInfoList());
     419    for (; it.current(); ++it)
     420    {
     421        const QString fn = (it.current())->fileName();
     422        if (fn != "." && fn != "..")
     423            Delete(*(it.current()));
     424    }
     425
     426    return FileDelete(dir);
     427}
     428
     429static QFileInfo MakeUnique(const QFileInfo &dest)
     430{
     431    QFileInfo newDest = dest;
     432
     433    for (uint i = 0; newDest.exists(); i++)
     434    {
     435        QString basename = QString("%1_%2.%3")
     436            .arg(dest.baseName(false)).arg(i).arg(dest.extension());
     437
     438        newDest.setFile(dest.dir(), basename);
     439
     440        VERBOSE(VB_GENERAL, LOC_ERR +
     441                QString("Need to find a new name for '%1' trying '%2'")
     442                .arg(dest.absFilePath()).arg(newDest.absFilePath()));
     443    }
     444
     445    return newDest;
     446}
     447
     448static QFileInfo MakeUniqueDirectory(const QFileInfo &dest)
     449{
     450    QFileInfo newDest = dest;
     451
     452    for (uint i = 0; newDest.exists() && !newDest.isDir(); i++)
     453    {
     454        QString fullname = QString("%1_%2").arg(dest.absFilePath()).arg(i);
     455        newDest.setFile(fullname);
     456
     457        VERBOSE(VB_GENERAL, LOC_ERR +
     458                QString("Need to find a new name for '%1' trying '%2'")
     459                .arg(dest.absFilePath()).arg(newDest.absFilePath()));
     460    }
     461
     462    return newDest;
     463}
     464
     465static bool FileCopy(const QFileInfo &src, const QFileInfo &dst)
     466{
     467    const int bufferSize = 16*1024;
     468
     469    QFile s(src.absFilePath());
     470    QFile d(dst.absFilePath());
     471    char buffer[bufferSize];
     472    int len;
     473
     474    if (!s.open(IO_ReadOnly))
     475        return false;
     476
     477    if (!d.open(IO_WriteOnly))
     478    {
     479        s.close();
     480        return false;
     481    }
     482
     483    len = s.readBlock(buffer, bufferSize);
     484    do
     485    {
     486        d.writeBlock(buffer, len);
     487        len = s.readBlock(buffer, bufferSize);
     488    } while (len > 0);
     489
     490    s.close();
     491    d.close();
     492
     493    return true;
     494}
     495
     496static bool FileMove(const QFileInfo &src, const QFileInfo &dst)
     497{
     498    // attempt to rename the file,
     499    // this will fail if files are on different partitions
     500    if (rename(src.absFilePath().local8Bit(),
     501               dst.absFilePath().local8Bit()) == 0)
     502        return true;
     503
     504    // src and dst are on different mount points, move manually.
     505    if (errno == EXDEV)
     506    {
     507        if (FileCopy(src, dst))
     508            return FileDelete(src);
     509    }
     510
     511    return false;
     512}
     513
     514static bool FileDelete(const QFileInfo &file)
     515{
     516    if (!file.isDir())
     517        return QFile::remove(file.absFilePath());
     518
     519    // delete .thumbcache
     520    QDir srcDir(file.absFilePath());
     521    QFileInfo tc(srcDir, ".thumbcache");
     522    GalleryUtil::Delete(tc);
     523
     524    srcDir.rmdir(srcDir.absPath());
     525
     526    return true;
     527}
     528
     529// Allow wholesale clearing of marks
     530// Exit "Show Devices" on exit from submenu
     531// Avoid using #define and #ifdef when possible.
  • mythvideo/mythvideo/videolist.cpp

     
    286286        while(itr != medias.end())
    287287        {
    288288            pDev = *itr;
    289             if (pDev)
     289            if (mon->ValidateAndLock(pDev))
    290290            {
    291291                QString path = pDev->getMountPath();
    292292                QString name = path.right(path.length()
    293293                                                - path.findRev("/")-1);
    294294                nodespath.append(path);
    295295                nodesname.append(name);
     296
     297                mon->Unlock(pDev);
    296298            }
    297299            itr++;
    298300        }