2 Author: Marco Costalba (C) 2005-2007
4 Copyright: See COPYING file that comes with this distribution
7 #include <QApplication>
10 #include "exceptionmanager.h"
17 void StateInfo::S::clear() {
19 sha
= fn
= dtSha
= "";
24 bool StateInfo::S::operator==(const StateInfo::S
& st
) const {
29 return ( sha
== st
.sha
37 bool StateInfo::S::operator!=(const StateInfo::S
& st
) const {
39 return !(StateInfo::S::operator==(st
));
42 void StateInfo::clear() {
50 StateInfo
& StateInfo::operator=(const StateInfo
& newState
) {
52 if (&newState
!= this) {
54 nextS
= newState
.curS
;
56 curS
= newState
.curS
; // prevS is mot modified to allow a rollback
61 bool StateInfo::operator==(const StateInfo
& newState
) const {
63 if (&newState
== this)
66 return (curS
== newState
.curS
); // compare is made on curS only
69 bool StateInfo::operator!=(const StateInfo
& newState
) const {
71 return !(StateInfo::operator==(newState
));
74 bool StateInfo::isChanged(uint what
) const {
78 ret
= (sha(true) != sha(false));
80 if (!ret
&& (what
& FILE_NAME
))
81 ret
= (fileName(true) != fileName(false));
83 if (!ret
&& (what
& DIFF_TO_SHA
))
84 ret
= (diffToSha(true) != diffToSha(false));
86 if (!ret
&& (what
& ALL_MERGE_FILES
))
87 ret
= (allMergeFiles(true) != allMergeFiles(false));
92 // ************************* Domain ****************************
94 Domain::Domain(MainImpl
* m
, Git
* g
, bool isMain
) : QObject(m
), git(g
) {
96 EM_INIT(exDeleteRequest
, "Deleting domain");
97 EM_INIT(exCancelRequest
, "Canceling update");
99 fileHistory
= new FileHistory(this, git
);
101 git
->setDefaultModel(fileHistory
);
104 busy
= readyToDrag
= dragging
= dropping
= linked
= false;
106 container
= new QWidget(NULL
); // will be reparented to m()->tabWdg
114 // remove before to delete, avoids a Qt warning in QInputContext()
115 m()->tabWdg
->removeTab(m()->tabWdg
->indexOf(container
));
119 void Domain::clear(bool complete
) {
124 fileHistory
->clear();
127 void Domain::on_closeAllTabs() {
129 delete this; // must be sync, deleteLater() does not work
132 void Domain::deleteWhenDone() {
134 if (!EM_IS_PENDING(exDeleteRequest
))
135 EM_RAISE(exDeleteRequest
);
137 emit
cancelDomainProcesses();
142 void Domain::on_deleteWhenDone() {
144 if (!EM_IS_PENDING(exDeleteRequest
))
147 QTimer::singleShot(20, this, SLOT(on_deleteWhenDone()));
150 void Domain::setThrowOnDelete(bool b
) {
153 EM_REGISTER(exDeleteRequest
);
155 EM_REMOVE(exDeleteRequest
);
158 bool Domain::isThrowOnDeleteRaised(int excpId
, SCRef curContext
) {
160 return EM_MATCH(excpId
, exDeleteRequest
, curContext
);
163 MainImpl
* Domain::m() const {
165 return static_cast<MainImpl
*>(parent());
168 void Domain::showStatusBarMessage(const QString
& msg
, int timeout
) {
170 m()->statusBar()->showMessage(msg
, timeout
);
173 void Domain::setTabCaption(const QString
& caption
) {
175 int idx
= m()->tabWdg
->indexOf(container
);
176 m()->tabWdg
->setTabText(idx
, caption
);
179 bool Domain::setReadyToDrag(bool b
) {
181 readyToDrag
= (b
&& !busy
&& !dragging
&& !dropping
);
185 bool Domain::setDragging(bool b
) {
187 bool dragFinished
= (!b
&& dragging
);
189 dragging
= (b
&& readyToDrag
&& !dropping
);
200 void Domain::unlinkDomain(Domain
* d
) {
203 while (d
->disconnect(SIGNAL(updateRequested(StateInfo
)), this))
204 ;// a signal is emitted for every connection you make,
205 // so if you duplicate a connection, two signals will be emitted.
208 void Domain::linkDomain(Domain
* d
) {
210 unlinkDomain(d
); // be sure only one connection is active
211 connect(d
, SIGNAL(updateRequested(StateInfo
)), this, SLOT(on_updateRequested(StateInfo
)));
215 void Domain::on_updateRequested(StateInfo newSt
) {
221 bool Domain::flushQueue() {
222 // during dragging any state update is queued, so try to flush pending now
224 if (!busy
&& st
.flushQueue()) {
231 bool Domain::event(QEvent
* e
) {
233 bool fromMaster
= false;
240 update(fromMaster
, ((UpdateDomainEvent
*)e
)->isForced());
243 if (!busy
&& !st
.requestPending())
244 QApplication::postEvent(m(), new MessageEvent(((MessageEvent
*)e
)->myData()));
245 else // waiting for the end of updating
246 statusBarRequest
= ((MessageEvent
*)e
)->myData();
251 return QObject::event(e
);
254 void Domain::populateState() {
256 const Rev
* r
= git
->revLookup(st
.sha());
258 st
.setIsMerge(r
->parentsCount() > 1);
261 void Domain::update(bool fromMaster
, bool force
) {
263 if (busy
&& st
.requestPending()) {
264 // quick exit current (obsoleted) update but only if state
265 // is going to change. Without this check calling update()
266 // many times with the same data nullify the update
267 EM_RAISE(exCancelRequest
);
268 emit
cancelDomainProcesses();
270 if (busy
|| dragging
)
273 if (linked
&& !fromMaster
) {
274 // in this case let the update to fall down from master domain
276 st
.rollBack(); // we don't want to filter out next update sent from master
277 emit
updateRequested(tmp
);
281 EM_REGISTER_Q(exCancelRequest
); // quiet, no messages when thrown
282 setThrowOnDelete(true);
283 git
->setThrowOnStop(true);
284 git
->setCurContext(this);
286 setReadyToDrag(false); // do not start any drag while updating
287 populateState(); // complete any missing state information
288 st
.setLock(true); // any state change will be queued now
297 if (git
->curContext() != this)
298 qDebug("ASSERT in Domain::update, context is %p "
299 "instead of %p", (void*)git
->curContext(), (void*)this);
301 git
->setCurContext(NULL
);
302 git
->setThrowOnStop(false);
303 setThrowOnDelete(false);
304 EM_REMOVE(exCancelRequest
);
309 If we have a cancel request because of a new update is in queue we
310 cannot roolback current state to avoid new update is filtered out
311 in case rolled back sha and new sha are the same.
312 This could happen with arrow navigation:
314 sha -> go UP (new sha) -> go DOWN (cancel) -> rollback to sha
316 And pending request 'sha' is filtered out leaving us in an
322 git
->setCurContext(NULL
);
323 git
->setThrowOnStop(false);
324 setThrowOnDelete(false);
325 EM_REMOVE(exCancelRequest
);
327 if (QApplication::overrideCursor())
328 QApplication::restoreOverrideCursor();
330 QString
context("updating ");
331 if (git
->isThrowOnStopRaised(i
, context
+ metaObject()->className())) {
335 if (isThrowOnDeleteRaised(i
, context
+ metaObject()->className())) {
339 if (i
== exCancelRequest
)
343 const QString
info("Exception \'" + EM_DESC(i
) + "\' "
344 "not handled in init...re-throw");
349 bool nextRequestPending
= flushQueue();
351 if (!nextRequestPending
&& !statusBarRequest
.isEmpty()) {
352 // update status bar when we are sure no more work is pending
353 QApplication::postEvent(m(), new MessageEvent(statusBarRequest
));
354 statusBarRequest
= "";
356 if (!nextRequestPending
&& popupType
)
360 void Domain::sendPopupEvent() {
362 // call an async context popup, must be executed
363 // after returning to event loop
364 DeferredPopupEvent
* e
= new DeferredPopupEvent(popupData
, popupType
);
365 QApplication::postEvent(m(), e
);
369 void Domain::on_contextMenu(const QString
& data
, int type
) {
375 return; // we are in the middle of an update
377 // if list view is already updated pop-up
378 // context menu, otherwise it means update()
379 // has still not been called, a pop-up request,
380 // will be fired up at the end of next update()
381 if ((type
== POPUP_LIST_EV
) && (data
!= st
.sha()))