Index: mythgallery/mythgallery/galleryutil.h
===================================================================
--- mythgallery/mythgallery/galleryutil.h	(revision 7775)
+++ mythgallery/mythgallery/galleryutil.h	(working copy)
@@ -32,6 +32,11 @@
     static bool loadDirectory(ThumbList& itemList,
                               const QString& dir, bool recurse,
                               ThumbDict *itemDict, ThumbGenerator* thumbGen);
+
+    static QFileInfo copyFile(QFileInfo src, QFileInfo dest, bool move);
+    static bool deleteFile(QFileInfo file);
+    static QFileInfo copyDirectory(QFileInfo src, QFileInfo dest, bool move);
+    static bool deleteDirectory(QFileInfo dir);
 };
 
 #endif /* EXIFUTIL_H */
Index: mythgallery/mythgallery/iconview.cpp
===================================================================
--- mythgallery/mythgallery/iconview.cpp	(revision 7775)
+++ mythgallery/mythgallery/iconview.cpp	(working copy)
@@ -31,6 +31,8 @@
 #include <mythtv/xmlparse.h>
 #include <mythtv/dialogbox.h>
 #include <mythtv/mythdbcon.h>
+#include <mythtv/mythmediamonitor.h>
+#include <mythtv/mythdialogs.h>
 
 #include "galleryutil.h"
 #include "gallerysettings.h"
@@ -72,13 +74,14 @@
     query.exec();
 }
 
-IconView::IconView(const QString& galleryDir, MythMainWindow* parent, 
-                   const char* name )
+IconView::IconView(const QString& galleryDir, MythMediaDevice *initialDevice,
+                   MythMainWindow* parent, const char* name )
     : MythDialog(parent, name)
 {
     m_galleryDir = galleryDir;    
 
     m_inMenu     = false;
+    m_inSubMenu = false;
     m_itemList.setAutoDelete(true);
     m_itemDict.setAutoDelete(false);
 
@@ -94,20 +97,32 @@
     m_lastCol = 0;
     m_topRow  = 0;
     m_isGallery  = false;
+#ifndef _WIN32
+    m_showDevices = false;
+    m_currDevice = initialDevice;
+#endif
 
-    loadDirectory(galleryDir);
+#ifndef _WIN32
+    if (m_currDevice)
+    {
+        if (!m_currDevice->isMounted(true))
+            m_currDevice->mount();
+
+        connect(m_currDevice, SIGNAL(statusChanged(MediaStatus, MythMediaDevice*)),
+                              SLOT(mediaStatusChanged(MediaStatus, MythMediaDevice*)));
+
+        loadDirectory(m_currDevice->getMountPath());
+    }
+    else
+#endif
+        loadDirectory(galleryDir);
 }
 
 IconView::~IconView()
 {
-    UIListBtnTypeItem* item = m_menuType->GetItemFirst();
-    while (item) {
-        Action *act = (Action*) item->getData();
-        if (act)
-            delete act;
-        item = m_menuType->GetItemNext(item);
-    }
-    
+    clearMenu(m_submenuType);
+    clearMenu(m_menuType);
+
     delete m_thumbGen;
     delete m_theme;
 }
@@ -232,6 +247,11 @@
                                  item->pixmap->height()/2-bh2+sh,
                                  bw-2*sw, bh-2*sh-(int)(15*hmult));
 
+                if (m_itemMarked.contains(item->path))
+                {
+                    p.drawPixmap(xpos, ypos, m_MrkPix);
+                }
+
             }
             else {
 
@@ -246,6 +266,11 @@
                                  item->pixmap->width()/2-bw2+sw,
                                  item->pixmap->height()/2-bh2+sh,
                                  bw-2*sw, bh-2*sh);
+
+                if (m_itemMarked.contains(item->path))
+                {
+                    p.drawPixmap(xpos, ypos, m_MrkPix);
+                }
             }
            
             curPos++;
