2 Author: Marco Costalba (C) 2005-2007
4 Copyright: See COPYING file that comes with this distribution
7 #include <QApplication>
10 #include "FileHistory.h"
11 #include "exceptionmanager.h"
18 void StateInfo::S::clear() {
20 sha
= fn
= dtSha
= "";
25 bool StateInfo::S::operator==(const StateInfo::S
& st
) const {
30 return ( sha
== st
.sha
38 bool StateInfo::S::operator!=(const StateInfo::S
& st
) const {
40 return !(StateInfo::S::operator==(st
));
43 void StateInfo::clear() {
51 StateInfo
& StateInfo::operator=(const StateInfo
& newState
) {
53 if (&newState
!= this) {
55 nextS
= newState
.curS
;
57 curS
= newState
.curS
; // prevS is mot modified to allow a rollback
62 bool StateInfo::operator==(const StateInfo
& newState
) const {
64 if (&newState
== this)
67 return (curS
== newState
.curS
); // compare is made on curS only
70 bool StateInfo::operator!=(const StateInfo
& newState
) const {
72 return !(StateInfo::operator==(newState
));
75 bool StateInfo::isChanged(uint what
) const {
79 ret
= (sha(true) != sha(false));
81 if (!ret
&& (what
& FILE_NAME
))
82 ret
= (fileName(true) != fileName(false));
84 if (!ret
&& (what
& DIFF_TO_SHA
))
85 ret
= (diffToSha(true) != diffToSha(false));
87 if (!ret
&& (what
& ALL_MERGE_FILES
))
88 ret
= (allMergeFiles(true) != allMergeFiles(false));
93 // ************************* Domain ****************************
95 Domain::Domain(MainImpl
* m
, Git
* g
, bool isMain
) : QObject(m
), git(g
) {
97 EM_INIT(exDeleteRequest
, "Deleting domain");
98 EM_INIT(exCancelRequest
, "Canceling update");
100 fileHistory
= new FileHistory(this, git
);
102 git
->setDefaultModel(fileHistory
);
105 busy
= linked
= false;
107 container
= new QWidget(NULL
); // will be reparented to m()->tabWdg
115 // remove before to delete, avoids a Qt warning in QInputContext()
116 m()->tabWdg
->removeTab(m()->tabWdg
->indexOf(container
));
117 container
->deleteLater();
120 void Domain::clear(bool complete
) {
125 fileHistory
->clear();
128 void Domain::on_closeAllTabs() {
130 delete this; // must be sync, deleteLater() does not work
133 void Domain::deleteWhenDone() {
135 if (!EM_IS_PENDING(exDeleteRequest
))
136 EM_RAISE(exDeleteRequest
);
138 emit
cancelDomainProcesses();
143 void Domain::on_deleteWhenDone() {
145 if (!EM_IS_PENDING(exDeleteRequest
))
148 QTimer::singleShot(20, this, SLOT(on_deleteWhenDone()));
151 void Domain::setThrowOnDelete(bool b
) {
154 EM_REGISTER(exDeleteRequest
);
156 EM_REMOVE(exDeleteRequest
);
159 bool Domain::isThrowOnDeleteRaised(int excpId
, SCRef curContext
) {
161 return EM_MATCH(excpId
, exDeleteRequest
, curContext
);
164 MainImpl
* Domain::m() const {
166 return static_cast<MainImpl
*>(parent());
169 void Domain::showStatusBarMessage(const QString
& msg
, int timeout
) {
171 m()->statusBar()->showMessage(msg
, timeout
);
174 void Domain::setTabCaption(const QString
& caption
) {
176 int idx
= m()->tabWdg
->indexOf(container
);
177 m()->tabWdg
->setTabText(idx
, caption
);
180 void Domain::unlinkDomain(Domain
* d
) {
183 while (d
->disconnect(SIGNAL(updateRequested(StateInfo
)), this))
184 ;// a signal is emitted for every connection you make,
185 // so if you duplicate a connection, two signals will be emitted.
188 void Domain::linkDomain(Domain
* d
) {
190 unlinkDomain(d
); // be sure only one connection is active
191 connect(d
, SIGNAL(updateRequested(StateInfo
)), this, SLOT(on_updateRequested(StateInfo
)));
195 void Domain::on_updateRequested(StateInfo newSt
) {
201 bool Domain::flushQueue() {
202 // during dragging any state update is queued, so try to flush pending now
204 if (!busy
&& st
.flushQueue()) {
211 bool Domain::event(QEvent
* e
) {
213 bool fromMaster
= false;
215 switch (int(e
->type())) {
220 update(fromMaster
, ((UpdateDomainEvent
*)e
)->isForced());
223 if (!busy
&& !st
.requestPending())
224 QApplication::postEvent(m(), new MessageEvent(((MessageEvent
*)e
)->myData()));
225 else // waiting for the end of updating
226 statusBarRequest
= ((MessageEvent
*)e
)->myData();
231 return QObject::event(e
);
234 void Domain::populateState() {
236 const Rev
* r
= git
->revLookup(st
.sha());
238 st
.setIsMerge(r
->parentsCount() > 1);
241 void Domain::update(bool fromMaster
, bool force
) {
243 if (busy
&& st
.requestPending()) {
244 // quick exit current (obsoleted) update but only if state
245 // is going to change. Without this check calling update()
246 // many times with the same data nullify the update
247 EM_RAISE(exCancelRequest
);
248 emit
cancelDomainProcesses();
253 if (linked
&& !fromMaster
) {
254 // in this case let the update to fall down from master domain
256 st
.rollBack(); // we don't want to filter out next update sent from master
257 emit
updateRequested(tmp
);
261 EM_REGISTER_Q(exCancelRequest
); // quiet, no messages when thrown
262 setThrowOnDelete(true);
263 git
->setThrowOnStop(true);
264 git
->setCurContext(this);
266 populateState(); // complete any missing state information
267 st
.setLock(true); // any state change will be queued now
276 if (git
->curContext() != this)
277 qDebug("ASSERT in Domain::update, context is %p "
278 "instead of %p", (void*)git
->curContext(), (void*)this);
280 git
->setCurContext(NULL
);
281 git
->setThrowOnStop(false);
282 setThrowOnDelete(false);
283 EM_REMOVE(exCancelRequest
);
288 If we have a cancel request because of a new update is in queue we
289 cannot roolback current state to avoid new update is filtered out
290 in case rolled back sha and new sha are the same.
291 This could happen with arrow navigation:
293 sha -> go UP (new sha) -> go DOWN (cancel) -> rollback to sha
295 And pending request 'sha' is filtered out leaving us in an
301 git
->setCurContext(NULL
);
302 git
->setThrowOnStop(false);
303 setThrowOnDelete(false);
304 EM_REMOVE(exCancelRequest
);
306 if (QApplication::overrideCursor())
307 QApplication::restoreOverrideCursor();
309 QString
context("updating ");
310 if (git
->isThrowOnStopRaised(i
, context
+ metaObject()->className())) {
314 if (isThrowOnDeleteRaised(i
, context
+ metaObject()->className())) {
318 if (i
== exCancelRequest
)
322 const QString
info("Exception \'" + EM_DESC(i
) + "\' "
323 "not handled in init...re-throw");
328 bool nextRequestPending
= flushQueue();
330 if (!nextRequestPending
&& !statusBarRequest
.isEmpty()) {
331 // update status bar when we are sure no more work is pending
332 QApplication::postEvent(m(), new MessageEvent(statusBarRequest
));
333 statusBarRequest
= "";
335 if (!nextRequestPending
&& popupType
)
339 void Domain::sendPopupEvent() {
341 // call an async context popup, must be executed
342 // after returning to event loop
343 DeferredPopupEvent
* e
= new DeferredPopupEvent(popupData
, popupType
);
344 QApplication::postEvent(m(), e
);
348 void Domain::on_contextMenu(const QString
& data
, int type
) {
354 return; // we are in the middle of an update
356 // if list view is already updated pop-up
357 // context menu, otherwise it means update()
358 // has still not been called, a pop-up request,
359 // will be fired up at the end of next update()
360 if ((type
== POPUP_LIST_EV
) && (data
!= st
.sha()))