changeset 69:6d5a5571caec

* Basic working "Open Repository" dialog
author Chris Cannam
date Thu, 18 Nov 2010 15:14:39 +0000
parents b918e57c7bea
children 3af5c2b913c7
files easyhg.pro easyhg.qrc hgexplorer.qrc images/browser-64.png images/browser.png images/hdd_unmount-64.png images/hdd_unmount.png images/hglogo-64.png images/hglogo.png images/logo-droplets.svg mainwindow.cpp mainwindow.h multichoicedialog.cpp multichoicedialog.h recentfiles.h selectablelabel.cpp selectablelabel.h
diffstat 17 files changed, 525 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/easyhg.pro	Wed Nov 17 22:13:34 2010 +0000
+++ b/easyhg.pro	Thu Nov 18 15:14:39 2010 +0000
@@ -7,6 +7,9 @@
     DESTDIR = .
 }
 
+OBJECTS_DIR = o
+MOC_DIR = o
+
 HEADERS = mainwindow.h \
     hgexpwidget.h \
     common.h \
@@ -26,7 +29,8 @@
     recentfiles.h \
     startupdialog.h \
     repositorydialog.h \
-    multichoicedialog.h
+    multichoicedialog.h \
+    selectablelabel.h
 SOURCES = main.cpp \
     mainwindow.cpp \
     hgexpwidget.cpp \
@@ -47,16 +51,17 @@
     recentfiles.cpp \
     startupdialog.cpp \
     repositorydialog.cpp \
-    multichoicedialog.cpp
+    multichoicedialog.cpp \
+    selectablelabel.cpp
 
 macx-* {
 SOURCES += common_osx.mm
 }
 
 # ! [0]
-RESOURCES = hgexplorer.qrc
+RESOURCES = easyhg.qrc
 win32 {
-    RC_FILE = hgexplorer.rc
+    RC_FILE = easyhg.rc
 }
 
 QT += network opengl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyhg.qrc	Thu Nov 18 15:14:39 2010 +0000