@@ -273,22 +298,31 @@
         QString action = actions[i];
         if (action == "MENU") {
             m_inMenu = !m_inMenu;
-            m_menuType->SetActive(m_inMenu);
+            m_menuType->SetActive(m_inMenu & !m_inSubMenu);
+            m_submenuType->SetActive(m_inMenu & m_inSubMenu);
             menuHandled = true;
         }
         else if (action == "UP") {
-            if (m_inMenu) {
+            if (m_inMenu & !m_inSubMenu) {
                 m_menuType->MoveUp();
                 menuHandled = true;
             }
+            else if (m_inMenu & m_inSubMenu) {
+                m_submenuType->MoveUp();
+                menuHandled = true;
+            }
             else
                 handled = moveUp();
         }
         else if (action == "DOWN") {
-            if (m_inMenu) {
+            if (m_inMenu & !m_inSubMenu) {
                 m_menuType->MoveDown();
                 menuHandled = true;
             }
+            else if (m_inMenu & m_inSubMenu) {
+                m_submenuType->MoveDown();
+                menuHandled = true;
+            }
             else
                 handled = moveDown();
         }
@@ -322,6 +356,24 @@
             m_topRow  = QMAX(m_currRow-(m_nRows-1),0);
             handled = true;
         }
+        else if (action == "MARK")
+        {
+            int pos = m_currRow * m_nCols + m_currCol;
+            ThumbItem *item = m_itemList.at(pos);
+            if (!item) {
+                std::cerr << "The impossible happened" << std::endl;
+                break;
+            }
+
+            std::cout << "(un)marking " << item->path.ascii() << std::endl;
+
+            if (!m_itemMarked.contains(item->path))
+                m_itemMarked.append(item->path);
+            else
+                m_itemMarked.remove(item->path);
+
+            handled = true;
+        }
         else if (action == "SELECT" || action == "PLAY")
         {
             if (m_inMenu) {
@@ -337,6 +389,20 @@
                 }
         
                 QFileInfo fi(item->path);
+#ifndef _WIN32
+                if (item->mediaDevice)
+                {
+                    m_currDevice = item->mediaDevice;
+
+                    if (!m_currDevice->isMounted())
+                        m_currDevice->mount();
+
+                    item->path = m_currDevice->getMountPath();
+
+                    connect(m_currDevice, SIGNAL(statusChanged(MediaStatus, MythMediaDevice*)),
+                                          SLOT(mediaStatusChanged(MediaStatus, MythMediaDevice*)));
+                }
+#endif
                 if (item->isDir) {
                     loadDirectory(item->path);
                     handled = true;
@@ -380,25 +446,75 @@
         {
             QString action = actions[i];
             if (action == "ESCAPE") {
-                QDir d(m_currDir);
-                if (d != QDir(m_galleryDir)) {
+#ifndef _WIN32
+                if (m_showDevices)
+                {
+                    loadDirectory(m_galleryDir);
+                    handled = true;
+                }
+                else
+                {
+#endif
+                    QDir d(m_currDir);
+#ifndef _WIN32
+                    MediaMonitor *mon = MediaMonitor::getMediaMonitor();
+                    if (mon)
+                    {
+                        QValueList <MythMediaDevice *> removables = mon->getMedias(MEDIATYPE_DATA);
+                        QValueList <MythMediaDevice *>::Iterator it = removables.begin();
+                        for (; it != removables.end(); it++)
+                        {
+                            if (d == QDir((*it)->getMountPath()))
+                            {
+                                actionShowDevices();
 
-                    QString oldDirName = d.dirName();
-                    d.cdUp();
-                    loadDirectory(d.absPath());
+                                // make sure previous devies is visible and selected
+                                ThumbItem *item;
+                                if ((*it)->getVolumeID() != "")
+                                    item = m_itemDict.find((*it)->getVolumeID());
+                                else
+                                    item = m_itemDict.find((*it)->getDevicePath());
 
-                    // make sure up-directory is visible and selected
-                    ThumbItem* item = m_itemDict.find(oldDirName);
-                    if (item) {
-                        int pos = m_itemList.find(item);
-                        if (pos != -1) {
-                            m_currRow = pos/m_nCols;
-                            m_currCol = pos-m_currRow*m_nCols;
-                            m_topRow  = QMAX(0, m_currRow-(m_nRows-1));
+                                if (item)
+                                {
+                                    int pos = m_itemList.find(item);
+                                    if (pos != -1)
+                                    {
+                                        m_currRow = pos/m_nCols;
+                                        m_currCol = pos-m_currRow*m_nCols;
+                                        m_topRow = QMAX(0, m_currRow-(m_nRows-1));
+                                    }
+                                }
+                                handled = true;
+                                break;
+                            }
                         }
                     }
-                    handled = true;
+                    if (!handled)
+                    {
+#endif
+                        if (d != QDir(m_galleryDir)) {
+
+                            QString oldDirName = d.dirName();
+                            d.cdUp();
+                            loadDirectory(d.absPath());
+
+                            // make sure up-directory is visible and selected
+                            ThumbItem* item = m_itemDict.find(oldDirName);
+                            if (item) {
+                                int pos = m_itemList.find(item);
+                                if (pos != -1) {
+                                    m_currRow = pos/m_nCols;
+                                    m_currCol = pos-m_currRow*m_nCols;
+                                    m_topRow  = QMAX(0, m_currRow-(m_nRows-1));
+                                }
+                            }
+                            handled = true;
+                        }
+#ifndef _WIN32
+                    }
                 }
+#endif
             }
         }
     }
@@ -501,6 +617,13 @@
         exit(-1);
     }
 
+    m_submenuType = (UIListBtnType*)container->GetType("submenu");
+    if (!m_menuType) {
+        std::cerr << "MythGallery: Failed to get submenu area."
+                  << std::endl;
+        exit(-1);
+    }
+
     // Menu Actions
 
     UIListBtnTypeItem* item;
@@ -508,15 +631,15 @@
     item->setData(new Action(&IconView::actionSlideShow));
     item = new UIListBtnTypeItem(m_menuType, tr("Random"));
     item->setData(new Action(&IconView::actionRandomShow));
-    item = new UIListBtnTypeItem(m_menuType, tr("Rotate CW"));
-    item->setData(new Action(&IconView::actionRotateCW));
-    item = new UIListBtnTypeItem(m_menuType, tr("Rotate CCW"));
-    item->setData(new Action(&IconView::actionRotateCCW));
-    item = new UIListBtnTypeItem(m_menuType, tr("Import"));
-    item->setData(new Action(&IconView::actionImport));
+    item = new UIListBtnTypeItem(m_menuType, tr("Meta Data..."));
+    item->setData(new Action(&IconView::actionSubMenuMetadata));
+    item = new UIListBtnTypeItem(m_menuType, tr("Marking..."));
+    item->setData(new Action(&IconView::actionSubMenuMark));
+    item = new UIListBtnTypeItem(m_menuType, tr("File..."));
+    item->setData(new Action(&IconView::actionSubMenuFile));
     item = new UIListBtnTypeItem(m_menuType, tr("Settings"));
     item->setData(new Action(&IconView::actionSettings));
-    
+
     m_menuType->SetActive(false);
 
     container = m_theme->GetSet("view");
@@ -570,6 +693,15 @@
         m_folderSelPix = QPixmap(*img);
         delete img;
 
+        img = gContext->LoadScaleImage("gallery-mark.png");
+        if (!img) {
+            std::cerr << "Failed to load gallery-mark.png"
+                      << std::endl;
+            exit(-1);
+        }
+        m_MrkPix = QPixmap(*img);
+        delete img;
+
         m_thumbW = m_backRegPix.width();
         m_thumbH = m_backRegPix.height();
         m_nCols  = m_viewRect.width()/m_thumbW - 1;
@@ -586,6 +718,10 @@
     if (!d.exists())
         return;
 
+#ifndef _WIN32
+    m_showDevices = false;
+#endif
+
     m_currDir = d.absPath();
     m_itemList.clear();
     m_itemDict.clear();
@@ -718,15 +854,89 @@
 
 void IconView::pressMenu()
 {
-    UIListBtnTypeItem* item = m_menuType->GetItemCurrent();
+    UIListBtnTypeItem* item;
 
+    if (m_inSubMenu)
+        item = m_submenuType->GetItemCurrent();
+    else
+        item = m_menuType->GetItemCurrent();
+
     if (!item || !item->getData())
         return;
 
     Action *act = (Action*) item->getData();
     (this->*(*act))();
+
+    m_menuType->SetActive(m_inMenu & !m_inSubMenu);
+    m_submenuType->SetActive(m_inMenu & m_inSubMenu);
 }
 
+void IconView::actionMainMenu()
+{
+    clearMenu(m_submenuType);
+    m_submenuType->Reset();
+
+    m_inSubMenu = false;
+}
+
+void IconView::actionSubMenuMetadata()
+{
+    clearMenu(m_submenuType);
+    m_submenuType->Reset();
+
+    UIListBtnTypeItem *item;
+    item = new UIListBtnTypeItem(m_submenuType, tr("Return"));
+    item->setData(new Action(&IconView::actionMainMenu));
+    item = new UIListBtnTypeItem(m_submenuType, tr("Rotate CW"));
+    item->setData(new Action(&IconView::actionRotateCW));
+    item = new UIListBtnTypeItem(m_submenuType, tr("Rotate CCW"));
+    item->setData(new Action(&IconView::actionRotateCCW));
+
+    m_inSubMenu = true;
+}
+
+void IconView::actionSubMenuMark()
+{
+    clearMenu(m_submenuType);
+    m_submenuType->Reset();
+
+    UIListBtnTypeItem *item;
+    item = new UIListBtnTypeItem(m_submenuType, tr("Return"));
+    item->setData(new Action(&IconView::actionMainMenu));
+    item = new UIListBtnTypeItem(m_submenuType, tr("Clear Marked"));
+    item->setData(new Action(&IconView::actionClearMarked));
+    item = new UIListBtnTypeItem(m_submenuType, tr("Select All"));
+    item->setData(new Action(&IconView::actionSelectAll));
+
+    m_inSubMenu = true;
+}
+
+void IconView::actionSubMenuFile()
+{
+    clearMenu(m_submenuType);
+    m_submenuType->Reset();
+
+    UIListBtnTypeItem *item;
+    item = new UIListBtnTypeItem(m_submenuType, tr("Return"));
+    item->setData(new Action(&IconView::actionMainMenu));
+#ifndef _WIN32
+    item = new UIListBtnTypeItem(m_submenuType, tr("Show Devices"));
+    item->setData(new Action(&IconView::actionShowDevices));
+#endif
+    item = new UIListBtnTypeItem(m_submenuType, tr("Import"));
+    item->setData(new Action(&IconView::actionImport));
+    item = new UIListBtnTypeItem(m_submenuType, tr("Copy here"));
+    item->setData(new Action(&IconView::actionCopyHere));
+    item = new UIListBtnTypeItem(m_submenuType, tr("Move here"));
+    item->setData(new Action(&IconView::actionMoveHere));
+    item = new UIListBtnTypeItem(m_submenuType, tr("Delete Marked"));
+    item->setData(new Action(&IconView::actionDeleteMarked));
+    item = new UIListBtnTypeItem(m_submenuType, tr("Create Dir"));
+    item->setData(new Action(&IconView::actionMkDir));
+
+    m_inSubMenu = true;
+}
+
 void IconView::actionRotateCW()
 {
     ThumbItem* item = m_itemList.at(m_currRow * m_nCols +
@@ -908,6 +1118,136 @@
     }
 }
 
+#ifndef _WIN32
+void IconView::actionShowDevices()
+{
+    if (m_currDevice)
+    {
+        m_currDevice->disconnect(this);
+        m_currDevice = NULL;
+    }
+
+    m_showDevices = true;
+
+    m_itemList.clear();
+    m_itemDict.clear();
+
+    m_thumbGen->cancel();
+
+    /* add gallery directory */
+    ThumbItem *item = new ThumbItem;
+    item->name = QString("Gallery");
+    item->path = m_galleryDir;
+    item->isDir = true;
+    m_itemList.append(item);
+    m_itemDict.insert(item->name, item);
+
+    MediaMonitor *mon = MediaMonitor::getMediaMonitor();
+    if (mon)
+    {
+        QValueList <MythMediaDevice *> removables = mon->getMedias(MEDIATYPE_DATA);
+        QValueList <MythMediaDevice *>::Iterator it = removables.begin();
+        for (; it != removables.end(); it++)
+        {
+            item = new ThumbItem;
+            if ((*it)->getVolumeID() != "")
+                item->name = (*it)->getVolumeID();
+            else
+                item->name = (*it)->getDevicePath();
+            item->path = (*it)->getMountPath();
+            item->isDir = true;
+            item->mediaDevice = *it;
+            m_itemList.append(item);
+            m_itemDict.insert(item->name, item);
+        }
+    }
+
+    m_lastRow = QMAX((int)ceilf((float)m_itemList.count()/(float)m_nCols)-1,0);
+    m_lastCol = QMAX(m_itemList.count()-m_lastRow*m_nCols-1,0);
+}
+#endif
+
+void IconView::actionCopyHere()
+{
+    copyMarkedFiles(false);
+}
+
+void IconView::actionMoveHere()
+{
+    copyMarkedFiles(true);
+}
+
+void IconView::actionDeleteMarked()
+{
+    std::cerr << "deleting marked files\n";
+
+    bool cont = MythPopupBox::showOkCancelPopup(gContext->GetMainWindow(), tr("Delete Marked Files"),
+                                                QString(tr("Deleting %1 images and folders"))
+                                                .arg(m_itemMarked.count()), false);
+
+    if (cont)
+    {
+        QStringList::iterator it;
+        QFileInfo fi;
+
+        for (it = m_itemMarked.begin(); it != m_itemMarked.end(); it++)
+        {
+            fi.setFile(*it);
+
+            std::cerr << "fi = " << fi.absFilePath() << endl;
+
+            if (fi.exists())
+            {
+                if (fi.isDir())
+                {
+                    GalleryUtil::deleteDirectory(fi);
+                    std::cerr << "deleting directory " << fi.absFilePath().local8Bit() << endl;
+                }
+                else
+                {
+                    GalleryUtil::deleteFile(fi);
+                    std::cerr << "deleting file " << fi.absFilePath().local8Bit() << endl;
+                }
+            }
+        }
+
+        m_itemMarked.clear();
+
+        loadDirectory(m_currDir);
+    }
+}
+
+void IconView::actionClearMarked()
+{
+    m_itemMarked.clear();
+}
+
+void IconView::actionSelectAll()
+{
+    ThumbItem *item;
+    for (item = m_itemList.first(); item; item = m_itemList.next())
+    {
+        if (!m_itemMarked.contains(item->path))
+            m_itemMarked.append(item->path);
+    }
+}
+
+void IconView::actionMkDir()
+{
+    QString folderName = tr("New Folder");
+
+    bool res = MythPopupBox::showGetTextPopup(gContext->GetMainWindow(), tr("Create New Folder"),
+                                              tr("Create New Folder"), folderName);
+
+    if (res)
+    {
+        QDir cdir(m_currDir);
+        cdir.mkdir(folderName);
+
+        loadDirectory(m_currDir);
+    }
+}
+
 void IconView::importFromDir(const QString &fromDir, const QString &toDir)
 {
     QDir d(fromDir);
@@ -947,3 +1287,54 @@
         }
     }
 }
+
+void IconView::copyMarkedFiles(bool move)
+{
+    QStringList::iterator it;
+    QFileInfo fi;
+    QFileInfo dest;
+
+    for (it = m_itemMarked.begin(); it != m_itemMarked.end(); it++)
+    {
+        fi.setFile(*it);
+        dest.setFile(QDir(m_currDir), fi.fileName());
+
+        if (fi.exists())
+        {
+            if (fi.isDir())
+                dest = GalleryUtil::copyDirectory(fi, dest, move);
+            else
+                dest = GalleryUtil::copyFile(fi, dest, move);
+
+            *it = dest.absFilePath();
+        }
+    }
+
+    loadDirectory(m_currDir);
+}
+
+void IconView::clearMenu(UIListBtnType *menu)
+{
+    UIListBtnTypeItem* item = menu->GetItemFirst();
+    while (item)
+    {
+        Action *act = (Action*) item->getData();
+        if (act)
+            delete act;
+        item = menu->GetItemNext(item);
+    }
+}
+
+void IconView::mediaStatusChanged( MediaStatus oldStatus, MythMediaDevice* pMedia)
+{
+    if (m_currDevice == pMedia)
+    {
+        actionShowDevices();
+
+        m_currRow = 0;
+        m_currCol = 0;
+
+        updateView();
+        updateText();
+    }
+}
Index: mythgallery/mythgallery/main.cpp
===================================================================
--- mythgallery/mythgallery/main.cpp	(revision 7775)
+++ mythgallery/mythgallery/main.cpp	(working copy)
@@ -14,6 +14,7 @@
 #include <mythtv/mythdialogs.h>
 #include <mythtv/mythplugin.h>
 #include <mythtv/dialogbox.h>
+#include <mythtv/mythmedia.h>
 
 extern "C" {
 int mythplugin_init(const char *libversion);
@@ -33,11 +34,28 @@
         diag.exec();
     }
     else {
-        IconView icv(startdir, gContext->GetMainWindow(), "IconView");
+        IconView icv(startdir, NULL, gContext->GetMainWindow(), "IconView");
         icv.exec();
     }
 }
 
+void handleMedia(MythMediaDevice *dev)
+{
+    QString galleryDir = gContext->GetSetting("GalleryDir");
+    QDir dir(galleryDir);
+    if (!dir.exists() || !dir.isReadable()) {
+        DialogBox diag(gContext->GetMainWindow(),
+                       QObject::tr("Gallery Directory does not exist"
+                                   " or is unreadable."));
+        diag.AddButton(QObject::tr("Ok"));
+        diag.exec();
+    }
+    else {
+        IconView icv(galleryDir, dev, gContext->GetMainWindow(), "IconView");
+        icv.exec();
+    }
+}
+
 void setupKeys(void)
 {
     REG_JUMP("MythGallery", "Image viewer / slideshow", "", runGallery);
@@ -63,6 +81,9 @@
     REG_KEY("Gallery", "LOWRIGHT", "Go to the lower-right corner of the image",
             "PgDown");
     REG_KEY("Gallery", "INFO", "Toggle Showing Information about Image", "I");
+    REG_KEY("Gallery", "MARK", "Mark image", "T");
+
+    REG_MEDIA_HANDLER("MythGallery Media Handler", "", "", handleMedia, MEDIATYPE_DATA | MEDIATYPE_MIXED);
 }
 
 int mythplugin_init(const char *libversion)
Index: mythgallery/mythgallery/thumbgenerator.cpp
===================================================================
--- mythgallery/mythgallery/thumbgenerator.cpp	(revision 7775)
+++ mythgallery/mythgallery/thumbgenerator.cpp	(working copy)
@@ -280,15 +280,17 @@
 
 QString ThumbGenerator::getThumbcacheDir(const QString& inDir)
 {
+    QString galleryDir = gContext->GetSetting("GalleryDir");
+
     // For directory "/my/images/january", this function either returns 
     // "/my/images/january/.thumbcache" or "~/.mythtv/mythgallery/january/.thumbcache"
     QString aPath = inDir + QString("/.thumbcache/");
     if ( gContext->GetNumSetting("GalleryThumbnailLocation") 
-            && ! QDir(aPath).exists() )
+            && ! QDir(aPath).exists() && inDir.startsWith(galleryDir))
     {
         mkpath(aPath);
     }
-    if ( ! gContext->GetNumSetting("GalleryThumbnailLocation") || ! QDir(aPath).exists() ) 
+    if ( ! gContext->GetNumSetting("GalleryThumbnailLocation") || ! QDir(aPath).exists() || ! inDir.startsWith(galleryDir))
     {
         // Arrive here if storing thumbs in home dir, 
         // OR failed to create thumb dir in gallery pics location
Index: mythgallery/mythgallery/iconview.h
===================================================================
--- mythgallery/mythgallery/iconview.h	(revision 7775)
+++ mythgallery/mythgallery/iconview.h	(working copy)
@@ -26,6 +26,7 @@
 #include <qpixmap.h>
 
 #include <mythtv/mythdialogs.h>
+#include <mythtv/mythmedia.h>
 
 class XMLParse;
 class UIListBtnType;
@@ -41,6 +42,7 @@
         name   = "";
         path   = "";
         isDir  = false;
+        mediaDevice = NULL;
     }
 
     ~ThumbItem() {
@@ -55,6 +57,7 @@
     QString  name;
     QString  path;
     bool     isDir;
+    MythMediaDevice *mediaDevice;
 };
 
 typedef QPtrList<ThumbItem> ThumbList;
@@ -66,8 +69,8 @@
 
 public:
 
-    IconView(const QString& galleryDir, MythMainWindow* parent, 
-             const char* name = 0);
+    IconView(const QString& galleryDir, MythMediaDevice *initialDevice,
+             MythMainWindow* parent, const char* name = 0);
     ~IconView();
 
 protected:
@@ -90,20 +93,39 @@
     bool moveLeft();
     bool moveRight();
 
+    void actionMainMenu();
+    void actionSubMenuMetadata();
+    void actionSubMenuMark();
+    void actionSubMenuFile();
+
     void actionRotateCW();
     void actionRotateCCW();
     void actionSlideShow();
     void actionRandomShow();
     void actionSettings();
     void actionImport();
+#ifndef _WIN32
+    void actionShowDevices();
+#endif
+    void actionCopyHere();
+    void actionMoveHere();
+    void actionDeleteMarked();
+    void actionClearMarked();
+    void actionSelectAll();
+    void actionMkDir();
 
+
     void pressMenu();
 
     void loadThumbnail(ThumbItem *item);
     void importFromDir(const QString &fromDir, const QString &toDir);
+    void copyMarkedFiles(bool move = false);
+
+    void clearMenu(UIListBtnType *menu);
     
     QPtrList<ThumbItem> m_itemList;
     QDict<ThumbItem>    m_itemDict;
+    QStringList         m_itemMarked;
     QString             m_galleryDir;
 
     XMLParse           *m_theme;
@@ -112,15 +134,22 @@
     QRect               m_viewRect;
 
     bool                m_inMenu;
+    bool                m_inSubMenu;
     UIListBtnType      *m_menuType;
+    UIListBtnType      *m_submenuType;
     
     QPixmap             m_backRegPix;
     QPixmap             m_backSelPix;
     QPixmap             m_folderRegPix;
     QPixmap             m_folderSelPix;
+    QPixmap             m_MrkPix;
 
     QString             m_currDir;
     bool                m_isGallery;
+#ifndef _WIN32
+    bool                m_showDevices;
+    MythMediaDevice    *m_currDevice;
+#endif
 
     int                 m_currRow;
     int                 m_currCol;
@@ -138,6 +167,11 @@
     ThumbGenerator     *m_thumbGen;
 
     typedef void (IconView::*Action)();
+
+#ifndef _WIN32
+public slots:
+    void mediaStatusChanged( MediaStatus oldStatus, MythMediaDevice* pMedia);
+#endif
 };
 
 
