Mercurial > hg > easyhg
comparison src/mainwindow.cpp @ 540:fc2df97920e8 fswatcher
Introduce FsWatcher into main window (though it isn't fully rigged up yet)
author | Chris Cannam |
---|---|
date | Mon, 13 Feb 2012 17:29:06 +0000 |
parents | a4e699d32a9a |
children | 0a16db274f2c |
comparison
equal
deleted
inserted
replaced
539:3935a7e621ca | 540:fc2df97920e8 |
---|---|
50 #include "annotatedialog.h" | 50 #include "annotatedialog.h" |
51 #include "version.h" | 51 #include "version.h" |
52 #include "workstatuswidget.h" | 52 #include "workstatuswidget.h" |
53 #include "hgignoredialog.h" | 53 #include "hgignoredialog.h" |
54 #include "versiontester.h" | 54 #include "versiontester.h" |
55 #include "fswatcher.h" | |
55 | 56 |
56 | 57 |
57 MainWindow::MainWindow(QString myDirPath) : | 58 MainWindow::MainWindow(QString myDirPath) : |
58 m_myDirPath(myDirPath), | 59 m_myDirPath(myDirPath), |
59 m_helpDialog(0), | 60 m_helpDialog(0) |
60 m_fsWatcherGeneralTimer(0), | |
61 m_fsWatcherRestoreTimer(0), | |
62 m_fsWatcherSuspended(false) | |
63 { | 61 { |
64 setWindowIcon(QIcon(":images/easyhg-icon.png")); | 62 setWindowIcon(QIcon(":images/easyhg-icon.png")); |
65 | 63 |
66 QString wndTitle; | 64 QString wndTitle; |
67 | 65 |
68 m_showAllFiles = false; | 66 m_showAllFiles = false; |
69 | 67 |
70 m_fsWatcher = 0; | 68 m_fsWatcher = new FsWatcher(); |
69 m_fsWatcherToken = m_fsWatcher->getNewToken(); | |
70 m_commandSequenceInProgress = false; | |
71 connect(m_fsWatcher, SIGNAL(changed()), this, SLOT(fsWatcherChanged())); | |
72 | |
71 m_commitsSincePush = 0; | 73 m_commitsSincePush = 0; |
72 m_shouldHgStat = true; | 74 m_shouldHgStat = true; |
73 | 75 |
74 createActions(); | 76 createActions(); |
75 createMenus(); | 77 createMenus(); |
1299 m_lastRevertedFiles.clear(); | 1301 m_lastRevertedFiles.clear(); |
1300 m_mergeTargetRevision = ""; | 1302 m_mergeTargetRevision = ""; |
1301 m_mergeCommitComment = ""; | 1303 m_mergeCommitComment = ""; |
1302 m_stateUnknown = true; | 1304 m_stateUnknown = true; |
1303 m_needNewLog = true; | 1305 m_needNewLog = true; |
1304 if (m_fsWatcher) { | |
1305 delete m_fsWatcherGeneralTimer; | |
1306 m_fsWatcherGeneralTimer = 0; | |
1307 delete m_fsWatcherRestoreTimer; | |
1308 m_fsWatcherRestoreTimer = 0; | |
1309 delete m_fsWatcher; | |
1310 m_fsWatcher = 0; | |
1311 } | |
1312 } | 1306 } |
1313 | 1307 |
1314 void MainWindow::hgServe() | 1308 void MainWindow::hgServe() |
1315 { | 1309 { |
1316 QStringList params; | 1310 QStringList params; |
1819 updateToolBarStyle(); | 1813 updateToolBarStyle(); |
1820 hgRefresh(); | 1814 hgRefresh(); |
1821 } | 1815 } |
1822 } | 1816 } |
1823 | 1817 |
1824 void MainWindow::updateFileSystemWatcher() | |
1825 { | |
1826 bool justCreated = false; | |
1827 if (!m_fsWatcher) { | |
1828 m_fsWatcher = new QFileSystemWatcher(); | |
1829 justCreated = true; | |
1830 } | |
1831 | |
1832 // QFileSystemWatcher will refuse to add a file or directory to | |
1833 // its watch list that it is already watching -- fine, that's what | |
1834 // we want -- but it prints a warning when this happens, which is | |
1835 // annoying because it would be the normal case for us. So we'll | |
1836 // check for duplicates ourselves. | |
1837 QSet<QString> alreadyWatched; | |
1838 QStringList dl(m_fsWatcher->directories()); | |
1839 foreach (QString d, dl) alreadyWatched.insert(d); | |
1840 | |
1841 std::deque<QString> pending; | |
1842 pending.push_back(m_workFolderPath); | |
1843 | |
1844 while (!pending.empty()) { | |
1845 | |
1846 QString path = pending.front(); | |
1847 pending.pop_front(); | |
1848 if (!alreadyWatched.contains(path)) { | |
1849 m_fsWatcher->addPath(path); | |
1850 DEBUG << "Added to file system watcher: " << path << endl; | |
1851 } | |
1852 | |
1853 QDir d(path); | |
1854 if (d.exists()) { | |
1855 d.setFilter(QDir::Dirs | QDir::NoDotAndDotDot | | |
1856 QDir::Readable | QDir::NoSymLinks); | |
1857 foreach (QString entry, d.entryList()) { | |
1858 if (entry.startsWith('.')) continue; | |
1859 QString entryPath = d.absoluteFilePath(entry); | |
1860 pending.push_back(entryPath); | |
1861 } | |
1862 } | |
1863 } | |
1864 | |
1865 // The general timer isn't really related to the fs watcher | |
1866 // object, it just does something similar -- every now and then we | |
1867 // do a refresh just to update the history dates etc | |
1868 | |
1869 m_fsWatcherGeneralTimer = new QTimer(this); | |
1870 connect(m_fsWatcherGeneralTimer, SIGNAL(timeout()), | |
1871 this, SLOT(checkFilesystem())); | |
1872 m_fsWatcherGeneralTimer->setInterval(30 * 60 * 1000); // half an hour | |
1873 m_fsWatcherGeneralTimer->start(); | |
1874 | |
1875 if (justCreated) { | |
1876 connect(m_fsWatcher, SIGNAL(directoryChanged(QString)), | |
1877 this, SLOT(fsDirectoryChanged(QString))); | |
1878 connect(m_fsWatcher, SIGNAL(fileChanged(QString)), | |
1879 this, SLOT(fsFileChanged(QString))); | |
1880 } | |
1881 } | |
1882 | |
1883 void MainWindow::suspendFileSystemWatcher() | |
1884 { | |
1885 DEBUG << "MainWindow::suspendFileSystemWatcher" << endl; | |
1886 if (m_fsWatcher) { | |
1887 m_fsWatcherSuspended = true; | |
1888 if (m_fsWatcherRestoreTimer) { | |
1889 delete m_fsWatcherRestoreTimer; | |
1890 m_fsWatcherRestoreTimer = 0; | |
1891 } | |
1892 m_fsWatcherGeneralTimer->stop(); | |
1893 } | |
1894 } | |
1895 | |
1896 void MainWindow::restoreFileSystemWatcher() | |
1897 { | |
1898 DEBUG << "MainWindow::restoreFileSystemWatcher" << endl; | |
1899 if (m_fsWatcherRestoreTimer) delete m_fsWatcherRestoreTimer; | |
1900 | |
1901 // The restore timer is used to leave a polite interval between | |
1902 // being asked to restore the watcher and actually doing so. It's | |
1903 // a single shot timer each time it's used, but we don't use | |
1904 // QTimer::singleShot because we want to stop the previous one if | |
1905 // it's running (via deleting it) | |
1906 | |
1907 m_fsWatcherRestoreTimer = new QTimer(this); | |
1908 connect(m_fsWatcherRestoreTimer, SIGNAL(timeout()), | |
1909 this, SLOT(actuallyRestoreFileSystemWatcher())); | |
1910 m_fsWatcherRestoreTimer->setInterval(1000); | |
1911 m_fsWatcherRestoreTimer->setSingleShot(true); | |
1912 m_fsWatcherRestoreTimer->start(); | |
1913 } | |
1914 | |
1915 void MainWindow::actuallyRestoreFileSystemWatcher() | |
1916 { | |
1917 DEBUG << "MainWindow::actuallyRestoreFileSystemWatcher" << endl; | |
1918 if (m_fsWatcher) { | |
1919 m_fsWatcherSuspended = false; | |
1920 m_fsWatcherGeneralTimer->start(); | |
1921 } | |
1922 } | |
1923 | |
1924 void MainWindow::checkFilesystem() | 1818 void MainWindow::checkFilesystem() |
1925 { | 1819 { |
1926 DEBUG << "MainWindow::checkFilesystem" << endl; | 1820 DEBUG << "MainWindow::checkFilesystem" << endl; |
1927 hgRefresh(); | 1821 hgRefresh(); |
1928 } | 1822 } |
1929 | 1823 |
1930 void MainWindow::fsDirectoryChanged(QString d) | 1824 void MainWindow::fsWatcherChanged() |
1931 { | 1825 { |
1932 DEBUG << "MainWindow::fsDirectoryChanged " << d << endl; | 1826 DEBUG << "MainWindow::fsWatcherChanged" << endl; |
1933 if (!m_fsWatcherSuspended) { | 1827 |
1934 hgStat(); | |
1935 } | |
1936 } | |
1937 | |
1938 void MainWindow::fsFileChanged(QString f) | |
1939 { | |
1940 DEBUG << "MainWindow::fsFileChanged " << f << endl; | |
1941 if (!m_fsWatcherSuspended) { | |
1942 hgStat(); | |
1943 } | |
1944 } | 1828 } |
1945 | 1829 |
1946 QString MainWindow::format1(QString head) | 1830 QString MainWindow::format1(QString head) |
1947 { | 1831 { |
1948 return QString("<qt><h3>%1</h3></qt>").arg(head); | 1832 return QString("<qt><h3>%1</h3></qt>").arg(head); |
2086 output); | 1970 output); |
2087 } | 1971 } |
2088 | 1972 |
2089 void MainWindow::commandStarting(HgAction action) | 1973 void MainWindow::commandStarting(HgAction action) |
2090 { | 1974 { |
2091 // Annoyingly, hg stat actually modifies the working directory -- | 1975 m_commandSequenceInProgress = true; |
2092 // it creates files called hg-checklink and hg-checkexec to test | |
2093 // properties of the filesystem. For safety's sake, suspend the | |
2094 // fs watcher while running commands, and restore it shortly after | |
2095 // a command has finished. | |
2096 | |
2097 if (action.action == ACT_STAT) { | |
2098 suspendFileSystemWatcher(); | |
2099 } | |
2100 } | 1976 } |
2101 | 1977 |
2102 void MainWindow::commandFailed(HgAction action, QString stderr, QString stdout) | 1978 void MainWindow::commandFailed(HgAction action, QString stderr, QString stdout) |
2103 { | 1979 { |
2104 DEBUG << "MainWindow::commandFailed" << endl; | 1980 DEBUG << "MainWindow::commandFailed" << endl; |
2105 restoreFileSystemWatcher(); | 1981 |
1982 m_commandSequenceInProgress = false; | |
2106 | 1983 |
2107 QString setstr; | 1984 QString setstr; |
2108 #ifdef Q_OS_MAC | 1985 #ifdef Q_OS_MAC |
2109 setstr = tr("Preferences"); | 1986 setstr = tr("Preferences"); |
2110 #else | 1987 #else |
2181 } else if (stderr.contains("entry cancelled")) { | 2058 } else if (stderr.contains("entry cancelled")) { |
2182 // ignore this, user cancelled username or password dialog | 2059 // ignore this, user cancelled username or password dialog |
2183 return; | 2060 return; |
2184 } else if (stderr.contains("no changes found") || stdout.contains("no changes found")) { | 2061 } else if (stderr.contains("no changes found") || stdout.contains("no changes found")) { |
2185 // success: hg 2.1 starts returning failure code for empty pull/push | 2062 // success: hg 2.1 starts returning failure code for empty pull/push |
2063 m_commandSequenceInProgress = true; // there may be further commands | |
2186 commandCompleted(action, stdout); | 2064 commandCompleted(action, stdout); |
2187 return; | 2065 return; |
2188 } | 2066 } |
2189 break; // go on to default report | 2067 break; // go on to default report |
2190 case ACT_PUSH: | 2068 case ACT_PUSH: |
2197 } else if (stderr.contains("entry cancelled")) { | 2075 } else if (stderr.contains("entry cancelled")) { |
2198 // ignore this, user cancelled username or password dialog | 2076 // ignore this, user cancelled username or password dialog |
2199 return; | 2077 return; |
2200 } else if (stderr.contains("no changes found") || stdout.contains("no changes found")) { | 2078 } else if (stderr.contains("no changes found") || stdout.contains("no changes found")) { |
2201 // success: hg 2.1 starts returning failure code for empty pull/push | 2079 // success: hg 2.1 starts returning failure code for empty pull/push |
2080 m_commandSequenceInProgress = true; // there may be further commands | |
2202 commandCompleted(action, stdout); | 2081 commandCompleted(action, stdout); |
2203 return; | 2082 return; |
2204 } | 2083 } |
2205 break; // go on to default report | 2084 break; // go on to default report |
2206 case ACT_QUERY_HEADS_ACTIVE: | 2085 case ACT_QUERY_HEADS_ACTIVE: |
2207 case ACT_QUERY_HEADS: | 2086 case ACT_QUERY_HEADS: |
2208 // fails if repo is empty; we don't care (if there's a genuine | 2087 // fails if repo is empty; we don't care (if there's a genuine |
2209 // problem, something else will fail too). Pretend it | 2088 // problem, something else will fail too). Pretend it |
2210 // succeeded, so that any further actions that are contingent | 2089 // succeeded, so that any further actions that are contingent |
2211 // on the success of the heads query get carried out properly. | 2090 // on the success of the heads query get carried out properly. |
2091 m_commandSequenceInProgress = true; // there may be further commands | |
2212 commandCompleted(action, ""); | 2092 commandCompleted(action, ""); |
2213 return; | 2093 return; |
2214 case ACT_FOLDERDIFF: | 2094 case ACT_FOLDERDIFF: |
2215 case ACT_CHGSETDIFF: | 2095 case ACT_CHGSETDIFF: |
2216 // external program, unlikely to be anything useful in stderr | 2096 // external program, unlikely to be anything useful in stderr |
2259 | 2139 |
2260 void MainWindow::commandCompleted(HgAction completedAction, QString output) | 2140 void MainWindow::commandCompleted(HgAction completedAction, QString output) |
2261 { | 2141 { |
2262 // std::cerr << "commandCompleted: " << completedAction.action << std::endl; | 2142 // std::cerr << "commandCompleted: " << completedAction.action << std::endl; |
2263 | 2143 |
2264 restoreFileSystemWatcher(); | |
2265 HGACTIONS action = completedAction.action; | 2144 HGACTIONS action = completedAction.action; |
2266 | 2145 |
2267 if (action == ACT_NONE) return; | 2146 if (action == ACT_NONE) return; |
2268 | 2147 |
2269 output.replace("\r\n", "\n"); | 2148 output.replace("\r\n", "\n"); |
2318 m_currentBranch = output.trimmed(); | 2197 m_currentBranch = output.trimmed(); |
2319 break; | 2198 break; |
2320 | 2199 |
2321 case ACT_STAT: | 2200 case ACT_STAT: |
2322 m_lastStatOutput = output; | 2201 m_lastStatOutput = output; |
2323 updateFileSystemWatcher(); | |
2324 break; | 2202 break; |
2325 | 2203 |
2326 case ACT_RESOLVE_LIST: | 2204 case ACT_RESOLVE_LIST: |
2327 // This happens on every update, after the stat (above) | 2205 // This happens on every update, after the stat (above) |
2328 if (output != "") { | 2206 if (output != "") { |
2622 } | 2500 } |
2623 break; | 2501 break; |
2624 } | 2502 } |
2625 | 2503 |
2626 if (noMore) { | 2504 if (noMore) { |
2505 m_commandSequenceInProgress = false; | |
2627 m_stateUnknown = false; | 2506 m_stateUnknown = false; |
2628 enableDisableActions(); | 2507 enableDisableActions(); |
2629 m_hgTabs->updateHistory(); | 2508 m_hgTabs->updateHistory(); |
2630 updateRecentMenu(); | 2509 updateRecentMenu(); |
2631 } | 2510 } |