changeset 199:f16fe0db11f3

* Add "Show All Files" toggle to show ignored and clean files * Clear selection when Esc is pressed * Don't delete and recreate the filesystem watcher on stat, just update it
author Chris Cannam
date Mon, 03 Jan 2011 22:02:08 +0000
parents 4adbd5c9c15d
children 8c8c04bdf0fa
files filestates.cpp filestates.h filestatuswidget.cpp filestatuswidget.h hgtabwidget.cpp hgtabwidget.h mainwindow.cpp mainwindow.h multichoicedialog.cpp multichoicedialog.h
diffstat 10 files changed, 113 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/filestates.cpp	Mon Jan 03 14:31:22 2011 +0000
+++ b/filestates.cpp	Mon Jan 03 22:02:08 2011 +0000
@@ -27,12 +27,14 @@
 
 void FileStates::clearBuckets()
 {
+    m_clean.clear();
     m_modified.clear();
     m_added.clear();
     m_removed.clear();
     m_missing.clear();
     m_inConflict.clear();
     m_unknown.clear();
+    m_ignored.clear();
 }
 
 FileStates::State FileStates::charToState(QChar c, bool *ok)
@@ -53,6 +55,7 @@
     if (c == 'U') return InConflict;
     if (c == '?') return Unknown;
     if (c == 'C') return Clean;
+    if (c == 'I') return Ignored;
     if (ok) *ok = false;
     return Unknown;
 }
@@ -60,13 +63,14 @@
 QStringList *FileStates::stateToBucket(State s)
 {
     switch (s) {
-    case Clean: default: return 0; // not implemented yet
+    case Clean: return &m_clean; // not implemented yet
     case Modified: return &m_modified;
     case Added: return &m_added;
     case Unknown: return &m_unknown;
     case Removed: return &m_removed;
     case Missing: return &m_missing;
     case InConflict: return &m_inConflict;
+    case Ignored: return &m_ignored;
     }
 }
 
@@ -95,12 +99,12 @@
     }
 
     foreach (QString file, m_stateMap.keys()) {
-
         QStringList *bucket = stateToBucket(m_stateMap[file]);
-        bucket->push_back(file);
+        if (bucket) bucket->push_back(file);
     }
 
-    DEBUG << "FileStates: " << m_modified.size() << " modified, " << m_added.size()
+    DEBUG << "FileStates: "
+          << m_modified.size() << " modified, " << m_added.size()
           << " added, " << m_removed.size() << " removed, " << m_missing.size()
           << " missing, " << m_inConflict.size() << " in conflict, "
           << m_unknown.size() << " unknown" << endl;
--- a/filestates.h	Mon Jan 03 14:31:22 2011 +0000
+++ b/filestates.h	Mon Jan 03 22:02:08 2011 +0000
@@ -39,9 +39,10 @@
         Missing,
         Clean,
         Unknown,
+        Ignored,
 
         FirstState = Modified,
-        LastState = Unknown
+        LastState = Ignored
     };
 
     void parseStates(QString text);
@@ -56,6 +57,8 @@
     QStringList removed() const { return m_removed; }
     QStringList missing() const { return m_missing; }
     QStringList inConflict() const { return m_inConflict; }
+    QStringList clean() const { return m_clean; }
+    QStringList ignored() const { return m_ignored; }
 
     State getStateOfFile(QString file) const;
 
@@ -66,6 +69,8 @@
     QStringList m_removed;
     QStringList m_missing;
     QStringList m_inConflict;
+    QStringList m_clean;
+    QStringList m_ignored;
     QMap<QString, State> m_stateMap;
 
     State charToState(QChar, bool * = 0);
--- a/filestatuswidget.cpp	Mon Jan 03 14:31:22 2011 +0000
+++ b/filestatuswidget.cpp	Mon Jan 03 22:02:08 2011 +0000
@@ -30,6 +30,7 @@
 #include <QToolButton>
 #include <QDir>
 #include <QProcess>
+#include <QCheckBox>
 
 FileStatusWidget::FileStatusWidget(QWidget *parent) :
     QWidget(parent),
@@ -79,6 +80,7 @@
     m_simpleLabels[FileStates::Missing] = tr("Missing:");
     m_simpleLabels[FileStates::InConflict] = tr("In Conflict:");
     m_simpleLabels[FileStates::Unknown] = tr("Untracked:");
+    m_simpleLabels[FileStates::Ignored] = tr("Ignored:");
 
     m_descriptions[FileStates::Clean] = tr("You have not changed these files.");
     m_descriptions[FileStates::Modified] = tr("You have changed these files since you last committed them.");
