FreeCAD

Форк
0
/
AutoTransaction.cpp 
243 строки · 8.1 Кб
1
/****************************************************************************
2
 *   Copyright (c) 2019 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
3
 *                                                                          *
4
 *   This file is part of the FreeCAD CAx development system.               *
5
 *                                                                          *
6
 *   This library is free software; you can redistribute it and/or          *
7
 *   modify it under the terms of the GNU Library General Public            *
8
 *   License as published by the Free Software Foundation; either           *
9
 *   version 2 of the License, or (at your option) any later version.       *
10
 *                                                                          *
11
 *   This library  is distributed in the hope that it will be useful,       *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
14
 *   GNU Library General Public License for more details.                   *
15
 *                                                                          *
16
 *   You should have received a copy of the GNU Library General Public      *
17
 *   License along with this library; see the file COPYING.LIB. If not,     *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,          *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                 *
20
 *                                                                          *
21
 ****************************************************************************/
22

23
#include "PreCompiled.h"
24

25
#include <Base/Interpreter.h>
26

27
#include "AutoTransaction.h"
28
#include "Application.h"
29
#include "Document.h"
30
#include "Transactions.h"
31

32

33
FC_LOG_LEVEL_INIT("App", true, true)
34

35
using namespace App;
36

37
static int _TransactionLock;
38
static int _TransactionClosed;
39

40
AutoTransaction::AutoTransaction(const char *name, bool tmpName) {
41
    auto &app = GetApplication();
42
    if(name && app._activeTransactionGuard>=0) {
43
        if(!app.getActiveTransaction()
44
                || (!tmpName && app._activeTransactionTmpName))
45
        {
46
            FC_LOG("auto transaction '" << name << "', " << tmpName);
47
            tid = app.setActiveTransaction(name);
48
            app._activeTransactionTmpName = tmpName;
49
        }
50
    }
51
    // We use negative transaction guard to disable auto transaction from here
52
    // and any stack below. This is to support user setting active transaction
53
    // before having any existing AutoTransaction on stack, or 'persist'
54
    // transaction that can out live AutoTransaction.
55
    if(app._activeTransactionGuard<0)
56
        --app._activeTransactionGuard;
57
    else if(tid || app._activeTransactionGuard>0)
58
        ++app._activeTransactionGuard;
59
    else if(app.getActiveTransaction()) {
60
        FC_LOG("auto transaction disabled because of '" << app._activeTransactionName << "'");
61
        --app._activeTransactionGuard;
62
    } else
63
        ++app._activeTransactionGuard;
64
    FC_TRACE("construct auto Transaction " << app._activeTransactionGuard);
65
}
66

67
AutoTransaction::~AutoTransaction() {
68
    auto &app = GetApplication();
69
    FC_TRACE("before destruct auto Transaction " << app._activeTransactionGuard);
70
    if(app._activeTransactionGuard<0)
71
        ++app._activeTransactionGuard;
72
    else if(!app._activeTransactionGuard) {
73
#ifdef FC_DEBUG
74
        FC_ERR("Transaction guard error");
75
#endif
76
    } else if(--app._activeTransactionGuard == 0) {
77
        try {
78
            // We don't call close() here, because close() only closes
79
            // transaction that we opened during construction time. However,
80
            // when _activeTransactionGuard reaches zero here, we are supposed
81
            // to close any transaction opened.
82
            app.closeActiveTransaction();
83
        } catch(Base::Exception &e) {
84
            e.ReportException();
85
        } catch(...)
86
        {}
87
    }
88
    FC_TRACE("destruct auto Transaction " << app._activeTransactionGuard);
89
}
90

91
void AutoTransaction::close(bool abort) {
92
    if(tid || abort) {
93
        GetApplication().closeActiveTransaction(abort,abort?0:tid);
94
        tid = 0;
95
    }
96
}
97

98
void AutoTransaction::setEnable(bool enable) {
99
    auto &app = GetApplication();
100
    if(!app._activeTransactionGuard)
101
        return;
102
    if((enable && app._activeTransactionGuard>0)
103
            || (!enable && app._activeTransactionGuard<0))
104
        return;
105
    app._activeTransactionGuard = -app._activeTransactionGuard;
106
    FC_TRACE("toggle auto Transaction " << app._activeTransactionGuard);
107
    if(!enable && app._activeTransactionTmpName) {
108
        bool close = true;
109
        for(auto &v : app.DocMap) {
110
            if(v.second->hasPendingTransaction()) {
111
                close = false;
112
                break;
113
            }
114
        }
115
        if(close)
116
            app.closeActiveTransaction();
117
    }
118
}
119