@@ -0,0 +1,26 @@
+<RCC>
+    <qresource prefix="/">
+        <file>images/add.png</file>
+        <file>images/commit.png</file>
+        <file>images/diff.png</file>
+        <file>images/folderdiff.png</file>
+        <file>images/exit.png</file>
+        <file>images/merge.png</file>
+        <file>images/pull.png</file>
+        <file>images/push.png</file>
+        <file>images/remove.png</file>
+        <file>images/settings.png</file>
+        <file>images/status.png</file>
+        <file>images/undo.png</file>
+        <file>images/update.png</file>
+        <file>images/incoming.png</file>
+        <file>images/chgsetdiff.png</file>
+        <file>images/browser.png</file>
+        <file>images/browser-64.png</file>
+        <file>images/hglogo.png</file>
+        <file>images/hglogo-64.png</file>
+        <file>images/hdd_unmount.png</file>
+        <file>images/hdd_unmount-64.png</file>
+        <file>images/fileopen.png</file>
+    </qresource>
+</RCC>
--- a/hgexplorer.qrc	Wed Nov 17 22:13:34 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-<RCC>
-    <qresource prefix="/">
-        <file>images/add.png</file>
-        <file>images/commit.png</file>
-        <file>images/diff.png</file>
-        <file>images/folderdiff.png</file>
-        <file>images/exit.png</file>
-        <file>images/merge.png</file>
-        <file>images/pull.png</file>
-        <file>images/push.png</file>
-        <file>images/remove.png</file>
-        <file>images/settings.png</file>
-        <file>images/status.png</file>
-        <file>images/undo.png</file>
-        <file>images/update.png</file>
-        <file>images/incoming.png</file>
-        <file>images/chgsetdiff.png</file>
-    </qresource>
-</RCC>
Binary file images/browser-64.png has changed
Binary file images/browser.png has changed
Binary file images/hdd_unmount-64.png has changed
Binary file images/hdd_unmount.png has changed
Binary file images/hglogo-64.png has changed
Binary file images/hglogo.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/images/logo-droplets.svg	Thu Nov 18 15:14:39 2010 +0000
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg id="Layer_1" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="120" width="100" version="1.0" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 124.766 152.099"><metadata id="metadata6845"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title>Mercurial &quot;droplets&quot; logo</dc:title><dc:creator><cc:Agent><dc:title>Cali Mastny and Matt Mackall</dc:title></cc:Agent></dc:creator><cc:license rdf:resource="http://creativecommons.org/licenses/GPL/2.0/"/><dc:date>Feb 12 2008</dc:date></cc:Work><cc:License rdf:about="http://creativecommons.org/licenses/GPL/2.0/"><cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/><cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/><cc:requires rdf:resource="http://web.resource.org/cc/Notice"/><cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/><cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike"/><cc:requires rdf:resource="http://web.resource.org/cc/SourceCode"/></cc:License></rdf:RDF></metadata>
+<rect id="rect6847" stroke-linejoin="miter" style="stroke-dasharray:none;" height="150.12" width="124.77" stroke="#000" stroke-miterlimit="4" y="0.98776" x="0.3169" stroke-width="1.9755" fill="#FFF"/><path id="text2611" style="stroke-dasharray:none;" d="M9.848,124.61c1.777-0.79,3.665-1.18,5.479-1.18,1.74,0,2.851,0.43,3.48,1.32,1.332-0.89,3.146-1.32,4.553-1.32,4.221,0,4.369,1.71,4.369,6.73v11.11c0,0.49,0.074,0.49-2.036,0.49v-11.81c0-3.63-0.074-4.74-2.48-4.74-1.073,0-2.184,0.25-3.369,1.03v15.27c-0.037,0.15-0.111,0.18-0.369,0.22-0.038,0-0.074,0.03-0.112,0.03h-1.555v-11.81c0-3.49,0-4.77-2.517-4.77-1.074,0-2.147,0.21-3.406,0.82v15.27c0,0.49,0.074,0.49-2.0361,0.49v-17.15m27.831-1.18c-3.146,0-6.626,0.89-6.626,10.4,0,7.33,2.554,8.47,6.071,8.47,2.701,0,5.034-0.89,5.034-1.32,0-0.53-0.074-1.35-0.259-1.82-1.148,0.79-2.777,1.21-4.59,1.21-2.48,0-4.146-0.71-4.184-6.22,1.629,0,5.776-0.04,8.848-0.65,0.259-1.17,0.37-2.88,0.37-4.37,0-3.56-1.444-5.7-4.664-5.7m-0.185,1.78c2.221,0,2.813,1.46,2.85,4.31,0,0.75-0.037,1.64-0.148,2.49-2.073,0.5-5.591,0.5-7.072,0.5,0.261-6.48,2.481-7.3,4.37-7.3m8.07-0.21c1.739-1.14,3.332-1.57,4.961-1.57,1.814,0,2.666,0.5,2.666,1.11,0,0.35-0.112,0.96-0.297,1.31-0.519-0.28-1.11-0.53-2.074-0.53-1.184,0-2.295,0.32-3.183,1.1v14.85c0,0.49,0.037,0.49-2.073,0.49v-16.76m18.69-0.39c0-0.47-1.554-1.18-3.11-1.18-2.999,0-6.664,1.03-6.664,9.83,0,8.33,2.222,9.07,6.109,9.07,1.924,0,3.665-1.03,3.665-1.6,0-0.32-0.074-0.82-0.26-1.24-0.778,0.56-1.962,1.1-3.22,1.1-2.665,0-4.22-0.75-4.22-7.23,0-7.15,2.554-8.15,4.775-8.15,1.258,0,1.962,0.36,2.665,0.82,0.186-0.43,0.26-1.03,0.26-1.42m14.181,16.55c-1.63,0.82-3.776,1.14-5.627,1.14-4.739,0-5.442-1.99-5.442-6.73v-11.14c0-0.46-0.037-0.46,2.074-0.46v11.82c0,3.56,0.517,4.77,3.294,4.77,1.073,0,2.554-0.22,3.665-0.86v-15.27c0-0.46-0.074-0.46,2.036-0.46v17.19m4.221-16.16c1.739-1.14,3.332-1.57,4.96-1.57,1.814,0,2.666,0.5,2.666,1.11,0,0.35-0.111,0.96-0.296,1.31-0.519-0.28-1.111-0.53-2.074-0.53-1.184,0-2.295,0.32-3.183,1.1v14.85c0,0.49,0.037,0.49-2.073,0.49v-16.76m12.379-1.03c-1.629,0-2.11,0-2.11,0.96v16.83c2.073,0,2.11,0,2.11-0.49v-17.3m-2.184-6.27c0,1.18,0.37,1.6,1.11,1.64,0.851,0,1.259-0.61,1.259-1.67,0.037-1.11-0.26-1.61-1.111-1.61-0.814,0-1.221,0.61-1.258,1.64m5.696,7.3c0-0.39,0.074-0.61,0.222-0.71,0.704-0.39,3.41-0.86,6.48-0.86,2.33,0,3.81,1.11,3.81,4.31v2.31c0,6.34-0.18,11.07-0.18,11.07-0.85,0.47-2.45,1.18-5.04,1.18-2.66,0.03-5.329-0.22-5.329-5.48,0-5.02,2.739-5.81,5.479-5.81,1.04,0,2.26,0.11,3.07,0.43v-3.31c0-2.31-1.18-2.81-2.59-2.81-1.89,0-4.514,0.35-5.662,0.89-0.222-0.39-0.26-1-0.26-1.21m8.512,7.9c-0.7-0.25-1.7-0.35-2.4-0.35-2.11,0-4.04,0.42-4.04,4.34,0,3.66,1.59,3.7,3.48,3.7,1.19,0,2.37-0.32,2.78-0.75,0,0,0.18-4.27,0.18-6.94m7.86,8.37c0,0.49,0.04,0.49-2.04,0.49v-25.2c0-0.96,0.41-0.96,2.04-0.96v25.67" stroke-miterlimit="4" stroke-width="2.02999997" fill="#010101"/><g id="g4503" transform="matrix(0.9351326,0,0,0.9351326,150.39508,-1.251766)"><path id="path2339" fill="#1b1a1b" d="M-45.75,92.692c20.04-33.321-4.232-87.363-48.614-81.873-40.096,4.958-40.746,47.165-5.405,57.191,30.583,8.685,6.318,28.084,7.027,41,0.712,12.92,26.587,17.6,46.992-16.318z"/><circle id="circle2341" transform="matrix(1.0917947,-0.2858168,0.2858168,1.0917947,-180.30817,13.494135)" cy="85.364" cx="33.728" r="15.414" fill="#1b1a1b"/><path id="path2343" fill="#1b1a1b" d="M-140.06,48.936c-6.26,0.606-10.84,6.164-10.24,12.422,0.61,6.262,6.17,10.847,12.43,10.241,6.26-0.614,10.84-6.171,10.23-12.43-0.61-6.253-6.16-10.839-12.42-10.233z"/><path id="path2561" fill="#bfbfbf" d="M-44.993,91.34c20.041-33.321-4.231-87.363-48.613-81.873-40.104,4.9568-40.744,47.166-5.406,57.193,30.583,8.684,6.318,28.083,7.027,41,0.713,12.92,26.587,17.6,46.992-16.32z"/><path id="path2563" fill="#000" d="M-86.842,112.76c-1.215-1.97,0.642-4.16,2.551-3.99,3.039,0.26,9.655-0.04,14.876-3,13.043-7.39,33.114-42.966,23.019-65.405-4.519-10.044-6.72-12.92-11.374-17.833-0.95-1.002-0.405-0.948,0.238-0.609,2.517,1.321,6.94,6.437,11.477,14.765,7.664,14.069,7.267,30.795,4.416,41.287-1.986,7.299-8.825,23.815-18.842,30.955-10.039,7.15-21.785,11.26-26.361,3.83z"/><path id="path2565" fill="#000" d="M-95.93,66.591c-6.83-2.028-15.64-4.853-20.74-11.517-3.75-4.914-5.66-10.277-6.15-13.318-0.17-1.085-0.32-1.991-0.01-2.24,0.15-0.117,2.81,5.896,6.79,10.936,3.97,5.04,9.53,7.988,14.16,9.059,4.117,0.952,12.646,3.044,15.532,5.503,2.967,2.527,3.215,7.987,2.216,8.603-1.006,0.62-3.048-4.429-11.798-7.026z"/><path id="path2567" fill="#FFF" d="M-81.841,113.72c-0.132,1.57,1.665,1.87,4.083,1.51,3.099-0.46,5.72-0.81,9.287-2.6,4.835-2.42,9.728-5.89,13.312-10.57,10.692-13.945,14.478-30.45,13.895-32.824-0.195,1.961-2.776,12.253-8.679,21.532-7.582,11.922-13.079,18.262-25.758,21.342-3.529,0.86-5.967-0.45-6.14,1.61z"/><path id="path2569" fill="#FFF" d="M-109.96,59.479c1.44,1.225,4.4,2.857,10.223,4.767,7.031,2.305,10.455,4.304,11.888,5.262,1.52,1.018,2.483,3.288,2.578,1.272,0.099-2.019-1.145-3.755-3.921-4.675-1.878-0.624-5.038-2.109-8.067-2.707-1.946-0.384-5.111-1.146-7.831-1.978-1.48-0.457-3-1.258-4.87-1.941z"/><circle id="circle2577" transform="matrix(1.0917947,-0.2858168,0.2858168,1.0917947,-180.30817,13.494135)" cy="84.375" cx="34.681" r="15.414" fill="#bfbfbf"/><path id="path2579" fill="#000" d="M-128.68,108.38c13.53,12.54,33.894-4.69,24.93-19.897-1.01-1.708-2.32-3.009-1.89-1.7,2.87,8.747,0.22,15.667-4.72,19.227-4.85,3.5-11.51,4.09-16.84,1.32-1.57-0.81-2.22,0.37-1.48,1.05z"/><path id="path2585" fill="#FFF" d="M-118.07,110.95c1.73-0.36,11.75-2.95,14.1-11.194,0.73-2.569,0.86-2.053,0.66-0.661-1.06,7.105-7.78,12.345-13.49,12.545-1.16,0.12-2.68-0.39-1.27-0.69z"/><path id="path2589" fill="#bfbfbf" d="M-139.3,47.584c-6.26,0.605-10.84,6.164-10.24,12.422,0.61,6.261,6.17,10.847,12.43,10.241,6.25-0.614,10.84-6.173,10.23-12.431-0.61-6.254-6.17-10.838-12.42-10.232z"/><path id="path2591" fill="#000" d="M-144.47,67.571c0.07,0.805,1.17,1.838,2.9,2.312,1.49,0.408,5.32,1.45,10.25-1.658,4.92-3.108,5.49-11.421,3.25-13.865-0.69-1.239-1.59-2.14-0.88-0.164,1.81,4.99-1.7,9.659-4.74,11.82-3.03,2.162-6.88,1.139-8.45,0.66s-2.4,0.064-2.33,0.895z"/><path id="path2597" fill="#FFF" d="M-138.11,68.688c0.45-0.406,2.73-0.24,4.79-1.35,2.07-1.109,4.52-3.54,4.95-6.994,0.26-2.029,0.34-1.519,0.44-0.415-0.32,5.743-5.6,8.916-8.62,9.334-0.82,0.113-2.25,0.044-1.56-0.575z"/><path id="path2561_1_" fill="#999" d="M-47.767,69.694c8.532-24.594-9.323-61.736-45.446-57.268-32.637,4.035-33.167,38.389-4.4,46.55,32.582,4.933,12.962,29.512,10.179,41.904-2.495,11.11,26.331,12.94,39.667-31.186z"/><path id="path2571" fill="#f3f3f3" d="M-70.093,88.904c-8.827-1.092-21.529,18.836-9.552,16.506,5.756-0.86,10.525-2.89,14.794-7.762,5.567-6.353,13.883-20.074,16.288-28.94,2.025-7.476,1.007-19.057-1.081-8.175-2.142,11.167-11.623,29.464-20.449,28.371z"/><path id="path2581" fill="#999" d="M-129.39,104.85c2.05,0.03,3.28,0.32,5.35,1.77,4.09,1.7,11.61,0.62,15.09-3.95,3.47-4.57,3.58-10.868,2.26-14.674-3.24-9.314-16.99-9.149-23.13-1.417-6.64,8.636-1.61,18.231,0.43,18.271z"/><path id="path2593_2_" fill="#999" d="M-147.64,61.684c0.41,1.282,1.45,3.154,3.65,3.466,2.94,0.417,3.54,1.743,7,1.055,3.47-0.688,6.09-3.528,7.14-6.67,1.21-4.347-0.59-6.591-3.31-8.595-2.71-2.003-8.67-1.788-12.23,1.458-2.53,2.305-3.24,6.163-2.25,9.286z"/><path id="path256" fill="#f3f3f3" d="M-136.11,64.558c2.66-0.697,6.18-4.325,4.44-7.096-2.16-3.413-8.17-0.491-8.37,3.309-0.21,3.802,1.11,4.526,3.93,3.787z"/><path id="path258" fill="#f3f3f3" d="M-116.12,105.51c2.28-0.6,9.24-3.43,7.93-13.547-0.66-5.126-3.46,6.361-8.63,8.077-7.85,2.61-6.97,7.48,0.7,5.47z"/></g>
+</svg>
--- a/mainwindow.cpp	Wed Nov 17 22:13:34 2010 +0000
+++ b/mainwindow.cpp	Thu Nov 18 15:14:39 2010 +0000
@@ -31,6 +31,7 @@
 
 #include "mainwindow.h"
 #include "settingsdialog.h"
