| Chris@57 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@57 | 2 | 
| Chris@57 | 3 /* | 
| Chris@57 | 4     EasyMercurial | 
| Chris@57 | 5 | 
| Chris@57 | 6     Based on HgExplorer by Jari Korhonen | 
| Chris@57 | 7     Copyright (c) 2010 Jari Korhonen | 
| Chris@57 | 8     Copyright (c) 2010 Chris Cannam | 
| Chris@57 | 9     Copyright (c) 2010 Queen Mary, University of London | 
| Chris@57 | 10 | 
| Chris@57 | 11     This program is free software; you can redistribute it and/or | 
| Chris@57 | 12     modify it under the terms of the GNU General Public License as | 
| Chris@57 | 13     published by the Free Software Foundation; either version 2 of the | 
| Chris@57 | 14     License, or (at your option) any later version.  See the file | 
| Chris@57 | 15     COPYING included with this distribution for more information. | 
| Chris@57 | 16 */ | 
| jtkorhonen@0 | 17 | 
| jtkorhonen@0 | 18 #include "hgexpwidget.h" | 
| jtkorhonen@0 | 19 #include "common.h" | 
| Chris@43 | 20 #include "logparser.h" | 
| Chris@43 | 21 #include "changeset.h" | 
| Chris@43 | 22 #include "changesetitem.h" | 
| Chris@44 | 23 #include "grapher.h" | 
| cannam@45 | 24 #include "panner.h" | 
| cannam@45 | 25 #include "panned.h" | 
| Chris@88 | 26 #include "filestatuswidget.h" | 
| Chris@44 | 27 | 
| Chris@50 | 28 #include <QClipboard> | 
| Chris@50 | 29 #include <QContextMenuEvent> | 
| Chris@50 | 30 #include <QApplication> | 
| Chris@50 | 31 | 
| Chris@44 | 32 #include <iostream> | 
| jtkorhonen@0 | 33 | 
| jtkorhonen@0 | 34 #define REMOTE_REPO_STR  "Remote repository: " | 
| jtkorhonen@0 | 35 #define LOCAL_REPO_STR   "Local repository: " | 
| jtkorhonen@0 | 36 #define WORKFOLDER_STR   "Working folder: " | 
| jtkorhonen@0 | 37 | 
| jtkorhonen@0 | 38 | 
| jtkorhonen@0 | 39 const char hgStatViewOptions[NUM_STAT_FILE_TYPES] = {'m','a','r','d','u','c','i'}; | 
| jtkorhonen@0 | 40 | 
| jtkorhonen@0 | 41 const char *statFilesStr[NUM_STAT_FILE_TYPES] =  {  "M: Modified", | 
| jtkorhonen@0 | 42                                                     "A: To be added on next commit", | 
| jtkorhonen@0 | 43                                                     "R: To be removed on next commit", | 
| jtkorhonen@0 | 44                                                     "!: Tracked, locally deleted", | 
| jtkorhonen@0 | 45                                                     "?: Unknown, not yet tracked", | 
| jtkorhonen@0 | 46                                                     "C: Clean (not changed)", | 
| jtkorhonen@0 | 47                                                     "I: Ignored (via .hgignore file)"}; | 
| jtkorhonen@0 | 48 | 
| jtkorhonen@0 | 49 | 
| Chris@88 | 50 HgExpWidget::HgExpWidget(QWidget *parent, QString remoteRepo, | 
| Chris@88 | 51                          QString workFolderPath, | 
| Chris@88 | 52                          unsigned char viewFileTypesBits) : | 
| Chris@88 | 53     QTabWidget(parent) | 
| jtkorhonen@0 | 54 { | 
| jtkorhonen@0 | 55     //Work page | 
| jtkorhonen@0 | 56     //Work page | 
| jtkorhonen@0 | 57     //Work page | 
| jtkorhonen@0 | 58 | 
| jtkorhonen@0 | 59     //Remote repo | 
| jtkorhonen@0 | 60     grpRemoteRepo = new QGroupBox(tr(REMOTE_REPO_STR) + remoteRepo); | 
| jtkorhonen@0 | 61     grpRemoteRepo -> setMinimumHeight(24); | 
| jtkorhonen@0 | 62 | 
| jtkorhonen@0 | 63     //Local Repo | 
| jtkorhonen@0 | 64     grpLocalRepo = new QGroupBox(tr(LOCAL_REPO_STR) + workFolderPath + getHgDirName()); | 
| jtkorhonen@0 | 65     parentsLabel = new QLabel(tr("Working folder parent(s):")); | 
| jtkorhonen@0 | 66     localRepoHgParentsList = new QListWidget; | 
| jtkorhonen@0 | 67     localRepoHgParentsList -> setSelectionMode(QAbstractItemView::NoSelection); | 
| jtkorhonen@0 | 68     parentsLayout = new QVBoxLayout; | 
| jtkorhonen@0 | 69     parentsLayout -> addWidget(parentsLabel); | 
| jtkorhonen@0 | 70     parentsLayout -> addWidget(localRepoHgParentsList); | 
| jtkorhonen@0 | 71     grpLocalRepo -> setLayout(parentsLayout); | 
| jtkorhonen@32 | 72     copyCommentAct = new QAction("Copy comment", localRepoHgParentsList); | 
| jtkorhonen@32 | 73     userListMenu = new QMenu(localRepoHgParentsList); | 
| jtkorhonen@32 | 74     userListMenu -> addAction(copyCommentAct); | 
| jtkorhonen@32 | 75     connect(copyCommentAct, SIGNAL(triggered()), this, SLOT(copyComment())); | 
| jtkorhonen@0 | 76 | 
| jtkorhonen@0 | 77     //Workfolder | 
| jtkorhonen@0 | 78     grpWorkFolder = new QGroupBox(tr(WORKFOLDER_STR) + workFolderPath); | 
| jtkorhonen@0 | 79     workFolderLayout = new QHBoxLayout; | 
| jtkorhonen@0 | 80     workFolderFileList = new QListWidget; | 
| jtkorhonen@19 | 81     workFolderFileList -> setSelectionMode(QAbstractItemView::ExtendedSelection); | 
| jtkorhonen@0 | 82     grpViewFileTypes = new QGroupBox; | 
| jtkorhonen@0 | 83     fileTypesLayout = new QVBoxLayout; | 
| jtkorhonen@0 | 84 | 
| jtkorhonen@0 | 85     for(int i = 0; i < NUM_STAT_FILE_TYPES; i++) | 
| jtkorhonen@0 | 86     { | 
| jtkorhonen@0 | 87         chkViewFileTypes[i] = new QCheckBox(statFilesStr[i]); | 
| jtkorhonen@0 | 88         if ((1U << i) & viewFileTypesBits) | 
| jtkorhonen@0 | 89         { | 
| jtkorhonen@0 | 90             chkViewFileTypes[i]->setChecked(true); | 
| jtkorhonen@0 | 91         } | 
| jtkorhonen@0 | 92         else | 
| jtkorhonen@0 | 93         { | 
| jtkorhonen@0 | 94             chkViewFileTypes[i]->setChecked(false); | 
| jtkorhonen@0 | 95         } | 
| jtkorhonen@0 | 96         connect(chkViewFileTypes[i], SIGNAL(stateChanged(int)), this, SIGNAL(workFolderViewTypesChanged())); | 
| jtkorhonen@0 | 97         fileTypesLayout -> addWidget(chkViewFileTypes[i]); | 
| jtkorhonen@0 | 98     } | 
| jtkorhonen@0 | 99 | 
| jtkorhonen@0 | 100     grpViewFileTypes -> setLayout(fileTypesLayout); | 
| jtkorhonen@0 | 101     workFolderLayout->addWidget(workFolderFileList, 3); | 
| jtkorhonen@0 | 102     workFolderLayout->addWidget(grpViewFileTypes, 1); | 
| jtkorhonen@0 | 103     grpWorkFolder -> setLayout(workFolderLayout); | 
| jtkorhonen@0 | 104 | 
| jtkorhonen@0 | 105     workPageWidget = new QWidget; | 
| jtkorhonen@0 | 106     mainLayout = new QVBoxLayout(workPageWidget); | 
| jtkorhonen@0 | 107     mainLayout -> addWidget(grpRemoteRepo, 1); | 
| jtkorhonen@0 | 108     mainLayout -> addWidget(grpLocalRepo, 8); | 
| jtkorhonen@0 | 109     mainLayout -> addWidget(grpWorkFolder, 12); | 
| Chris@89 | 110 //!!!    addTab(workPageWidget, tr("My work")); | 
| jtkorhonen@0 | 111 | 
| Chris@88 | 112     // New work page | 
| Chris@88 | 113     fileStatusWidget = new FileStatusWidget; | 
| Chris@89 | 114     fileStatusWidget->setLocalPath(workFolderPath); | 
| Chris@89 | 115     fileStatusWidget->setRemoteURL(remoteRepo); | 
| Chris@89 | 116     addTab(fileStatusWidget, tr("My work")); | 
| Chris@88 | 117 | 
| Chris@43 | 118     // History graph page | 
| cannam@45 | 119     historyGraphPageWidget = new QWidget; | 
| cannam@45 | 120     Panned *panned = new Panned; | 
| cannam@45 | 121     Panner *panner = new Panner; | 
| cannam@45 | 122     historyGraphWidget = panned; | 
| cannam@45 | 123     historyGraphPanner = panner; | 
| cannam@45 | 124     QGridLayout *layout = new QGridLayout; | 
| cannam@45 | 125     layout->addWidget(historyGraphWidget, 0, 0); | 
| cannam@45 | 126     layout->addWidget(historyGraphPanner, 0, 1); | 
| cannam@45 | 127     panner->setMaximumWidth(80); | 
| cannam@45 | 128     panner->connectToPanned(panned); | 
| cannam@45 | 129     historyGraphPageWidget->setLayout(layout); | 
| Chris@58 | 130     addTab(historyGraphPageWidget, tr("History")); | 
| Chris@43 | 131 | 
| Chris@43 | 132 | 
| jtkorhonen@0 | 133     //History page | 
| jtkorhonen@0 | 134     //History page | 
| jtkorhonen@0 | 135     //History page | 
| jtkorhonen@0 | 136     historyPageWidget = new QWidget; | 
| jtkorhonen@0 | 137     localRepoHgLogList = new QListWidget; | 
| jtkorhonen@0 | 138     localRepoHgLogList->setFont(QFont("Courier New")); | 
| jtkorhonen@0 | 139     localRepoHgLogList -> setSelectionMode(QAbstractItemView::ExtendedSelection); | 
| jtkorhonen@0 | 140 | 
| jtkorhonen@0 | 141     historyLayout = new QVBoxLayout(historyPageWidget); | 
| jtkorhonen@0 | 142     historyLayout->addWidget(localRepoHgLogList); | 
| Chris@58 | 143 //!!!    addTab(historyPageWidget, tr("History (log)")); | 
| jtkorhonen@0 | 144 | 
| jtkorhonen@0 | 145     //Heads page | 
| jtkorhonen@0 | 146     //Heads page | 
| jtkorhonen@0 | 147     //Heads page | 
| jtkorhonen@0 | 148     headsPageWidget = new QWidget; | 
| jtkorhonen@0 | 149     localRepoHeadsList = new QListWidget; | 
| jtkorhonen@0 | 150     localRepoHeadsList -> setSelectionMode(QAbstractItemView::ExtendedSelection); | 
| jtkorhonen@0 | 151 | 
| jtkorhonen@0 | 152     headsLayout = new QVBoxLayout(headsPageWidget); | 
| jtkorhonen@0 | 153     headsLayout->addWidget(localRepoHeadsList); | 
| Chris@58 | 154 //!!!    addTab(headsPageWidget, tr("Heads")); | 
| jtkorhonen@0 | 155 | 
| jtkorhonen@0 | 156     //Initially, only work page is active | 
| Chris@58 | 157 //!!!    setTabEnabled(HEADSTAB, false); | 
| Chris@58 | 158 //!!!    setTabEnabled(HISTORYTAB, false); | 
| jtkorhonen@0 | 159 } | 
| jtkorhonen@0 | 160 | 
| jtkorhonen@32 | 161 void HgExpWidget::contextMenuEvent(QContextMenuEvent * event) | 
| jtkorhonen@32 | 162 { | 
| jtkorhonen@32 | 163     if (copyCommentAct -> isEnabled()) | 
| jtkorhonen@32 | 164     { | 
| jtkorhonen@32 | 165         QPoint topL; | 
| jtkorhonen@32 | 166         QPoint bottomR; | 
| jtkorhonen@32 | 167 | 
| jtkorhonen@32 | 168         topL = localRepoHgParentsList-> | 
| jtkorhonen@32 | 169             mapToGlobal(QPoint(0, 0)); | 
| jtkorhonen@32 | 170         bottomR = localRepoHgParentsList-> | 
| jtkorhonen@32 | 171             mapToGlobal(QPoint(localRepoHgParentsList -> width(), localRepoHgParentsList -> height())); | 
| jtkorhonen@32 | 172 | 
| jtkorhonen@32 | 173         if ((event -> globalPos().x() > topL.x()) && (event -> globalPos().x() < bottomR.x())) | 
| jtkorhonen@32 | 174         { | 
| jtkorhonen@32 | 175             if ((event -> globalPos().y() > topL.y()) && (event -> globalPos().y() < bottomR.y())) | 
| jtkorhonen@32 | 176             { | 
| jtkorhonen@32 | 177                 userListMenu->exec(event -> globalPos()); | 
| jtkorhonen@32 | 178             } | 
| jtkorhonen@32 | 179         } | 
| jtkorhonen@32 | 180     } | 
| jtkorhonen@32 | 181 } | 
| jtkorhonen@32 | 182 | 
| jtkorhonen@32 | 183 void HgExpWidget::copyComment() | 
| jtkorhonen@32 | 184 { | 
| jtkorhonen@32 | 185     if (localRepoHgParentsList -> count() >= 1) | 
| jtkorhonen@32 | 186     { | 
| jtkorhonen@32 | 187         QListWidgetItem *it =  localRepoHgParentsList -> item(0); | 
| jtkorhonen@32 | 188         QString tmp = it -> text(); | 
| jtkorhonen@32 | 189         int ind = tmp.indexOf("summary:"); | 
| jtkorhonen@32 | 190         if (ind != -1) | 
| jtkorhonen@32 | 191         { | 
| jtkorhonen@32 | 192             QString comment; | 
| jtkorhonen@32 | 193             ind += 11;   //jump over word "summary:" | 
| jtkorhonen@32 | 194 | 
| jtkorhonen@32 | 195             comment = tmp.mid(ind); | 
| jtkorhonen@32 | 196 | 
| jtkorhonen@32 | 197             QClipboard *clipboard = QApplication::clipboard(); | 
| jtkorhonen@32 | 198             clipboard->setText(comment); | 
| jtkorhonen@32 | 199         } | 
| jtkorhonen@32 | 200     } | 
| jtkorhonen@32 | 201 } | 
| jtkorhonen@32 | 202 | 
| jtkorhonen@32 | 203 | 
| jtkorhonen@0 | 204 | 
| jtkorhonen@0 | 205 QString HgExpWidget::getStatFlags() | 
| jtkorhonen@0 | 206 { | 
| jtkorhonen@0 | 207     QString ret; | 
| jtkorhonen@0 | 208 | 
| jtkorhonen@0 | 209     for(int i = 0; i < NUM_STAT_FILE_TYPES; i++) | 
| jtkorhonen@0 | 210     { | 
| jtkorhonen@0 | 211         if (Qt::Checked == chkViewFileTypes[i]->checkState()) | 
| jtkorhonen@0 | 212         { | 
| jtkorhonen@0 | 213             ret += hgStatViewOptions[i]; | 
| jtkorhonen@0 | 214         } | 
| jtkorhonen@0 | 215     } | 
| jtkorhonen@0 | 216 | 
| jtkorhonen@0 | 217     return ret; | 
| jtkorhonen@0 | 218 } | 
| jtkorhonen@0 | 219 | 
| jtkorhonen@0 | 220 | 
| jtkorhonen@0 | 221 unsigned char HgExpWidget::getFileTypesBits() | 
| jtkorhonen@0 | 222 { | 
| jtkorhonen@0 | 223     unsigned char ret; | 
| jtkorhonen@0 | 224 | 
| jtkorhonen@0 | 225     ret = 0; | 
| jtkorhonen@0 | 226 | 
| jtkorhonen@0 | 227     for(int i = 0; i < NUM_STAT_FILE_TYPES; i++) | 
| jtkorhonen@0 | 228     { | 
| jtkorhonen@0 | 229         if (Qt::Checked == chkViewFileTypes[i]->checkState()) | 
| jtkorhonen@0 | 230         { | 
| jtkorhonen@0 | 231             ret |= (1U << i); | 
| jtkorhonen@0 | 232         } | 
| jtkorhonen@0 | 233     } | 
| jtkorhonen@0 | 234 | 
| jtkorhonen@0 | 235     return ret; | 
| jtkorhonen@0 | 236 } | 
| jtkorhonen@0 | 237 | 
| jtkorhonen@0 | 238 | 
| jtkorhonen@0 | 239 void HgExpWidget::updateWorkFolderFileList(QString fileList) | 
| jtkorhonen@0 | 240 { | 
| Chris@86 | 241     statParser = StatParser(fileList); | 
| Chris@86 | 242 | 
| Chris@89 | 243     fileStatusWidget->setStatParser(statParser); | 
| Chris@89 | 244 | 
| jtkorhonen@0 | 245     workFolderFileList-> clear(); | 
| jtkorhonen@0 | 246     workFolderFileList -> addItems(fileList.split("\n")); | 
| jtkorhonen@0 | 247 } | 
| jtkorhonen@0 | 248 | 
| jtkorhonen@0 | 249 void HgExpWidget::updateLocalRepoHeadsList(QString headList) | 
| jtkorhonen@0 | 250 { | 
| jtkorhonen@0 | 251     localRepoHeadsList-> clear(); | 
| jtkorhonen@0 | 252     localRepoHeadsList -> addItems(splitChangeSets(headList)); | 
| jtkorhonen@0 | 253 | 
| jtkorhonen@0 | 254     //heads list is interesting only when we have 2 or more | 
| jtkorhonen@0 | 255     if (localRepoHeadsList-> count() < 2) | 
| jtkorhonen@0 | 256     { | 
| jtkorhonen@0 | 257         setTabEnabled(HEADSTAB, false); | 
| jtkorhonen@0 | 258     } | 
| jtkorhonen@0 | 259     else | 
| jtkorhonen@0 | 260     { | 
| jtkorhonen@0 | 261         setTabEnabled(HEADSTAB, true); | 
| jtkorhonen@0 | 262     } | 
| jtkorhonen@0 | 263 } | 
| jtkorhonen@0 | 264 | 
| jtkorhonen@0 | 265 | 
| jtkorhonen@0 | 266 void HgExpWidget::clearLists() | 
| jtkorhonen@0 | 267 { | 
| jtkorhonen@0 | 268     localRepoHeadsList-> clear(); | 
| jtkorhonen@0 | 269     localRepoHgParentsList-> clear(); | 
| jtkorhonen@0 | 270     workFolderFileList-> clear(); | 
| jtkorhonen@0 | 271     localRepoHgLogList -> clear(); | 
| jtkorhonen@0 | 272 } | 
| jtkorhonen@0 | 273 | 
| jtkorhonen@0 | 274 void HgExpWidget::updateLocalRepoParentsList(QString parentsList) | 
| jtkorhonen@0 | 275 { | 
| jtkorhonen@0 | 276     localRepoHgParentsList-> clear(); | 
| jtkorhonen@0 | 277     localRepoHgParentsList -> addItems(splitChangeSets(parentsList)); | 
| jtkorhonen@0 | 278 } | 
| jtkorhonen@0 | 279 | 
| jtkorhonen@0 | 280 void HgExpWidget::updateLocalRepoHgLogList(QString hgLogList) | 
| jtkorhonen@0 | 281 { | 
| jtkorhonen@0 | 282     localRepoHgLogList -> clear(); | 
| jtkorhonen@0 | 283     localRepoHgLogList -> addItems(splitChangeSets(hgLogList)); | 
| jtkorhonen@0 | 284 | 
| Chris@43 | 285     //!!! | 
| cannam@45 | 286     Panned *panned = static_cast<Panned *>(historyGraphWidget); | 
| cannam@45 | 287     Panner *panner = static_cast<Panner *>(historyGraphPanner); | 
| Chris@43 | 288     QGraphicsScene *scene = new QGraphicsScene(); | 
| Chris@43 | 289     Changesets csets = parseChangeSets(hgLogList); | 
| Chris@44 | 290     if (csets.empty()) return; | 
| Chris@53 | 291     Grapher g(scene); | 
| Chris@44 | 292     try { | 
| Chris@53 | 293 	g.layout(csets); | 
| Chris@44 | 294     } catch (std::string s) { | 
| Chris@44 | 295 	std::cerr << "Internal error: Layout failed: " << s << std::endl; | 
| Chris@44 | 296     } | 
| Chris@87 | 297     QGraphicsScene *oldScene = panned->scene(); | 
| cannam@45 | 298     panned->setScene(scene); | 
| cannam@45 | 299     panner->setScene(scene); | 
| Chris@87 | 300     if (oldScene) delete oldScene; | 
| Chris@53 | 301     ChangesetItem *tipItem = g.getItemFor(csets[0]); | 
| Chris@53 | 302     if (tipItem) tipItem->ensureVisible(); | 
| jtkorhonen@0 | 303 } | 
| jtkorhonen@0 | 304 | 
| jtkorhonen@0 | 305 | 
| Chris@43 | 306 | 
| jtkorhonen@0 | 307 int HgExpWidget::findLineStart(int nowIndex, QString str) | 
| jtkorhonen@0 | 308 { | 
| jtkorhonen@0 | 309     if (nowIndex < 0) | 
| jtkorhonen@0 | 310     { | 
| jtkorhonen@0 | 311         return -1; | 
| jtkorhonen@0 | 312     } | 
| jtkorhonen@0 | 313 | 
| jtkorhonen@0 | 314     while(str.at(nowIndex) != '\n') | 
| jtkorhonen@0 | 315     { | 
| jtkorhonen@0 | 316         if (nowIndex == 0) | 
| jtkorhonen@0 | 317         { | 
| jtkorhonen@0 | 318             return nowIndex; | 
| jtkorhonen@0 | 319         } | 
| jtkorhonen@0 | 320         nowIndex--; | 
| jtkorhonen@0 | 321     } | 
| jtkorhonen@0 | 322     return nowIndex + 1; | 
| jtkorhonen@0 | 323 } | 
| jtkorhonen@0 | 324 | 
| jtkorhonen@0 | 325 | 
| jtkorhonen@0 | 326 QStringList HgExpWidget::splitChangeSets(QString chgSetsStr) | 
| jtkorhonen@0 | 327 { | 
| Chris@43 | 328     return LogParser(chgSetsStr).split(); | 
| Chris@43 | 329     /* | 
| jtkorhonen@0 | 330     int currChgSet; | 
| jtkorhonen@0 | 331     int currChgSetLineStart; | 
| jtkorhonen@0 | 332 | 
| jtkorhonen@0 | 333     int prevChgSet; | 
| jtkorhonen@0 | 334     QStringList tmp; | 
| jtkorhonen@0 | 335 | 
| jtkorhonen@0 | 336     currChgSet = chgSetsStr.indexOf(CHGSET); | 
| jtkorhonen@0 | 337     currChgSetLineStart = findLineStart(currChgSet, chgSetsStr); | 
| jtkorhonen@0 | 338     prevChgSet = -1; | 
| jtkorhonen@0 | 339     while (currChgSet != -1) | 
| jtkorhonen@0 | 340     { | 
| jtkorhonen@0 | 341         if (prevChgSet != -1) | 
| jtkorhonen@0 | 342         { | 
| jtkorhonen@0 | 343             tmp.append(chgSetsStr.mid(prevChgSet, (currChgSetLineStart - prevChgSet - 1))); | 
| jtkorhonen@0 | 344         } | 
| jtkorhonen@0 | 345 | 
| jtkorhonen@0 | 346         prevChgSet = currChgSetLineStart; | 
| jtkorhonen@0 | 347 | 
| jtkorhonen@0 | 348         currChgSet = chgSetsStr.indexOf(CHGSET, currChgSet + 1); | 
| jtkorhonen@0 | 349         currChgSetLineStart = findLineStart(currChgSet, chgSetsStr); | 
| jtkorhonen@0 | 350     } | 
| jtkorhonen@0 | 351 | 
| jtkorhonen@0 | 352     if (prevChgSet != -1) | 
| jtkorhonen@0 | 353     { | 
| jtkorhonen@0 | 354         //Last changeset | 
| jtkorhonen@0 | 355         tmp.append(chgSetsStr.mid(prevChgSet)); | 
| jtkorhonen@0 | 356     } | 
| jtkorhonen@0 | 357     else | 
| jtkorhonen@0 | 358     { | 
| jtkorhonen@0 | 359         //Only changeset (if any) | 
| jtkorhonen@0 | 360         if (!chgSetsStr.isEmpty()) | 
| jtkorhonen@0 | 361         { | 
| jtkorhonen@0 | 362             tmp.append(chgSetsStr.mid(0)); | 
| jtkorhonen@0 | 363         } | 
| jtkorhonen@0 | 364     } | 
| jtkorhonen@0 | 365 | 
| jtkorhonen@0 | 366     return tmp; | 
| Chris@43 | 367     */ | 
| Chris@43 | 368 } | 
| Chris@43 | 369 | 
| Chris@43 | 370 Changesets HgExpWidget::parseChangeSets(QString changeSetsStr) | 
| Chris@43 | 371 { | 
| Chris@43 | 372     Changesets csets; | 
| Chris@43 | 373     LogList log = LogParser(changeSetsStr).parse(); | 
| Chris@43 | 374     foreach (LogEntry e, log) { | 
| Chris@43 | 375         Changeset *cs = new Changeset(); | 
| Chris@43 | 376         foreach (QString key, e.keys()) { | 
| Chris@44 | 377 	    if (key == "parents") { | 
| Chris@44 | 378 		QStringList parents = e.value(key).split | 
| Chris@44 | 379 		    (" ", QString::SkipEmptyParts); | 
| Chris@44 | 380 		cs->setParents(parents); | 
| Chris@52 | 381 	    } else if (key == "timestamp") { | 
| Chris@52 | 382 		cs->setTimestamp(e.value(key).split(" ")[0].toULongLong()); | 
| Chris@44 | 383 	    } else { | 
| Chris@44 | 384 		cs->setProperty(key.toLocal8Bit().data(), e.value(key)); | 
| Chris@44 | 385 	    } | 
| Chris@43 | 386         } | 
| Chris@43 | 387         csets.push_back(cs); | 
| Chris@43 | 388     } | 
| Chris@44 | 389     for (int i = 0; i+1 < csets.size(); ++i) { | 
| Chris@44 | 390 	Changeset *cs = csets[i]; | 
| Chris@44 | 391 	if (cs->parents().empty()) { | 
| Chris@44 | 392 	    QStringList list; | 
| Chris@44 | 393 	    list.push_back(csets[i+1]->id()); | 
| Chris@44 | 394 	    cs->setParents(list); | 
| Chris@44 | 395 	} | 
| Chris@44 | 396     } | 
| Chris@43 | 397     return csets; | 
| jtkorhonen@0 | 398 } | 
| jtkorhonen@0 | 399 | 
| jtkorhonen@0 | 400 QString HgExpWidget::getCurrentFileListLine() | 
| jtkorhonen@0 | 401 { | 
| jtkorhonen@0 | 402     if (workFolderFileList -> currentItem() != NULL) | 
| jtkorhonen@0 | 403     { | 
| jtkorhonen@0 | 404         return workFolderFileList -> currentItem()->text(); | 
| jtkorhonen@0 | 405     } | 
| jtkorhonen@0 | 406     return ""; | 
| jtkorhonen@0 | 407 } | 
| jtkorhonen@0 | 408 | 
| jtkorhonen@0 | 409 void HgExpWidget::setWorkFolderAndRepoNames(QString workFolderPath, QString remoteRepoPath) | 
| jtkorhonen@0 | 410 { | 
| jtkorhonen@0 | 411     grpRemoteRepo -> setTitle(tr(REMOTE_REPO_STR) + remoteRepoPath); | 
| jtkorhonen@0 | 412     grpLocalRepo -> setTitle(tr(LOCAL_REPO_STR) + workFolderPath + getHgDirName()); | 
| jtkorhonen@0 | 413     grpWorkFolder -> setTitle(tr(WORKFOLDER_STR) + workFolderPath); | 
| Chris@89 | 414 | 
| Chris@89 | 415     fileStatusWidget->setLocalPath(workFolderPath); | 
| Chris@89 | 416     fileStatusWidget->setRemoteURL(remoteRepoPath); | 
| jtkorhonen@0 | 417 } | 
| jtkorhonen@0 | 418 | 
| jtkorhonen@0 | 419 #define MERC_SHA1_MARKER_LEN 12 | 
| jtkorhonen@0 | 420 QString HgExpWidget::findRev(QString itemText, QString & smallRev) | 
| jtkorhonen@0 | 421 { | 
| jtkorhonen@0 | 422     QString tmp(itemText); | 
| jtkorhonen@0 | 423     int i; | 
| jtkorhonen@0 | 424     int j; | 
| jtkorhonen@0 | 425 | 
| jtkorhonen@0 | 426     smallRev ="0"; | 
| jtkorhonen@0 | 427 | 
| jtkorhonen@0 | 428     i = tmp.indexOf(CHGSET); | 
| jtkorhonen@0 | 429     if (i != -1) | 
| jtkorhonen@0 | 430     { | 
| jtkorhonen@0 | 431         j = i + 10; | 
| jtkorhonen@0 | 432         i = tmp.indexOf(":", j);  //xx:yyyyyy after changeset: | 
| jtkorhonen@0 | 433 | 
| jtkorhonen@0 | 434         if (i != -1) | 
| jtkorhonen@0 | 435         { | 
| jtkorhonen@0 | 436             smallRev = tmp.mid(j, (i-j)); | 
| jtkorhonen@0 | 437             return tmp.mid(i+1, MERC_SHA1_MARKER_LEN); | 
| jtkorhonen@0 | 438         } | 
| jtkorhonen@0 | 439     } | 
| jtkorhonen@0 | 440 | 
| jtkorhonen@0 | 441     return ""; | 
| jtkorhonen@0 | 442 } | 
| jtkorhonen@0 | 443 | 
| jtkorhonen@0 | 444 void HgExpWidget::getHistoryDiffRevisions(QString& revA, QString& revB) | 
| jtkorhonen@0 | 445 { | 
| jtkorhonen@0 | 446     QList <QListWidgetItem *> histList = localRepoHgLogList->selectedItems(); | 
| jtkorhonen@0 | 447     QList <QListWidgetItem *> headList = localRepoHeadsList->selectedItems(); | 
| jtkorhonen@0 | 448 | 
| jtkorhonen@0 | 449     QString revATmp; | 
| jtkorhonen@0 | 450     QString revBTmp; | 
| jtkorhonen@0 | 451     QString smallRevA; | 
| jtkorhonen@0 | 452     QString smallRevB; | 
| jtkorhonen@0 | 453     QString txtA; | 
| jtkorhonen@0 | 454     QString txtB; | 
| jtkorhonen@0 | 455 | 
| jtkorhonen@0 | 456     if (histList.count() == REQUIRED_CHGSET_DIFF_COUNT) | 
| jtkorhonen@0 | 457     { | 
| jtkorhonen@0 | 458         txtA = histList.last()->text(); | 
| jtkorhonen@0 | 459         txtB = histList.first()->text(); | 
| jtkorhonen@0 | 460 | 
| jtkorhonen@0 | 461     } | 
| jtkorhonen@0 | 462     else if (headList.count() == REQUIRED_CHGSET_DIFF_COUNT) | 
| jtkorhonen@0 | 463     { | 
| jtkorhonen@0 | 464         txtA = headList.last()->text(); | 
| jtkorhonen@0 | 465         txtB = headList.first()->text(); | 
| jtkorhonen@0 | 466     } | 
| jtkorhonen@0 | 467     else | 
| jtkorhonen@0 | 468     { | 
| jtkorhonen@0 | 469         revA = ""; | 
| jtkorhonen@0 | 470         revB = ""; | 
| jtkorhonen@0 | 471         return; | 
| jtkorhonen@0 | 472     } | 
| jtkorhonen@0 | 473 | 
| jtkorhonen@0 | 474     revATmp = findRev(txtA, smallRevA); | 
| jtkorhonen@0 | 475     revBTmp = findRev(txtB, smallRevB); | 
| jtkorhonen@0 | 476 | 
| jtkorhonen@0 | 477     //Switch order according to repo small revision number (user can select items from list in "wrong" order) | 
| jtkorhonen@0 | 478     if (smallRevB.toULongLong() > smallRevA.toULongLong()) | 
| jtkorhonen@0 | 479     { | 
| jtkorhonen@0 | 480         revA = revATmp; | 
| jtkorhonen@0 | 481         revB = revBTmp; | 
| jtkorhonen@0 | 482     } | 
| jtkorhonen@0 | 483     else | 
| jtkorhonen@0 | 484     { | 
| jtkorhonen@0 | 485         revA = revBTmp; | 
| jtkorhonen@0 | 486         revB = revATmp; | 
| jtkorhonen@0 | 487     } | 
| jtkorhonen@0 | 488 } | 
| jtkorhonen@0 | 489 | 
| jtkorhonen@0 | 490 | 
| jtkorhonen@0 | 491 void HgExpWidget::getUpdateToRevRevision(QString& rev) | 
| jtkorhonen@0 | 492 { | 
| jtkorhonen@0 | 493     QList <QListWidgetItem *> histList = localRepoHgLogList->selectedItems(); | 
| jtkorhonen@0 | 494     QString txt; | 
| jtkorhonen@0 | 495     QString smallRev; | 
| jtkorhonen@0 | 496 | 
| jtkorhonen@0 | 497 | 
| jtkorhonen@0 | 498     if (histList.count() == 1) | 
| jtkorhonen@0 | 499     { | 
| jtkorhonen@0 | 500         txt = histList.first()->text(); | 
| jtkorhonen@0 | 501         rev = findRev(txt, smallRev); | 
| jtkorhonen@0 | 502     } | 
| jtkorhonen@0 | 503     else | 
| jtkorhonen@0 | 504     { | 
| jtkorhonen@0 | 505         rev = ""; | 
| jtkorhonen@0 | 506     } | 
| jtkorhonen@0 | 507 } | 
| jtkorhonen@0 | 508 | 
| jtkorhonen@0 | 509 | 
| jtkorhonen@32 | 510 void HgExpWidget::enableDisableOtherTabs(int tabPage) | 
| jtkorhonen@32 | 511 { | 
| jtkorhonen@32 | 512     static int oldTabPage = -1; | 
| jtkorhonen@0 | 513 | 
| jtkorhonen@32 | 514     if  (tabPage != oldTabPage) | 
| jtkorhonen@32 | 515     { | 
| jtkorhonen@32 | 516         oldTabPage = tabPage; | 
| jtkorhonen@32 | 517         if (tabPage == WORKTAB) | 
| jtkorhonen@32 | 518         { | 
| jtkorhonen@32 | 519             copyCommentAct -> setEnabled(true); | 
| jtkorhonen@32 | 520         } | 
| jtkorhonen@32 | 521         else | 
| jtkorhonen@32 | 522         { | 
| jtkorhonen@32 | 523             copyCommentAct -> setEnabled(false); | 
| jtkorhonen@32 | 524         } | 
| jtkorhonen@32 | 525     } | 
| jtkorhonen@32 | 526 | 
| jtkorhonen@0 | 527     //history list is only interesting when we have something in it ;-) | 
| jtkorhonen@0 | 528     if (localRepoHgLogList -> count() < 2) | 
| jtkorhonen@0 | 529     { | 
| jtkorhonen@0 | 530         setTabEnabled(HISTORYTAB, false); | 
| jtkorhonen@0 | 531     } | 
| jtkorhonen@0 | 532     else | 
| jtkorhonen@0 | 533     { | 
| jtkorhonen@0 | 534         setTabEnabled(HISTORYTAB, true); | 
| jtkorhonen@0 | 535     } | 
| jtkorhonen@0 | 536 | 
| jtkorhonen@0 | 537     //history list is only interesting when we have something in it ;-) | 
| jtkorhonen@0 | 538     if (localRepoHgLogList -> count() < 2) | 
| jtkorhonen@0 | 539     { | 
| jtkorhonen@0 | 540         setTabEnabled(HISTORYTAB, false); | 
| jtkorhonen@0 | 541     } | 
| jtkorhonen@0 | 542     else | 
| jtkorhonen@0 | 543     { | 
| jtkorhonen@0 | 544         setTabEnabled(HISTORYTAB, true); | 
| jtkorhonen@0 | 545     } | 
| jtkorhonen@0 | 546 } | 
| jtkorhonen@0 | 547 | 
| jtkorhonen@0 | 548 | 
| jtkorhonen@0 | 549 | 
| jtkorhonen@0 | 550 |