@@ -92,6 +94,8 @@
     m_descriptions[FileStates::Unknown] = tr("These files are in your working folder but are not under version control.<br>"
 //                                             "Select a file and use Add to place it under version control or Ignore to remove it from this list.");
                                              "Select a file and use Add to place it under version control.");
+    m_descriptions[FileStates::Ignored] = tr("These files have names that match entries in the working folder's .hgignore file,<br>"
+                                             "and so will be ignored by the version control system.");
 
     m_highlightExplanation = tr("Files highlighted <font color=#d40000>in red</font> "
                                 "have appeared since your most recent commit or update.");
@@ -124,6 +128,12 @@
 
     layout->setRowStretch(++row, 20);
 
+    layout->addItem(new QSpacerItem(1, 1), ++row, 0);
+
+    m_showAllFiles = new QCheckBox(tr("Show all files"), this);
+    layout->addWidget(m_showAllFiles, ++row, 0, 1, 3, Qt::AlignLeft);
+    connect(m_showAllFiles, SIGNAL(toggled(bool)),
+            this, SIGNAL(showAllChanged(bool)));
 }
 
 FileStatusWidget::~FileStatusWidget()
--- a/filestatuswidget.h	Mon Jan 03 14:31:22 2011 +0000
+++ b/filestatuswidget.h	Mon Jan 03 22:02:08 2011 +0000
@@ -27,6 +27,7 @@
 class QPushButton;
 class QFileInfo;
 class ClickableLabel;
+class QCheckBox;
 
 class FileStatusWidget : public QWidget
 {
@@ -70,6 +71,7 @@
     
 signals:
     void selectionChanged();
+    void showAllChanged(bool);
 
 public slots:
     void clearSelections();
@@ -90,6 +92,8 @@
     
     QLabel *m_noModificationsLabel;
 
+    QCheckBox *m_showAllFiles;
+    
     FileStates m_fileStates;
     QMap<FileStates::State, QString> m_simpleLabels;
     QMap<FileStates::State, QString> m_descriptions;
--- a/hgtabwidget.cpp	Mon Jan 03 14:31:22 2011 +0000
+++ b/hgtabwidget.cpp	Mon Jan 03 22:02:08 2011 +0000
@@ -37,6 +37,8 @@
     m_fileStatusWidget->setRemoteURL(remoteRepo);
     connect(m_fileStatusWidget, SIGNAL(selectionChanged()),
             this, SIGNAL(selectionChanged()));
+    connect(m_fileStatusWidget, SIGNAL(showAllChanged(bool)),
+            this, SIGNAL(showAllChanged(bool)));
     addTab(m_fileStatusWidget, tr("My work"));
 
     // History graph page
--- a/hgtabwidget.h	Mon Jan 03 14:31:22 2011 +0000
+++ b/hgtabwidget.h	Mon Jan 03 22:02:08 2011 +0000
@@ -81,6 +81,7 @@
 
 signals:
     void selectionChanged();
+    void showAllChanged(bool);
 
     void commit();
     void revert();
--- a/mainwindow.cpp	Mon Jan 03 14:31:22 2011 +0000
+++ b/mainwindow.cpp	Mon Jan 03 22:02:08 2011 +0000
@@ -30,6 +30,7 @@
 #include <QSettings>
 #include <QInputDialog>
 #include <QRegExp>
+#include <QShortcut>
 
 #include "mainwindow.h"
 #include "multichoicedialog.h"
@@ -49,6 +50,8 @@
 
     QString wndTitle;
 
+    showAllFiles = false;
+
     fsWatcher = 0;
     commitsSincePush = 0;
     shouldHgStat = true;
@@ -79,6 +82,8 @@
 
     connect(hgTabs, SIGNAL(selectionChanged()),
             this, SLOT(enableDisableActions()));
+    connect(hgTabs, SIGNAL(showAllChanged(bool)),
+            this, SLOT(showAllChanged(bool)));
 
     setUnifiedTitleAndToolBarOnMac(true);
     connectActions();
@@ -170,6 +175,12 @@
     hgTabs->clearSelections();
 }
 