+#include "multichoicedialog.h"
 #include "startupdialog.h"
 #include "colourset.h"
 #include "debug.h"
@@ -694,14 +695,59 @@
 }
     
 
+void MainWindow::open()
+{
+    MultiChoiceDialog *d = new MultiChoiceDialog
+        (tr("Open Repository"),
+         tr("What would you like to open?"),
+         this);
+
+    d->addChoice("remote",
+                 tr("<qt><center><img src=\":images/browser-64.png\"><br>Remote repository</center></qt>"),
+                 tr("Open an existing remote repository, by cloning a Mercurial repository URL into a local folder."),
+                 MultiChoiceDialog::UrlArg);
+
+    d->addChoice("local",
+                 tr("<qt><center><img src=\":images/hglogo-64.png\"><br>Local repository</center></qt>"),
+                 tr("Open an existing local Mercurial repository."),
+                 MultiChoiceDialog::DirectoryArg);
+
+    d->addChoice("init",
+                 tr("<qt><center><img src=\":images/hdd_unmount-64.png\"><br>File folder</center></qt>"),
+                 tr("Open a local folder, by creating a Mercurial repository in it."),
+                 MultiChoiceDialog::DirectoryArg);
+    
+    d->setCurrentChoice("local");
+
+    if (d->exec() == QDialog::Accepted) {
+
+        QString choice = d->getCurrentChoice();
+        QString arg = d->getArgument().trimmed();
+    
+        if (choice == "local") {
+            workFolderPath = arg;
+        } else {
+            //!!!
+        }
+        
+        hgExp->clearLists();
+        enableDisableActions();
+        hgStat();
+    }
+
+    delete d;
+}
+
 void MainWindow::settings()
 {
+/*!!!
     SettingsDialog *settingsDlg = new SettingsDialog(this);
     settingsDlg->setModal(true);
     settingsDlg->exec();
     hgExp -> clearLists();
     enableDisableActions();
     hgStat();
+*/
 }
 
 #define STDOUT_NEEDS_BIG_WINDOW 512