Index: mythgallery/mythgallery/gallery-ui.xml
===================================================================
--- mythgallery/mythgallery/gallery-ui.xml	(revision 7775)
+++ mythgallery/mythgallery/gallery-ui.xml	(working copy)
@@ -21,7 +21,7 @@
     </font>
 
     <container name="menu">
-      <area>20,20,140,240</area>
+      <area>20,20,140,500</area>
 
       <listbtnarea name="menu" draworder="0">
         <area>0,0,140,240</area>
@@ -35,6 +35,18 @@
         <showscrollarrows>no</showscrollarrows>
       </listbtnarea>
 
+      <listbtnarea name="submenu" draworder="0">
+        <area>0,260,140,240</area>
+        <gradient type="unselected" start="#000000" end="#505050" alpha="100">
+        </gradient>
+        <gradient type="selected" start="#52CA38" end="#349838" alpha="255">
+        </gradient>
+        <fcnfont name="active" function="active"></fcnfont>
+        <fcnfont name="inactive" function="inactive"></fcnfont>
+        <showarrow>no</showarrow>
+        <showscrollarrows>no</showscrollarrows>
+      </listbtnarea>
+
     </container>
 
     <container name="text">
Index: mythgallery/mythgallery/galleryutil.cpp
===================================================================
--- mythgallery/mythgallery/galleryutil.cpp	(revision 7775)
+++ mythgallery/mythgallery/galleryutil.cpp	(working copy)
@@ -20,6 +20,8 @@
 #include <qfileinfo.h>
 #include <qdir.h>
 
