fileview.cpp

Go to the documentation of this file.
00001 /*
00002         Description: file viewer window
00003 
00004         Author: Marco Costalba (C) 2005-2006
00005 
00006         Copyright: See COPYING file that comes with this distribution
00007 
00008 */
00009 #include <qtextedit.h>
00010 #include <qlistview.h>
00011 #include <qspinbox.h>
00012 #include <qlineedit.h>
00013 #include <qmessagebox.h>
00014 #include <qsettings.h>
00015 #include <qstatusbar.h>
00016 #include <qlabel.h>
00017 #include <qsplitter.h>
00018 #include <qapplication.h>
00019 #include <qcursor.h>
00020 #include <qregexp.h>
00021 #include <qclipboard.h>
00022 #include <qtoolbutton.h>
00023 #include <qtabwidget.h>
00024 #include "mainimpl.h"
00025 #include "git.h"
00026 #include "annotate.h"
00027 #include "listview.h"
00028 #include "filecontent.h"
00029 #include "filebase.h"
00030 #include "fileview.h"
00031 
00032 #define MAX_LINE_NUM 5
00033 
00034 FileView::FileView(MainImpl* mi, Git* g) : Domain(mi, g) {
00035 
00036         fileTab = new TabFile(m());
00037         m()->tabWdg->addTab(fileTab, "File");
00038         tabPosition = m()->tabWdg->count() - 1;
00039 
00040         fh = new FileHistory();
00041         histListView = new ListView(this, git, fileTab->histListView, fh, m()->listViewFont);
00042         textEditFile = new FileContent(this, git, fileTab->textEditFile);
00043 
00044         // cannot be set directly in the .ui file
00045         fileTab->spinBoxRevision->setSpecialValueText(" ");
00046 
00047         clear(true); // init some stuff
00048 
00049         connect(git, SIGNAL(loadCompleted(const FileHistory*, const QString&)),
00050                 this, SLOT(on_loadCompleted(const FileHistory*, const QString&)));
00051 
00052         connect(git, SIGNAL(newRevsAdded(const FileHistory*, const QValueVector<QString>&)),
00053         histListView, SLOT(on_newRevsAdded(const FileHistory*, const QValueVector<QString>&)));
00054 
00055         connect(m(), SIGNAL(repaintListViews(const QFont&)),
00056                 histListView, SLOT(on_repaintListViews(const QFont&)));
00057 
00058         connect(histListView, SIGNAL(contextMenu(const QString&, int)),
00059                 this, SLOT(on_contextMenu(const QString&, int)));
00060 
00061         connect(textEditFile, SIGNAL(annotationAvailable(bool)),
00062                 this, SLOT(on_annotationAvailable(bool)));
00063 
00064         connect(textEditFile, SIGNAL(fileAvailable(bool)),
00065                 this, SLOT(on_fileAvailable(bool)));
00066 
00067         connect(textEditFile, SIGNAL(revIdSelected(int)),
00068                 this, SLOT(on_revIdSelected(int)));
00069 
00070         connect(fileTab->toolButtonCopy, SIGNAL(clicked()),
00071                 this, SLOT(on_toolButtonCopy_clicked()));
00072 
00073         connect(fileTab->toolButtonShowAnnotate, SIGNAL(toggled(bool)),
00074                 this, SLOT(on_toolButtonShowAnnotate_toggled(bool)));
00075 
00076         connect(fileTab->toolButtonFindAnnotate, SIGNAL(toggled(bool)),
00077                 this, SLOT(on_toolButtonFindAnnotate_toggled(bool)));
00078 
00079         connect(fileTab->toolButtonRangeFilter, SIGNAL(toggled(bool)),
00080                 this, SLOT(on_toolButtonRangeFilter_toggled(bool)));
00081 
00082         connect(fileTab->toolButtonPin, SIGNAL(toggled(bool)),
00083                 this, SLOT(on_toolButtonPin_toggled(bool)));
00084 
00085         connect(fileTab->toolButtonHighlightText, SIGNAL(toggled(bool)),
00086                 this, SLOT(on_toolButtonHighlightText_toggled(bool)));
00087 
00088         connect(fileTab->spinBoxRevision, SIGNAL(valueChanged(int)),
00089                 this, SLOT(on_spinBoxRevision_valueChanged(int)));
00090 }
00091 
00092 FileView::~FileView() {
00093 
00094         if (!parent())
00095                 return;
00096 
00097         delete textEditFile; // delete now, without waiting base QObject d'tor
00098         delete histListView; // to do the job for us, we need them out before
00099         delete fh;           // Domain d'tor is called.
00100 
00101         // remove before to delete, avoids a Qt warning in QInputContext()
00102         m()->tabWdg->removePage(fileTab);
00103         delete fileTab;
00104 
00105         m()->statusBar()->clear(); // cleanup any pending progress info
00106         QApplication::restoreOverrideCursor();
00107 }
00108 
00109 void FileView::clear(bool complete) {
00110 
00111         if (complete) {
00112                 st.clear();
00113                 m()->tabWdg->changeTab(fileTab, "File");
00114                 fileTab->toolButtonCopy->setEnabled(false);
00115         }
00116         histListView->clear();
00117         textEditFile->clear();
00118 
00119         annotateAvailable = fileAvailable = false;
00120         updateEnabledButtons();
00121 
00122         fileTab->toolButtonPin->setEnabled(false);
00123         fileTab->toolButtonPin->setOn(false); // should not trigger an update
00124         fileTab->spinBoxRevision->setEnabled(false);
00125         fileTab->spinBoxRevision->setValue(fileTab->spinBoxRevision->minValue()); // clears the box
00126 }
00127 
00128 bool FileView::goToCurrentAnnotation() {
00129 
00130         QListViewItem* item = fileTab->histListView->currentItem();
00131         int id = (item) ? item->text(QGit::ANN_ID_COL).toInt() : 0;
00132         textEditFile->goToAnnotation(id);
00133         return (id != 0);
00134 }
00135 
00136 void FileView::updateSpinBoxValue() {
00137 
00138         QListViewItem* item = fileTab->histListView->currentItem();
00139         if (!item || !fileTab->spinBoxRevision->isEnabled())
00140                 return;
00141 
00142         int id = item->text(QGit::ANN_ID_COL).toInt();
00143         fileTab->spinBoxRevision->setValue(id); // triggers on_spinBoxRevision_valueChanged()
00144 }
00145 
00146 bool FileView::doUpdate(bool force) {
00147 
00148         if (st.fileName().isEmpty())
00149                 return false;
00150 
00151         if (st.isChanged(StateInfo::FILE_NAME) || force) {
00152 
00153                 clear(false);
00154                 m()->tabWdg->changeTab(fileTab, st.fileName());
00155                 fh->clear(st.fileName());
00156                 if (git->startFileHistory(fh)) {
00157                         QApplication::restoreOverrideCursor();
00158                         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
00159                         m()->statusBar()->message("Retrieving history of '" +
00160                                                    st.fileName() + "'...");
00161                 }
00162         } else if (histListView->update() || st.sha().isEmpty()) {
00163 
00164                 updateSpinBoxValue();
00165                 m()->statusBar()->message(git->getRevInfo(st.sha()));
00166         }
00167         if (!fileTab->toolButtonPin->isOn())
00168                 textEditFile->update();
00169 
00170         return true; // always accept new state
00171 }
00172 
00173 // ************************************ SLOTS ********************************
00174 
00175 void FileView::updateEnabledButtons() {
00176 
00177         QToolButton* copy = fileTab->toolButtonCopy;
00178         QToolButton* showAnnotate = fileTab->toolButtonShowAnnotate;
00179         QToolButton* findAnnotate = fileTab->toolButtonFindAnnotate;
00180         QToolButton* rangeFilter = fileTab->toolButtonRangeFilter;
00181         QToolButton* highlight = fileTab->toolButtonHighlightText;
00182 
00183         // first enable
00184         copy->setEnabled(fileAvailable);
00185         showAnnotate->setEnabled(annotateAvailable);
00186         findAnnotate->setEnabled(annotateAvailable);
00187         rangeFilter->setEnabled(annotateAvailable);
00188         highlight->setEnabled(fileAvailable && git->isTextHighlighter());
00189 
00190         // then disable
00191         if (!showAnnotate->isOn())
00192                 findAnnotate->setEnabled(false);
00193 
00194         if (highlight->isOn()) {
00195                 findAnnotate->setEnabled(false);
00196                 rangeFilter->setEnabled(false);
00197         }
00198         if (rangeFilter->isOn())
00199                 highlight->setEnabled(false);
00200 
00201         // special case: reset range filter when changing file
00202         if (!annotateAvailable && rangeFilter->isOn())
00203                 rangeFilter->toggle();
00204 }
00205 
00206 void FileView::on_toolButtonCopy_clicked() {
00207 
00208         textEditFile->copySelection();
00209 }
00210 
00211 void FileView::on_toolButtonShowAnnotate_toggled(bool b) {
00212 
00213         updateEnabledButtons();
00214         textEditFile->setShowAnnotate(b);
00215 
00216         if (b && fileTab->toolButtonFindAnnotate->isOn())
00217                 goToCurrentAnnotation();
00218 }
00219 
00220 void FileView::on_toolButtonFindAnnotate_toggled(bool b) {
00221 
00222         updateEnabledButtons();
00223         if (b)
00224                 goToCurrentAnnotation();
00225 }
00226 
00227 void FileView::on_toolButtonPin_toggled(bool b) {
00228 // button is enabled and togglable only if st.sha() is found
00229 
00230         fileTab->spinBoxRevision->setDisabled(b);
00231 
00232         if (!b) {
00233                 updateSpinBoxValue(); // UPDATE() call is filtered in this case
00234                 textEditFile->update(true);
00235         }
00236 }
00237 
00238 void FileView::on_toolButtonRangeFilter_toggled(bool b) {
00239 
00240         updateEnabledButtons();
00241         if (b) {
00242                 if (!textEditFile->annotateAvailable()) {
00243                         dbs("ASSERT in on_toolButtonRangeFilter_toggled: annotate not available");
00244                         return;
00245                 }
00246                 if (!fileTab->textEditFile->hasSelectedText()) {
00247                         m()->statusBar()->message("Please select some text");
00248                         return;
00249                 }
00250         }
00251         bool rangeFilterActive = textEditFile->rangeFilter(b);
00252         filterOnRange(rangeFilterActive);
00253 }
00254 
00255 void FileView::on_toolButtonHighlightText_toggled(bool b) {
00256 
00257         updateEnabledButtons();
00258         textEditFile->setHighlightSource(b);
00259 }
00260 
00261 void FileView::on_spinBoxRevision_valueChanged(int id) {
00262 
00263         if (id != fileTab->spinBoxRevision->minValue()) {
00264 
00265                 SCRef selRev(histListView->getSha(id));
00266 
00267                 if (st.sha() != selRev) { // to avoid looping
00268                         st.setSha(selRev);
00269                         st.setSelectItem(true);
00270                         UPDATE();
00271                 }
00272         }
00273 }
00274 
00275 void FileView::on_loadCompleted(const FileHistory* f, const QString&) {
00276 
00277         QApplication::restoreOverrideCursor();
00278 
00279         if (f != fh)
00280                 return;
00281 
00282         histListView->updateIdValues();
00283         int maxId = fileTab->histListView->childCount();
00284         if (maxId == 0) {
00285                 m()->statusBar()->clear();
00286                 return;
00287         }
00288         fileTab->spinBoxRevision->setMaxValue(maxId);
00289         fileTab->toolButtonPin->setEnabled(true);
00290         fileTab->spinBoxRevision->setEnabled(true);
00291 
00292         UPDATE();
00293 
00294         updateProgressBar(0);
00295         textEditFile->startAnnotate(fh);
00296 }
00297 
00298 void FileView::showAnnotation() {
00299 
00300         if (  !fileTab->toolButtonPin->isOn()
00301             && fileTab->toolButtonShowAnnotate->isEnabled()
00302             && fileTab->toolButtonShowAnnotate->isOn()) {
00303 
00304                 textEditFile->setShowAnnotate(true);
00305 
00306                 if (   fileTab->toolButtonFindAnnotate->isEnabled()
00307                     && fileTab->toolButtonFindAnnotate->isOn())
00308 
00309                         goToCurrentAnnotation();
00310         }
00311 }
00312 
00313 void FileView::on_annotationAvailable(bool b) {
00314 
00315         annotateAvailable = b;
00316         updateEnabledButtons();
00317 
00318         if (b)
00319                 showAnnotation(); // in case annotation got ready after file
00320 }
00321 
00322 void FileView::on_fileAvailable(bool b) {
00323 
00324         fileAvailable = b;
00325         updateEnabledButtons();
00326 
00327         if (b) {
00328                 // code range is independent from annotation
00329                 if (fileTab->toolButtonRangeFilter->isOn())
00330                         textEditFile->goToRangeStart();
00331 
00332                 showAnnotation(); // in case file got ready after annotation
00333         }
00334 }
00335 
00336 void FileView::on_revIdSelected(int id) {
00337 
00338         if (id == 0)
00339                 return;
00340 
00341         if (fileTab->spinBoxRevision->isEnabled())
00342                 fileTab->spinBoxRevision->setValue(id);
00343         else {
00344                 QListView* hv = fileTab->histListView;
00345                 QString row = QString::number(id);
00346                 QListViewItem* item = hv->findItem(row, QGit::ANN_ID_COL, Qt::Contains);
00347                 hv->setCurrentItem(item);
00348         }
00349 }
00350 
00351 // ******************************* data events ****************************
00352 
00353 void FileView::customEvent(QCustomEvent* e) {
00354 
00355         if (e->type() == (int)QGit::ANN_PRG_EV)
00356                 updateProgressBar(((AnnotateProgressEvent*)e)->myData().toInt());
00357         else
00358                 Domain::customEvent(e);
00359 }
00360 
00361 void FileView::updateProgressBar(int annotatedNum) {
00362 
00363         uint tot = fileTab->histListView->childCount();
00364         if (tot == 0)
00365                 return;
00366 
00367         int cc = (annotatedNum * 100) / tot;
00368         int idx = (annotatedNum * 40) / tot;
00369         QString head("Annotating '" + st.fileName() + "' [");
00370         QString tail("] " + QString::number(cc) + " %");
00371         QString done, toDo;
00372         done.fill('.', idx);
00373         toDo.fill(' ', 40 - idx);
00374         m()->statusBar()->message(head + done + toDo + tail);
00375 }
00376 
00377 void FileView::filterOnRange(bool isOn) {
00378 // TODO integrate with mainimpl function
00379 
00380         QListView* hv = fileTab->histListView;
00381         QListViewItemIterator it(hv);
00382         bool evenLine = false;
00383         int visibleCnt = 0;
00384         RangeInfo r;
00385         while (it.current()) {
00386                 ListViewItem* item = static_cast<ListViewItem*>(it.current());
00387 
00388                 if (isOn) {
00389                         if (!textEditFile->getRange(item->sha(), &r))
00390                                 continue;
00391 
00392                         if (r.modified) {
00393                                 item->setEven(evenLine);
00394                                 evenLine = !evenLine;
00395                                 visibleCnt++;
00396                         } else
00397                                 item->setVisible(false);
00398                 } else {
00399                         item->setEven(evenLine);
00400                         evenLine = !evenLine;
00401                         if (!item->isVisible())
00402                                 item->setVisible(true);
00403                 }
00404                 ++it;
00405         }
00406         QString msg;
00407         if (isOn)
00408                 msg = QString("Found %1 matches. Toggle filter "
00409                               "button to remove the filter").arg(visibleCnt);
00410         else
00411                 hv->ensureItemVisible(hv->currentItem());
00412 
00413         m()->statusBar()->message(msg);
00414 }

Generated on Fri Dec 7 21:57:37 2007 for QGit by  doxygen 1.5.3