+void MainWindow::showAllChanged(bool s)
+{
+    showAllFiles = s;
+    hgQueryPaths();
+}
+
 void MainWindow::hgRefresh()
 {
     clearState();
@@ -186,7 +197,12 @@
 void MainWindow::hgStat()
 {
     QStringList params;
-    params << "stat" << "-ardum";
+
+    if (showAllFiles) {
+        params << "stat" << "-A";
+    } else {
+        params << "stat" << "-ardum";
+    }
 
     lastStatOutput = "";
 
@@ -867,6 +883,10 @@
     mergeCommitComment = "";
     stateUnknown = true;
     needNewLog = true;
+    if (fsWatcher) {
+        delete fsWatcher;
+        fsWatcher = 0;
+    }
 }
 
 void MainWindow::hgServe()
@@ -1283,29 +1303,51 @@
 
 void MainWindow::updateFileSystemWatcher()
 {
-    delete fsWatcher;
-    fsWatcher = new QFileSystemWatcher();
+    bool justCreated = false;
+    if (!fsWatcher) {
+        fsWatcher = new QFileSystemWatcher();
+        justCreated = true;
+    }
+
+    // QFileSystemWatcher will refuse to add a file or directory to
+    // its watch list that it is already watching -- fine, that's what
+    // we want -- but it prints a warning when this happens, which is
+    // annoying because it would be the normal case for us.  So we'll
+    // check for duplicates ourselves.
+    QSet<QString> alreadyWatched;
+    QStringList dl(fsWatcher->directories());
+    foreach (QString d, dl) alreadyWatched.insert(d);
+    
     std::deque<QString> pending;
     pending.push_back(workFolderPath);
+
     while (!pending.empty()) {
+
         QString path = pending.front();
         pending.pop_front();
-        fsWatcher->addPath(path);
-        DEBUG << "Added to file system watcher: " << path << endl;
+        if (!alreadyWatched.contains(path)) {
+            fsWatcher->addPath(path);
+            DEBUG << "Added to file system watcher: " << path << endl;
+        }
+
         QDir d(path);
         if (d.exists()) {
-            d.setFilter(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable);
+            d.setFilter(QDir::Dirs | QDir::NoDotAndDotDot |
+                        QDir::Readable | QDir::NoSymLinks);
             foreach (QString entry, d.entryList()) {
-                if (entry == ".hg") continue;
+                if (entry.startsWith('.')) continue;
                 QString entryPath = d.absoluteFilePath(entry);
                 pending.push_back(entryPath);
             }
         }
     }
-    connect(fsWatcher, SIGNAL(directoryChanged(QString)),
-            this, SLOT(fsDirectoryChanged(QString)));
-    connect(fsWatcher, SIGNAL(fileChanged(QString)),
-            this, SLOT(fsFileChanged(QString)));
+
+    if (justCreated) {
+        connect(fsWatcher, SIGNAL(directoryChanged(QString)),
+                this, SLOT(fsDirectoryChanged(QString)));
+        connect(fsWatcher, SIGNAL(fileChanged(QString)),
+                this, SLOT(fsFileChanged(QString)));
+    }
 }
 
 void MainWindow::fsDirectoryChanged(QString d)
@@ -1434,7 +1476,6 @@
 void MainWindow::commandFailed(HgAction action, QString output)
 {
     DEBUG << "MainWindow::commandFailed" << endl;
-    if (fsWatcher) fsWatcher->blockSignals(false);
 
     // Some commands we just have to ignore bad return values from:
 
@@ -1473,6 +1514,9 @@
             reportNewRemoteHeads(output);
             return;
         }
+    case ACT_STAT:
+        if (fsWatcher) fsWatcher->blockSignals(false);
+        break; // go on and report
     default:
         break;
     }
@@ -1500,7 +1544,6 @@
 void MainWindow::commandCompleted(HgAction completedAction, QString output)
 {
     HGACTIONS action = completedAction.action;
-    if (fsWatcher) fsWatcher->blockSignals(false);
 
     if (action == ACT_NONE) return;
 
@@ -1535,6 +1578,7 @@
     case ACT_STAT:
         lastStatOutput = output;
         updateFileSystemWatcher();
+        if (fsWatcher) fsWatcher->blockSignals(false);
         break;
 
     case ACT_RESOLVE_LIST:
@@ -1549,7 +1593,7 @@
             output = winnowed.join("\n");
         }
         DEBUG << "lastStatOutput = " << lastStatOutput << endl;
-        DEBUG << "output = " << output << endl;
+        DEBUG << "resolve output = " << output << endl;
         hgTabs->updateWorkFolderFileList(lastStatOutput + output);
         break;
 
@@ -1784,7 +1828,6 @@
 
     connect(hgAnnotateAct, SIGNAL(triggered()), this, SLOT(hgAnnotate()));
     connect(hgServeAct, SIGNAL(triggered()), this, SLOT(hgServe()));