@@ -951,9 +997,8 @@
                 switch(runningAction)
                 {
                     case ACT_STAT:
-                        {
-                            hgExp -> updateWorkFolderFileList(runner -> getStdOut());
-                        }
+                        MultiChoiceDialog::addRecentArgument("local", workFolderPath);
+                        hgExp -> updateWorkFolderFileList(runner -> getStdOut());
                         break;
 
                     case ACT_INCOMING:
@@ -975,11 +1020,15 @@
                         break;
 
                     case ACT_INIT:
+                        MultiChoiceDialog::addRecentArgument("init", workFolderPath);
+                        MultiChoiceDialog::addRecentArgument("local", workFolderPath);
                         enableDisableActions();
                         shouldHgStat = true;
                         break;
 
                     case ACT_CLONEFROMREMOTE:
+                        MultiChoiceDialog::addRecentArgument("local", workFolderPath);
+                        MultiChoiceDialog::addRecentArgument("remote", remoteRepoPath);
                         QMessageBox::information(this, "Clone", runner -> getStdOut());
                         enableDisableActions();
                         shouldHgStat = true;
@@ -1108,6 +1157,7 @@
     connect(hgIgnoreAct, SIGNAL(triggered()), this, SLOT(hgIgnore()));
 
     connect(settingsAct, SIGNAL(triggered()), this, SLOT(settings()));
+    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
 
     connect(hgInitAct, SIGNAL(triggered()), this, SLOT(hgInit()));
     connect(hgCloneFromRemoteAct, SIGNAL(triggered()), this, SLOT(hgCloneFromRemote()));
@@ -1310,6 +1360,10 @@
     hgCloneFromRemoteAct = new QAction(tr("Clone from remote"), this);
     hgCloneFromRemoteAct->setStatusTip(tr("Clone from remote repository into local repository in selected folder"));
 
+    openAct = new QAction(QIcon(":/images/fileopen.png"), tr("Open..."), this);
+    openAct -> setStatusTip(tr("Open repository"));
+    openAct -> setIconVisibleInMenu(true);
+
     settingsAct = new QAction(QIcon(":/images/settings.png"), tr("Settings..."), this);
     settingsAct -> setStatusTip(tr("View and change application settings"));
     settingsAct -> setIconVisibleInMenu(true);
@@ -1399,6 +1453,7 @@
     fileMenu -> addAction(hgInitAct);
     fileMenu -> addAction(hgCloneFromRemoteAct);
     fileMenu -> addSeparator();
+    fileMenu -> addAction(openAct);
     fileMenu -> addAction(settingsAct);
     fileMenu -> addSeparator();
     fileMenu -> addAction(exitAct);
@@ -1427,7 +1482,7 @@
 {
     fileToolBar = addToolBar(tr("File"));
     fileToolBar -> setIconSize(QSize(MY_ICON_SIZE, MY_ICON_SIZE));
-    fileToolBar -> addAction(settingsAct);
+    fileToolBar -> addAction(openAct);
     fileToolBar -> addAction(hgStatAct);
     fileToolBar -> addSeparator();
 //    fileToolBar -> addAction(hgChgSetDiffAct);
@@ -1467,6 +1522,9 @@
     statusBar()->showMessage(tr("Ready"));
 }
 
+
+//!!! review these:
+
 void MainWindow::readSettings()
 {
     QDir workFolder;
--- a/mainwindow.h	Wed Nov 17 22:13:34 2010 +0000
+++ b/mainwindow.h	Thu Nov 18 15:14:39 2010 +0000
@@ -88,6 +88,7 @@
 private slots:
     void about();
     void settings();
+    void open();
     void startupDialog();
 
     void hgRemove();
@@ -147,6 +148,7 @@
     //File menu actions
     QAction *hgInitAct;
     QAction *hgCloneFromRemoteAct;
+    QAction *openAct;
     QAction *settingsAct;
     QAction *exitAct;
 
--- a/multichoicedialog.cpp	Wed Nov 17 22:13:34 2010 +0000
+++ b/multichoicedialog.cpp	Thu Nov 18 15:14:39 2010 +0000
@@ -17,7 +17,16 @@
 
 #include "multichoicedialog.h"
 
+#include "selectablelabel.h"
+
+#include "debug.h"
+
 #include <QDialogButtonBox>
+#include <QToolButton>
+#include <QPushButton>
+#include <QFont>
+#include <QDir>
+#include <QFileDialog>
 
 MultiChoiceDialog::MultiChoiceDialog(QString title, QString heading, QWidget *parent) :
     QDialog(parent)
@@ -31,26 +40,204 @@
     outer->addWidget(new QLabel(heading), 0, 0, 1, 3);
 
     QWidget *innerWidget = new QWidget;
-    outer->addWidget(innerWidget, 1, 0, 1, 2);
-    m_choiceLayout = new QGridLayout;
+    outer->addWidget(innerWidget, 1, 0, 1, 3);
+    m_choiceLayout = new QHBoxLayout;
     innerWidget->setLayout(m_choiceLayout);
 
     m_descriptionLabel = new QLabel;
     outer->addWidget(m_descriptionLabel, 2, 0, 1, 3);
 
+    QFont f = m_descriptionLabel->font();
+    f.setPointSize(f.pointSize() * 0.9);
+    m_descriptionLabel->setFont(f);
+
     m_argLabel = new QLabel();
     outer->addWidget(m_argLabel, 3, 0);
 
-    m_argEdit = new QLineEdit();
+    m_argEdit = new QComboBox();
+    m_argEdit->setEditable(true);
     outer->addWidget(m_argEdit, 3, 1);
+    outer->setColumnStretch(1, 20);
 
     m_browseButton = new QPushButton(tr("Browse..."));
     outer->addWidget(m_browseButton, 3, 2);
+    connect(m_browseButton, SIGNAL(clicked()), this, SLOT(browse()));
 
     QDialogButtonBox *bbox = new QDialogButtonBox(QDialogButtonBox::Ok |
                                                   QDialogButtonBox::Cancel);
     connect(bbox, SIGNAL(accepted()), this, SLOT(accept()));
     connect(bbox, SIGNAL(rejected()), this, SLOT(reject()));
     outer->addWidget(bbox, 4, 0, 1, 3);
+    
+    setMinimumWidth(480);
 }
 
+QString
+MultiChoiceDialog::getCurrentChoice()
+{
+    return m_currentChoice;
+}
+
+void
+MultiChoiceDialog::setCurrentChoice(QString c)
+{
+    m_currentChoice = c;
+    choiceChanged();
+}
+
+QString
+MultiChoiceDialog::getArgument()
+{
+    return m_argEdit->currentText();
+}
+
+void
+MultiChoiceDialog::addRecentArgument(QString id, QString arg)
+{
+    RecentFiles(QString("Recent-%1").arg(id)).addFile(arg);
+}
+
+void
+MultiChoiceDialog::addChoice(QString id, QString text,
+                             QString description, ArgType arg)
+{
+    bool first = (m_texts.empty());
+
+    m_texts[id] = text;
+    m_descriptions[id] = description;
+    m_argTypes[id] = arg;
+    
+    if (arg != NoArg) {
+        m_recentFiles[id] = QSharedPointer<RecentFiles>
+            (new RecentFiles(QString("Recent-%1").arg(id)));
+    }
+
+    SelectableLabel *cb = new SelectableLabel;
+    cb->setSelectedText(text);
+    cb->setUnselectedText(text);
+
+    m_choiceLayout->addWidget(cb);
+    m_choiceButtons[cb] = id;
+
+    connect(cb, SIGNAL(selectionChanged()), this, SLOT(choiceChanged()));
+
+    if (first) {
+        m_currentChoice = id;
+        choiceChanged();
+    }
+}
+
+void
+MultiChoiceDialog::browse()
+{
+    QString origin = getArgument();
+
+    if (origin == "") {
+#ifdef Q_OS_WIN32
+        origin = "c:";
+#else
+        origin = QDir::homePath();
+#endif
+    }
+
+    QString path = origin;
+
+    if (m_argTypes[m_currentChoice] == DirectoryArg) {
+
+        path = QFileDialog::getExistingDirectory
+            (this, tr("Open Directory"), origin,
+             QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+        if (path != QString()) {
+            m_argEdit->lineEdit()->setText(path + QDir::separator());
+        }
+
+    } else {
+
+        path = QFileDialog::getOpenFileName
+            (this, tr("Open File"), origin);
+        if (path != QString()) {
+            m_argEdit->lineEdit()->setText(path);
+        }
+    }
+}
+
+void
+MultiChoiceDialog::choiceChanged()
+{
+    DEBUG << "choiceChanged" << endl;
+
+    if (m_choiceButtons.empty()) return;
+
+    QString id = "";
+
+    QObject *s = sender();
+    QWidget *w = qobject_cast<QWidget *>(s);
+    if (w) id = m_choiceButtons[w];
+
+    if (id == m_currentChoice) return;
+    if (id == "") {
+        // Happens when this is called for the very first time, when
+        // m_currentChoice has been set to the intended ID but no
+        // button has actually been pressed -- then we need to
+        // initialise
+        id = m_currentChoice;
+    }
+
+    m_currentChoice = id;
+
+    foreach (QWidget *cw, m_choiceButtons.keys()) {
+        SelectableLabel *sl = qobject_cast<SelectableLabel *>(cw);
+        if (sl) {
+            sl->setSelected(m_choiceButtons[cw] == id);
+        }
+    }
+
+    m_descriptionLabel->setText(m_descriptions[id]);
+
+    switch (m_argTypes[id]) {
+        
+    case NoArg:
+        m_argLabel->hide();
+        m_argEdit->hide();
+        m_browseButton->hide();
+        break;
+
+    case FileArg:
+        m_argLabel->setText(tr("File:"));
+        m_argLabel->show();
+        m_argEdit->show();
+        m_browseButton->show();
+        break;
+
+    case DirectoryArg:
+        m_argLabel->setText(tr("Folder:"));
+        m_argLabel->show();
+        m_argEdit->show();
+        m_browseButton->show();
+        break;
+
+    case UrlArg:
+        m_argLabel->setText(tr("URL:"));
+        m_argLabel->show();
+        m_argEdit->show();
+        m_browseButton->hide();
+        break;
+
+    case FileOrUrlArg:
+        m_argLabel->setText(tr("File or URL:"));
+        m_argLabel->show();
+        m_argEdit->show();
+        m_browseButton->show();
+        break;
+    }
+
+    if (m_argTypes[id] != NoArg) {
+        QSharedPointer<RecentFiles> rf = m_recentFiles[id];
+        m_argEdit->clear();
+        m_argEdit->addItems(rf->getRecent());
+    }
+
+    adjustSize();
+}
+
+
--- a/multichoicedialog.h	Wed Nov 17 22:13:34 2010 +0000
+++ b/multichoicedialog.h	Thu Nov 18 15:14:39 2010 +0000
@@ -18,24 +18,31 @@
 #ifndef MULTICHOICEDIALOG_H
 #define MULTICHOICEDIALOG_H
 
+#include "recentfiles.h"
+
 #include <QDialog>
 #include <QString>
-#include <QPushButton>
+#include <QAbstractButton>
 #include <QMap>
 #include <QLabel>
 #include <QLineEdit>
 #include <QGridLayout>
+#include <QHBoxLayout>
 #include <QStackedWidget>
+#include <QSharedPointer>
+#include <QComboBox>
 
 class MultiChoiceDialog : public QDialog
 {
     Q_OBJECT
 public:
-    explicit MultiChoiceDialog(QString title, QString heading, QWidget *parent = 0);
+    explicit MultiChoiceDialog(QString title, QString heading,
+                               QWidget *parent = 0);
 
     enum ArgType {
         NoArg,
         FileArg,
+        DirectoryArg,
         UrlArg,
         FileOrUrlArg
     };
@@ -43,29 +50,30 @@
     void addChoice(QString identifier, QString text,
                    QString description, ArgType arg);
 
-    QString getSelectedIdentifier();
+    void setCurrentChoice(QString);
+    QString getCurrentChoice();
     QString getArgument();
 
-signals:
+    static void addRecentArgument(QString identifier, QString name);
 
 private slots:
-
+    void choiceChanged();
+    void browse();
 
 private:
-    void updateArgWidgets(); // when choice changes
-
     QMap<QString, QString> m_texts;
     QMap<QString, QString> m_descriptions;
+    QMap<QString, ArgType> m_argTypes;
+    QMap<QString, QSharedPointer<RecentFiles> > m_recentFiles;
 
     QString m_currentChoice;
-    QMap<QString, QPushButton *> m_choiceButtons;
+    QMap<QWidget *, QString> m_choiceButtons;
 
-    QGridLayout *m_choiceLayout;
+    QHBoxLayout *m_choiceLayout;
     QLabel *m_descriptionLabel;
     QLabel *m_argLabel;
-    QLineEdit *m_argEdit;
-    QPushButton *m_browseButton;
-
+    QComboBox *m_argEdit;
+    QAbstractButton *m_browseButton;
 };
 
 #endif // MULTICHOICEDIALOG_H
--- a/recentfiles.h	Wed Nov 17 22:13:34 2010 +0000
+++ b/recentfiles.h	Thu Nov 18 15:14:39 2010 +0000
@@ -59,10 +59,9 @@
      * Add a name that is known to be either a file path or a URL.  If
      * it looks like a URL, add it literally; otherwise treat it as a
      * file path and canonicalise it appropriately.  Also takes into
-     * account the user preference for whether to include temporary
-     * files in the recent files menu: the file will not be added if
-     * the preference is set and the file appears to be a temporary
-     * one.
+     * account the preference for whether to include temporary files
+     * in the recent files menu: the file will not be added if the
+     * preference is set and the file appears to be a temporary one.
      */
     void addFile(QString name);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/selectablelabel.cpp	Thu Nov 18 15:14:39 2010 +0000
@@ -0,0 +1,151 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    EasyMercurial
+
+    Based on HgExplorer by Jari Korhonen
+    Copyright (c) 2010 Jari Korhonen
+    Copyright (c) 2010 Chris Cannam
+    Copyright (c) 2010 Queen Mary, University of London
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "selectablelabel.h"
+
+#include "debug.h"
+
+#include <iostream>
+#include <QApplication>
+
+SelectableLabel::SelectableLabel(QWidget *p) :
+    QLabel(p),
+    m_selected(false)
+{
+    setTextFormat(Qt::RichText);
+//    setLineWidth(2);
+//    setFixedWidth(480);
+    setupStyle();
+    setOpenExternalLinks(true);
+}
+
+SelectableLabel::~SelectableLabel()
+{
+}
+
+void
+SelectableLabel::setUnselectedText(QString text)
+{
+    if (m_unselectedText == text) return;
+    m_unselectedText = text;
+    if (!m_selected) {
+        setText(m_unselectedText);
+        resize(sizeHint());
+    }
+}
+
+void
+SelectableLabel::setSelectedText(QString text)
+{
+    if (m_selectedText == text) return;
+    m_selectedText = text;
+    if (m_selected) {
+        setText(m_selectedText);
+        resize(sizeHint());
+    }
+}
+
+void
+SelectableLabel::setupStyle()
+{
+    QPalette palette = QApplication::palette();
+
+    setTextInteractionFlags(Qt::LinksAccessibleByKeyboard |
+                            Qt::LinksAccessibleByMouse |
+                            Qt::TextSelectableByMouse);
+
+    if (m_selected) {
+        setStyleSheet
+            (QString("QLabel:hover { background: %1; color: %3; } "
+                     "QLabel:!hover { background: %2; color: %3 } "
+                     "QLabel { padding: 7px }")
+             .arg(palette.highlight().color().name())
+             .arg(palette.highlight().color().name())
+             .arg(palette.text().color().name()));
+    } else {
+        setStyleSheet
+            (QString("QLabel:hover { background: %1; color: %3; } "
+                     "QLabel:!hover { background: %2; color: %3 } "
+                     "QLabel { padding: 7px }")
+             .arg(palette.button().color().name())
+             .arg(palette.light().color().name())
+             .arg(palette.text().color().name()));
+    }
+}    
+
+void
+SelectableLabel::setSelected(bool s)
+{
+    if (m_selected == s) return;
+    m_selected = s;
+    if (m_selected) {
+        setText(m_selectedText);
+    } else {
+        setText(m_unselectedText);
+    }
+    setupStyle();
+    parentWidget()->resize(parentWidget()->sizeHint());
+}
+
+void
+SelectableLabel::toggle()
+{
+    setSelected(!m_selected);
+}
+
+void
+SelectableLabel::mousePressEvent(QMouseEvent *e)
+{
+    m_swallowRelease = !m_selected;
+    setSelected(true);
+    QLabel::mousePressEvent(e);
+    emit selectionChanged();
+}
+
+void
+SelectableLabel::mouseDoubleClickEvent(QMouseEvent *e)
+{
+    QLabel::mouseDoubleClickEvent(e);
+    emit doubleClicked();
+}
+
+void
+SelectableLabel::mouseReleaseEvent(QMouseEvent *e)
+{
+    if (!m_swallowRelease) QLabel::mouseReleaseEvent(e);
+    m_swallowRelease = false;
+}
+
+void
+SelectableLabel::enterEvent(QEvent *)
+{
+//    std::cerr << "enterEvent" << std::endl;
+//    QPalette palette = QApplication::palette();
+//    palette.setColor(QPalette::Window, Qt::gray);
+//    setStyleSheet("background: gray");
+//    setPalette(palette);
+}
+
+void
+SelectableLabel::leaveEvent(QEvent *)
+{
+//    std::cerr << "leaveEvent" << std::endl;
+//    setStyleSheet("background: white");
+//    QPalette palette = QApplication::palette();
+//    palette.setColor(QPalette::Window, Qt::gray);
+//    setPalette(palette);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/selectablelabel.h	Thu Nov 18 15:14:39 2010 +0000
@@ -0,0 +1,57 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    EasyMercurial
+
+    Based on HgExplorer by Jari Korhonen
+    Copyright (c) 2010 Jari Korhonen
+    Copyright (c) 2010 Chris Cannam
+    Copyright (c) 2010 Queen Mary, University of London
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef _SELECTABLE_LABEL_H_
+#define _SELECTABLE_LABEL_H_
+
+#include <QLabel>
+
+class SelectableLabel : public QLabel
+{
+    Q_OBJECT
+
+public:
+    SelectableLabel(QWidget *parent = 0);
+    virtual ~SelectableLabel();
+
+    void setSelectedText(QString);
+    void setUnselectedText(QString);
+
+    bool isSelected() const { return m_selected; }
+
+signals:
+    void selectionChanged();
+    void doubleClicked();
+
+public slots:
+    void setSelected(bool);
+    void toggle();
+
+protected:
+    virtual void mousePressEvent(QMouseEvent *e);
+    virtual void mouseReleaseEvent(QMouseEvent *e);
+    virtual void mouseDoubleClickEvent(QMouseEvent *e);
+    virtual void enterEvent(QEvent *);
+    virtual void leaveEvent(QEvent *);
+    void setupStyle();
+    QString m_selectedText;
+    QString m_unselectedText;
+    bool m_selected;
+    bool m_swallowRelease;
+};
+
+#endif