00001 
00002 
00003 
00004 
00005 
00006 
00007 #include <qapplication.h>
00008 #include <qlistview.h>
00009 #include "exceptionmanager.h"
00010 #include "mainimpl.h"
00011 #include "git.h"
00012 #include "domain.h"
00013 
00014 using namespace QGit;
00015 
00016 void StateInfo::S::clear() {
00017 
00018         sha = fn = dtSha = "";
00019         isM = allM = false;
00020         sel = true;
00021 }
00022 
00023 bool StateInfo::S::operator==(const StateInfo::S& st) const {
00024 
00025         if (&st == this)
00026                 return true;
00027 
00028         return (   sha   == st.sha
00029                 && fn    == st.fn
00030                 && dtSha == st.dtSha
00031                 && sel   == st.sel
00032                 && isM   == st.isM
00033                 && allM  == st.allM);
00034 }
00035 
00036 bool StateInfo::S::operator!=(const StateInfo::S& st) const {
00037 
00038         return !(StateInfo::S::operator==(st));
00039 }
00040 
00041 void StateInfo::clear() {
00042 
00043         nextS.clear();
00044         curS.clear();
00045         prevS.clear();
00046         isLocked = false;
00047 }
00048 
00049 StateInfo& StateInfo::operator=(const StateInfo& newState) {
00050 
00051         if (&newState != this) {
00052                 if (isLocked)
00053                         nextS = newState.curS;
00054                 else
00055                         curS = newState.curS; 
00056         }
00057         return *this;
00058 }
00059 
00060 bool StateInfo::operator==(const StateInfo& newState) const {
00061 
00062         if (&newState == this)
00063                 return true;
00064 
00065         return (curS == newState.curS); 
00066 }
00067 
00068 bool StateInfo::operator!=(const StateInfo& newState) const {
00069 
00070         return !(StateInfo::operator==(newState));
00071 }
00072 
00073 bool StateInfo::isChanged(uint what) const {
00074 
00075         bool ret = false;
00076         if (what & SHA)
00077                 ret = (sha(true) != sha(false));
00078 
00079         if (!ret && (what & FILE_NAME))
00080                 ret = (fileName(true) != fileName(false));
00081 
00082         if (!ret && (what & DIFF_TO_SHA))
00083                 ret = (diffToSha(true) != diffToSha(false));
00084 
00085         if (!ret && (what & ALL_MERGE_FILES))
00086                 ret = (allMergeFiles(true) != allMergeFiles(false));
00087 
00088         return ret;
00089 }
00090 
00091 
00092 
00093 Domain::Domain(MainImpl* m, Git* g) : QObject(m), git(g) {
00094 
00095         EM_INIT(exDeleteRequest, "Deleting domain");
00096         EM_INIT(exCancelRequest, "Canceling update");
00097 
00098         st.clear();
00099         busy = readyToDrag = dragging = dropping = linked = false;
00100         popupType = 0;
00101         tabPosition = -1;
00102 
00103         connect(m, SIGNAL(tabClosed(int)), this, SLOT(on_tabClosed(int)));
00104 }
00105 
00106 void Domain::on_closeAllTabs() {
00107 
00108         delete this; 
00109 }
00110 
00111 void Domain::deleteWhenDone() {
00112 
00113         if (!EM_IS_PENDING(exDeleteRequest))
00114                 EM_RAISE(exDeleteRequest);
00115 
00116         emit cancelDomainProcesses();
00117 
00118         on_deleteWhenDone();
00119 }
00120 
00121 void Domain::on_deleteWhenDone() {
00122 
00123         if (!EM_IS_PENDING(exDeleteRequest))
00124                 deleteLater();
00125         else
00126                 QTimer::singleShot(20, this, SLOT(on_deleteWhenDone()));
00127 }
00128 
00129 void Domain::on_tabClosed(int tabPos) {
00130 
00131         if (tabPosition > tabPos)
00132                 tabPosition--;
00133 }
00134 
00135 void Domain::setThrowOnDelete(bool b) {
00136 
00137         if (b)
00138                 EM_REGISTER(exDeleteRequest);
00139         else
00140                 EM_REMOVE(exDeleteRequest);
00141 }
00142 
00143 bool Domain::isThrowOnDeleteRaised(int excpId, SCRef curContext) {
00144 
00145         return EM_MATCH(excpId, exDeleteRequest, curContext);
00146 }
00147 
00148 MainImpl* Domain::m() const {
00149 
00150         return static_cast<MainImpl*>(parent());
00151 }
00152 
00153 const QString Domain::dragHostName() const {
00154 
00155         return QString::fromLatin1("@") + m()->curWorkDir();
00156 }
00157 
00158 bool Domain::setReadyToDrag(bool b) {
00159 
00160         readyToDrag = (b && !busy && !dragging && !dropping);
00161         return readyToDrag;
00162 }
00163 
00164 bool Domain::setDragging(bool b) {
00165 
00166         bool dragFinished = (!b && dragging);
00167 
00168         dragging = (b && readyToDrag && !dropping);
00169 
00170         if (dragging)
00171                 readyToDrag = false;
00172 
00173         if (dragFinished)
00174                 flushQueue();
00175 
00176         return dragging;
00177 }
00178 
00179 void Domain::unlinkDomain(Domain* d) {
00180 
00181         d->linked = false;
00182         while (d->disconnect(SIGNAL(updateRequested(StateInfo)), this))
00183                 ;
00184                  
00185 }
00186 
00187 void Domain::linkDomain(Domain* d) {
00188 
00189         unlinkDomain(d); 
00190         connect(d, SIGNAL(updateRequested(StateInfo)), this, SLOT(on_updateRequested(StateInfo)));
00191         d->linked = true;
00192 }
00193 
00194 void Domain::on_updateRequested(StateInfo newSt) {
00195 
00196         st = newSt;
00197         UPDATE();
00198 }
00199 
00200 bool Domain::flushQueue() {
00201 
00202 
00203         if (!busy && st.flushQueue()) {
00204                 UPDATE();
00205                 return true;
00206         }
00207         return false;
00208 }
00209 
00210 void Domain::customEvent(QCustomEvent* e) {
00211 
00212         bool fromMaster = false;
00213 
00214         switch (e->type()) {
00215         case UPD_DM_MST_EV:
00216                 fromMaster = true;
00217                 
00218         case UPD_DM_EV:
00219                 update(fromMaster, ((UpdateDomainEvent*)e)->isForced());
00220                 break;
00221         case MSG_EV:
00222                 if (!busy && !st.requestPending())
00223                         QApplication::postEvent(m(), new MessageEvent(((MessageEvent*)e)->myData()));
00224                 else 
00225                         statusBarRequest = ((MessageEvent*)e)->myData();
00226                 break;
00227         default:
00228                 break;
00229         }
00230         QObject::customEvent(e);
00231 }
00232 
00233 void Domain::populateState() {
00234 
00235         const Rev* r = git->revLookup(st.sha());
00236         if (r)
00237                 st.setIsMerge(r->parentsCount() > 1);
00238 }
00239 
00240 void Domain::update(bool fromMaster, bool force) {
00241 
00242         if (busy && st.requestPending()) {
00243                 
00244                 
00245                 
00246                 EM_RAISE(exCancelRequest);
00247                 emit cancelDomainProcesses();
00248         }
00249         if (busy || dragging)
00250                 return;
00251 
00252         if (linked && !fromMaster) {
00253                 
00254                 StateInfo tmp(st);
00255                 st.rollBack(); 
00256                 emit updateRequested(tmp);
00257                 return;
00258         }
00259         try {
00260                 EM_REGISTER_Q(exCancelRequest); 
00261                 setThrowOnDelete(true);
00262                 git->setThrowOnStop(true);
00263                 git->setCurContext(this);
00264                 busy = true;
00265                 setReadyToDrag(false); 
00266                 populateState(); 
00267                 st.setLock(true); 
00268 
00269                 if (doUpdate(force))
00270                         st.commit();
00271                 else
00272                         st.rollBack();
00273 
00274                 st.setLock(false);
00275                 busy = false;
00276                 if (git->curContext() != this)
00277                         qDebug("ASSERT in Domain::update, context is %p "
00278                                "instead of %p", (void*)git->curContext(), (void*)this);
00279 
00280                 git->setCurContext(NULL);
00281                 git->setThrowOnStop(false);
00282                 setThrowOnDelete(false);
00283                 EM_REMOVE(exCancelRequest);
00284 
00285         } catch (int i) {
00286 
00287                 
00288 
00289 
00290 
00291 
00292 
00293 
00294 
00295 
00296 
00297 
00298                 st.commit();
00299                 st.setLock(false);
00300                 busy = false;
00301                 git->setCurContext(NULL);
00302                 git->setThrowOnStop(false);
00303                 setThrowOnDelete(false);
00304                 EM_REMOVE(exCancelRequest);
00305 
00306                 if (QApplication::overrideCursor())
00307                         QApplication::restoreOverrideCursor();
00308 
00309                 QString context("updating ");
00310                 if (git->isThrowOnStopRaised(i,  context + className())) {
00311                         EM_THROW_PENDING;
00312                         return;
00313                 }
00314                 if (isThrowOnDeleteRaised(i,  context + className())) {
00315                         EM_THROW_PENDING;
00316                         return;
00317                 }
00318                 if (i == exCancelRequest)
00319                         EM_THROW_PENDING;
00320                         
00321                 else {
00322                         const QString info("Exception \'" + EM_DESC(i) + "\' "
00323                                            "not handled in init...re-throw");
00324                         dbs(info);
00325                         throw;
00326                 }
00327         }
00328         bool nextRequestPending = flushQueue();
00329 
00330         if (!nextRequestPending && !statusBarRequest.isEmpty()) {
00331                 
00332                 QApplication::postEvent(m(), new MessageEvent(statusBarRequest));
00333                 statusBarRequest = "";
00334         }
00335         if (!nextRequestPending && popupType)
00336                 sendPopupEvent();
00337 }
00338 
00339 void Domain::sendPopupEvent() {
00340 
00341         
00342         
00343         DeferredPopupEvent* e = new DeferredPopupEvent(popupData, popupType);
00344         QApplication::postEvent(m(), e);
00345         popupType = 0;
00346 }
00347 
00348 void Domain::on_contextMenu(const QString& data, int type) {
00349 
00350         popupType = type;
00351         popupData = data;
00352 
00353         if (busy)
00354                 return; 
00355 
00356         
00357         
00358         
00359         
00360         if ((type == POPUP_LIST_EV) && (data != st.sha()))
00361                 return;
00362 
00363         sendPopupEvent();
00364 }