-    connect(clearSelectionsAct, SIGNAL(triggered()), this, SLOT(clearSelections()));
 }
 
 void MainWindow::connectTabsSignals()
@@ -1973,7 +2016,7 @@
 {
     //File actions
     openAct = new QAction(QIcon(":/images/fileopen.png"), tr("Open..."), this);
-    openAct -> setStatusTip(tr("Open a repository"));
+    openAct -> setStatusTip(tr("Open an existing repository or working folder"));
 
     changeRemoteRepoAct = new QAction(tr("Change Remote Location..."), this);
     changeRemoteRepoAct->setStatusTip(tr("Change the default remote repository for pull and push actions"));
@@ -2037,8 +2080,9 @@
     aboutAct = new QAction(tr("About EasyMercurial"), this);
 
     // Miscellaneous
-    clearSelectionsAct = new QAction(tr("Clear selections"), this);
-    clearSelectionsAct->setShortcut(Qt::Key_Escape);
+    QShortcut *clearSelectionsShortcut = new QShortcut(Qt::Key_Escape, this);
+    connect(clearSelectionsShortcut, SIGNAL(activated()),
+            this, SLOT(clearSelections()));
 }
 
 void MainWindow::createMenus()
@@ -2057,6 +2101,7 @@
     fileMenu -> addAction(exitAct);
 
     advancedMenu -> addAction(hgIgnoreAct);
+    advancedMenu -> addSeparator();
     advancedMenu -> addAction(hgServeAct);
 
     helpMenu = menuBar()->addMenu(tr("Help"));
--- a/mainwindow.h	Mon Jan 03 14:31:22 2011 +0000
+++ b/mainwindow.h	Mon Jan 03 22:02:08 2011 +0000
@@ -71,6 +71,7 @@
     void changeRemoteRepo();
     void startupDialog();
     void clearSelections();
+    void showAllChanged(bool);
 
     void hgTest();
     void hgQueryPaths();
@@ -154,6 +155,8 @@
 
     bool firstStart;
 
+    bool showAllFiles;
+
     //Actions enabled flags
     bool remoteRepoActionsEnabled;
     bool localRepoActionsEnabled;
@@ -192,9 +195,6 @@
     //Help menu actions
     QAction *aboutAct;
 
-    // Other actions
-    QAction *clearSelectionsAct;
-
     QToolBar *fileToolBar;
     QToolBar *repoToolBar;
     QToolBar *workFolderToolBar;
--- a/multichoicedialog.cpp	Mon Jan 03 14:31:22 2011 +0000
+++ b/multichoicedialog.cpp	Mon Jan 03 22:02:08 2011 +0000
@@ -84,7 +84,7 @@
     outer->addWidget(bbox, 5, 0, 1, 3);
 
     m_okButton = bbox->button(QDialogButtonBox::Ok);
-    m_okButton->setEnabled(false);
+    updateOkButton();
 
     setMinimumWidth(480);
 }
@@ -203,6 +203,18 @@
 void
 MultiChoiceDialog::urlChanged(const QString &s)
 {
+    updateOkButton();
+}
+
+void
+MultiChoiceDialog::fileChanged(const QString &s)
+{
+    updateOkButton();
+}
+
+void
+MultiChoiceDialog::updateOkButton()
+{
 /* This doesn't work well
     if (m_argTypes[m_currentChoice] != UrlToDirectoryArg) {
         return;
@@ -231,17 +243,6 @@
 }
 
 void
-MultiChoiceDialog::fileChanged(const QString &s)
-{
-    if (m_argTypes[m_currentChoice] == UrlToDirectoryArg) {
-        m_okButton->setEnabled(getArgument() != "" &&
-                               getAdditionalArgument() != "");
-    } else {
-        m_okButton->setEnabled(getArgument() != "");
-    }
-}
-
-void
 MultiChoiceDialog::choiceChanged()
 {
     DEBUG << "choiceChanged" << endl;
@@ -323,6 +324,7 @@
         break;
     }
 
+    updateOkButton();
     adjustSize();
 }
 
--- a/multichoicedialog.h	Mon Jan 03 14:31:22 2011 +0000
+++ b/multichoicedialog.h	Mon Jan 03 22:02:08 2011 +0000
@@ -65,6 +65,8 @@
     void browse();
 
 private:
+    void updateOkButton();
+    
     QMap<QString, QString> m_texts;
     QMap<QString, QString> m_descriptions;
     QMap<QString, ArgType> m_argTypes;