120
int Application::setActiveTransaction(const char *name, bool persist) {
121
    if(!name || !name[0])
122
        name = "Command";
123

124
    if(_activeTransactionGuard>0 && getActiveTransaction()) {
125
        if(_activeTransactionTmpName) {
126
            FC_LOG("transaction rename to '" << name << "'");
127
            for(auto &v : DocMap)
128
                v.second->renameTransaction(name,_activeTransactionID);
129
        } else {
130
            if(persist)
131
                AutoTransaction::setEnable(false);
132
            return 0;
133
        }
134
    } else if (_TransactionLock) {
135
        if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG))
136
            FC_WARN("Transaction locked, ignore new transaction '" << name << "'");
137
        return 0;
138
    } else {
139
        FC_LOG("set active transaction '" << name << "'");
140
        _activeTransactionID = 0;
141
        for(auto &v : DocMap)
142
            v.second->_commitTransaction();
143
        _activeTransactionID = Transaction::getNewID();
144
    }
145
    _activeTransactionTmpName = false;
146
    _activeTransactionName = name;
147
    if(persist)
148
        AutoTransaction::setEnable(false);
149
    return _activeTransactionID;
150
}
151

152
const char *Application::getActiveTransaction(int *id) const {
153
    int tid = 0;
154
    if(Transaction::getLastID() == _activeTransactionID)
155
        tid = _activeTransactionID;
156
    if (id)
157
        *id = tid;
158
    return tid ? _activeTransactionName.c_str() : nullptr;
159
}
160

161
void Application::closeActiveTransaction(bool abort, int id) {
162
    if(!id) id = _activeTransactionID;
163
    if(!id)
164
        return;
165

166
    if(_activeTransactionGuard>0 && !abort) {
167
        FC_LOG("ignore close transaction");
168
        return;
169
    }
170

171
    if(_TransactionLock) {
172
        if(_TransactionClosed >= 0)
173
            _TransactionLock = abort?-1:1;
174
        FC_LOG("pending " << (abort?"abort":"close") << " transaction");
175
        return;
176
    }
177

178
    FC_LOG("close transaction '" << _activeTransactionName << "' " << abort);
179
    _activeTransactionID = 0;
180

181
    TransactionSignaller signaller(abort,false);
182
    for(auto &v : DocMap) {
183
        if(v.second->getTransactionID(true) != id)
184
            continue;
185
        if(abort)
186
            v.second->_abortTransaction();
187
        else
188
            v.second->_commitTransaction();
189
    }
190
}
191

192
////////////////////////////////////////////////////////////////////////
193

194
TransactionLocker::TransactionLocker(bool lock)
195
    :active(lock)
196
{
197
    if(lock)
198
        ++_TransactionLock;
199
}
200

201
TransactionLocker::~TransactionLocker()
202
{
203
    if(active) {
204
        try {
205
            activate(false);
206
            return;
207
        } catch (Base::Exception &e) {
208
            e.ReportException();
209
        } catch (Py::Exception &) {
210
            Base::PyException e;
211
            e.ReportException();
212
        } catch (std::exception &e) {
213
            FC_ERR(e.what());
214
        } catch (...) {
215
        }
216
        FC_ERR("Exception when unlocking transaction");
217
    }
218
}
219

220
void TransactionLocker::activate(bool enable)
221
{
222
    if(active == enable)
223
        return;
224

225
    active = enable;
226
    if(active) {
227
        ++_TransactionLock;
228
        return;
229
    }
230

231
    if(--_TransactionLock != 0)
232
        return;
233

234
    if(_TransactionClosed) {
235
        bool abort = (_TransactionClosed<0);
236
        _TransactionClosed = 0;
237
        GetApplication().closeActiveTransaction(abort);
238
    }
239
}
240

241
bool TransactionLocker::isLocked() {
242
    return _TransactionLock > 0;
243
}
244

245

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.