+#include <mythtv/mythdbcon.h>
+
 #include "config.h"
 #include "constants.h"
 #include "galleryutil.h"
@@ -201,3 +203,159 @@
 
     return isGallery;
 }
+
+QFileInfo GalleryUtil::copyFile(QFileInfo src, QFileInfo dest, bool move)
+{
+    QFileInfo newDest = dest;
+
+    // test if dest exists
+    int i = 0;
+    while (newDest.exists())
+    {
+        std::cerr << "need to find a new name for " << dest.absFilePath().local8Bit() << " trying ";
+        newDest.setFile(dest.dir(), dest.baseName() + "_" + QString::number(i) + "." + dest.extension());
+        std::cerr << newDest.absFilePath().local8Bit() << endl;
+        i++;
+    }
+
+    MSqlQuery query(MSqlQuery::InitCon());
+    QString cmd;
+    if (move)
+    {
+        std::cerr << "moving " << src.absFilePath().local8Bit();
+        cmd = "mv ";
+        query.prepare("UPDATE gallerymetadata SET image = :IMAGENEW "
+                      "WHERE image = :IMAGEOLD ;");
+    }
+    else
+    {
+        std::cerr << "copying " << src.absFilePath().local8Bit();
+        cmd = "cp ";
+        query.prepare("INSERT INTO gallerymetadata (image, keywords, angle) "
+                      "SELECT :IMAGENEW , keywords, angle "
+                      "FROM gallerymetadata "
+                      "WHERE image = :IMAGEOLD ;");
+    }
+    std::cerr << " to " << newDest.absFilePath().local8Bit() << endl;
+
+    cmd += "\"" + src.absFilePath().local8Bit() + "\" \"" + newDest.absFilePath().local8Bit() + "\"";
+    myth_system(cmd);
+
+    /* update metadata table */
+    query.bindValue(":IMAGENEW", newDest.absFilePath().utf8());
+    query.bindValue(":IMAGEOLD", src.absFilePath().utf8());
+    query.exec();
+
+    return newDest;
+}
+
+bool GalleryUtil::deleteFile(QFileInfo file)
+{
+    QString cmd = "rm \"" + file.absFilePath().local8Bit() + "\"";
+    myth_system(cmd);
+
+    MSqlQuery query(MSqlQuery::InitCon());
+    query.prepare("DELETE FROM gallerymetadata "
+                  "WHERE image = :IMAGE ;");
+    query.bindValue(":IMAGE", file.absFilePath().utf8());
+    query.exec();
+
+    return true;
+}
+
+QFileInfo GalleryUtil::copyDirectory(QFileInfo src, QFileInfo dest, bool move)
+{
+    QFileInfo newDest = dest;
+
+    QDir srcDir(src.absFilePath());
+    srcDir.setNameFilter(MEDIA_FILENAMES);
+    srcDir.setSorting(QDir::Name | QDir::DirsFirst | QDir::IgnoreCase);
+    srcDir.setMatchAllDirs(true);
+
+    /* test if dest exists and is a directory */
+    int i = 0;
+    while (newDest.exists() && !newDest.isDir())
+    {
+        std::cerr << "file exists, but we want dir for " << newDest.absFilePath().local8Bit();
+        newDest.setFile(dest.absFilePath() + "_" + QString::number(i));
+        std::cerr << " trying " << newDest.absFilePath().local8Bit() << endl;
+        i++;
+    }
+
+    if (!newDest.exists())
+    {
+        std::cerr << "creating directory " << newDest.absFilePath().local8Bit() << endl;
+
+        srcDir.mkdir(newDest.absFilePath());
+        newDest.refresh();
+    }
+
+    if (newDest.exists() && newDest.isDir())
+    {
+        QDir dstDir(newDest.absFilePath());
+
+        const QFileInfoList *list = srcDir.entryInfoList();
+
+        QFileInfoListIterator it(*list);
+        QFileInfo *fi;
+        QFileInfo dfi;
+
+        while ((fi = it.current()) != 0)
+        {
+            ++it;
+            if (fi->fileName() == "." || fi->fileName() == "..")
+                continue;
+
+            dfi.setFile(dstDir, fi->fileName());
+
+            std::cerr << "source is " << fi->absFilePath().local8Bit() << endl;
+            std::cerr << "destin is " << dfi.absFilePath().local8Bit() << endl;
+
+            if (fi->isDir())
+                dfi = copyDirectory(*fi, dfi, move);
+            else
+                dfi = copyFile(*fi, dfi, move);
+        }
+
+        if (move)
+            srcDir.rmdir(src.absFilePath());
+    }
+
+    return newDest;
+}
+
+bool GalleryUtil::deleteDirectory(QFileInfo dir)
+{
+    QDir srcDir(dir.absFilePath());
+    srcDir.setNameFilter(MEDIA_FILENAMES);
+    srcDir.setSorting(QDir::Name | QDir::DirsFirst | QDir::IgnoreCase);
+    srcDir.setMatchAllDirs(true);
+
+    if (srcDir.exists())
+    {
+        const QFileInfoList *list = srcDir.entryInfoList();
+
+        QFileInfoListIterator it(*list);
+        QFileInfo *fi;
+
+        while ((fi = it.current()) != 0)
+        {
+            ++it;
+            if (fi->fileName() == "." || fi->fileName() == "..")
+                continue;
+
+            if (fi->isDir())
+                deleteDirectory(*fi);
+            else
+                deleteFile(*fi);
+        }
+    }
+
+    // delete .thumbcache
+    QString cmd = "rm -rf \"" + srcDir.absPath().local8Bit() + "/.thumbcache\"";
+    myth_system(cmd);
+
+    srcDir.rmdir(srcDir.absPath());
+
+    return true;
+}
