phase 1: copy Kindred-only files onto upstream/main (FreeCAD 1.2.0-dev)
Wholesale copy of all Kindred Create additions that don't conflict with upstream FreeCAD code: - kindred-icons/ (1444 Catppuccin Mocha SVG icon overrides) - src/Mod/Create/ (Kindred Create workbench) - src/Gui/ Kindred source files (FileOrigin, OriginManager, OriginSelectorWidget, CommandOrigin, BreadcrumbToolBar, EditingContext) - src/Gui/Icons/ (Kindred branding and silo icons) - src/Gui/PreferencePacks/KindredCreate/ - src/Gui/Stylesheets/ (KindredCreate.qss, images_dark-light/) - package/ (rattler-build recipe) - docs/ (architecture, guides, specifications) - .gitea/ (CI workflows, issue templates) - mods/silo, mods/ztools submodules - .gitmodules (Kindred submodule URLs) - resources/ (kindred-create.desktop, kindred-create.xml) - banner-logo-light.png, CONTRIBUTING.md
This commit is contained in:
614
src/Gui/EditingContext.cpp
Normal file
614
src/Gui/EditingContext.cpp
Normal file
@@ -0,0 +1,614 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2025 Kindred Systems *
|
||||
* *
|
||||
* This file is part of Kindred Create. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "EditingContext.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Base/Type.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Document.h"
|
||||
#include "MDIView.h"
|
||||
#include "ToolBarManager.h"
|
||||
#include "ViewProvider.h"
|
||||
#include "ViewProviderDocumentObject.h"
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
// Catppuccin Mocha palette
|
||||
namespace CatppuccinMocha
|
||||
{
|
||||
constexpr const char* Surface0 = "#313244";
|
||||
constexpr const char* Surface1 = "#45475a";
|
||||
constexpr const char* Mauve = "#cba6f7";
|
||||
constexpr const char* Green = "#a6e3a1";
|
||||
constexpr const char* Blue = "#89b4fa";
|
||||
constexpr const char* Yellow = "#f9e2af";
|
||||
constexpr const char* Teal = "#94e2d5";
|
||||
constexpr const char* Red = "#f38ba8";
|
||||
constexpr const char* Peach = "#fab387";
|
||||
constexpr const char* Text = "#cdd6f4";
|
||||
} // namespace CatppuccinMocha
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Private data
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct EditingContextResolver::Private
|
||||
{
|
||||
QList<ContextDefinition> contexts; // sorted by descending priority
|
||||
QList<OverlayDefinition> overlays;
|
||||
EditingContext current;
|
||||
|
||||
// Additional commands injected into context toolbars
|
||||
// Key: contextId -> toolbarName -> list of command names
|
||||
QMap<QString, QMap<QString, QStringList>> injections;
|
||||
|
||||
void sortContexts()
|
||||
{
|
||||
std::sort(
|
||||
contexts.begin(),
|
||||
contexts.end(),
|
||||
[](const ContextDefinition& a, const ContextDefinition& b) {
|
||||
return a.priority > b.priority;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Singleton
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
EditingContextResolver* EditingContextResolver::_instance = nullptr;
|
||||
|
||||
EditingContextResolver* EditingContextResolver::instance()
|
||||
{
|
||||
if (!_instance) {
|
||||
_instance = new EditingContextResolver();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void EditingContextResolver::destruct()
|
||||
{
|
||||
delete _instance;
|
||||
_instance = nullptr;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Construction
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
EditingContextResolver::EditingContextResolver()
|
||||
: QObject(nullptr)
|
||||
, d(new Private)
|
||||
{
|
||||
registerBuiltinContexts();
|
||||
|
||||
// Connect to application signals
|
||||
auto& app = *Application::Instance;
|
||||
app.signalInEdit.connect([this](const ViewProviderDocumentObject& vp) { onInEdit(vp); });
|
||||
app.signalResetEdit.connect([this](const ViewProviderDocumentObject& vp) { onResetEdit(vp); });
|
||||
app.signalActiveDocument.connect([this](const Document& doc) { onActiveDocument(doc); });
|
||||
app.signalActivateView.connect([this](const MDIView* view) { onActivateView(view); });
|
||||
app.signalActivateWorkbench.connect([this](const char*) { refresh(); });
|
||||
}
|
||||
|
||||
EditingContextResolver::~EditingContextResolver()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper: check if an App::DocumentObject's type name matches (by string)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static bool objectIsDerivedFrom(App::DocumentObject* obj, const char* typeName)
|
||||
{
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
Base::Type target = Base::Type::fromName(typeName);
|
||||
if (target.isBad()) {
|
||||
return false;
|
||||
}
|
||||
return obj->getTypeId().isDerivedFrom(target);
|
||||
}
|
||||
|
||||
static bool vpObjectIsDerivedFrom(ViewProvider* vp, const char* typeName)
|
||||
{
|
||||
auto* vpd = dynamic_cast<ViewProviderDocumentObject*>(vp);
|
||||
if (!vpd) {
|
||||
return false;
|
||||
}
|
||||
return objectIsDerivedFrom(vpd->getObject(), typeName);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper: get the active "part" object from the active view
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static App::DocumentObject* getActivePartObject()
|
||||
{
|
||||
auto* guiDoc = Application::Instance->activeDocument();
|
||||
if (!guiDoc) {
|
||||
return nullptr;
|
||||
}
|
||||
auto* view = guiDoc->getActiveView();
|
||||
if (!view) {
|
||||
return nullptr;
|
||||
}
|
||||
return view->getActiveObject<App::DocumentObject*>("part");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper: get the label of the active "part" object
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static QString getActivePartLabel()
|
||||
{
|
||||
auto* obj = getActivePartObject();
|
||||
if (!obj) {
|
||||
return {};
|
||||
}
|
||||
return QString::fromUtf8(obj->Label.getValue());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper: get label of the object currently in edit
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static QString getInEditLabel()
|
||||
{
|
||||
auto* guiDoc = Application::Instance->activeDocument();
|
||||
if (!guiDoc) {
|
||||
return {};
|
||||
}
|
||||
auto* vp = guiDoc->getInEdit();
|
||||
if (!vp) {
|
||||
return {};
|
||||
}
|
||||
auto* vpd = dynamic_cast<ViewProviderDocumentObject*>(vp);
|
||||
if (!vpd || !vpd->getObject()) {
|
||||
return {};
|
||||
}
|
||||
return QString::fromUtf8(vpd->getObject()->Label.getValue());
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Built-in context registrations
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void EditingContextResolver::registerBuiltinContexts()
|
||||
{
|
||||
// --- Sketcher edit (highest priority — VP in edit) ---
|
||||
registerContext({
|
||||
/*.id =*/QStringLiteral("sketcher.edit"),
|
||||
/*.labelTemplate =*/QStringLiteral("Sketcher: {name}"),
|
||||
/*.color =*/QLatin1String(CatppuccinMocha::Green),
|
||||
/*.toolbars =*/
|
||||
{QStringLiteral("Edit Mode"),
|
||||
QStringLiteral("Geometries"),
|
||||
QStringLiteral("Constraints"),
|
||||
QStringLiteral("Sketcher Tools"),
|
||||
QStringLiteral("B-Spline Tools"),
|
||||
QStringLiteral("Visual Helpers")},
|
||||
/*.priority =*/90,
|
||||
/*.match =*/
|
||||
[]() {
|
||||
auto* doc = Application::Instance->activeDocument();
|
||||
if (!doc) {
|
||||
return false;
|
||||
}
|
||||
auto* vp = doc->getInEdit();
|
||||
return vp && vpObjectIsDerivedFrom(vp, "Sketcher::SketchObject");
|
||||
},
|
||||
});
|
||||
|
||||
// --- Assembly edit (VP in edit) ---
|
||||
registerContext({
|
||||
/*.id =*/QStringLiteral("assembly.edit"),
|
||||
/*.labelTemplate =*/QStringLiteral("Assembly: {name}"),
|
||||
/*.color =*/QLatin1String(CatppuccinMocha::Blue),
|
||||
/*.toolbars =*/
|
||||
{QStringLiteral("Assembly"),
|
||||
QStringLiteral("Assembly Joints"),
|
||||
QStringLiteral("Assembly Management")},
|
||||
/*.priority =*/90,
|
||||
/*.match =*/
|
||||
[]() {
|
||||
auto* doc = Application::Instance->activeDocument();
|
||||
if (!doc) {
|
||||
return false;
|
||||
}
|
||||
auto* vp = doc->getInEdit();
|
||||
return vp && vpObjectIsDerivedFrom(vp, "Assembly::AssemblyObject");
|
||||
},
|
||||
});
|
||||
|
||||
// --- PartDesign with features (active body has children) ---
|
||||
registerContext({
|
||||
/*.id =*/QStringLiteral("partdesign.feature"),
|
||||
/*.labelTemplate =*/QStringLiteral("Body: {name}"),
|
||||
/*.color =*/QLatin1String(CatppuccinMocha::Mauve),
|
||||
/*.toolbars =*/
|
||||
{QStringLiteral("Part Design Helper Features"),
|
||||
QStringLiteral("Part Design Modeling Features"),
|
||||
QStringLiteral("Part Design Dress-Up Features"),
|
||||
QStringLiteral("Part Design Transformation Features")},
|
||||
/*.priority =*/40,
|
||||
/*.match =*/
|
||||
[]() {
|
||||
auto* obj = getActivePartObject();
|
||||
if (!obj || !objectIsDerivedFrom(obj, "PartDesign::Body")) {
|
||||
return false;
|
||||
}
|
||||
// Body has at least one child beyond the origin
|
||||
auto children = obj->getOutList();
|
||||
for (auto* child : children) {
|
||||
if (child && !objectIsDerivedFrom(child, "App::Origin")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
// --- PartDesign body (active body, empty or origin-only) ---
|
||||
registerContext({
|
||||
/*.id =*/QStringLiteral("partdesign.body"),
|
||||
/*.labelTemplate =*/QStringLiteral("Body: {name}"),
|
||||
/*.color =*/QLatin1String(CatppuccinMocha::Mauve),
|
||||
/*.toolbars =*/
|
||||
{QStringLiteral("Part Design Helper Features"), QStringLiteral("Sketcher")},
|
||||
/*.priority =*/30,
|
||||
/*.match =*/
|
||||
[]() {
|
||||
auto* obj = getActivePartObject();
|
||||
return obj && objectIsDerivedFrom(obj, "PartDesign::Body");
|
||||
},
|
||||
});
|
||||
|
||||
// --- Assembly idle (assembly exists, active, but not in edit) ---
|
||||
registerContext({
|
||||
/*.id =*/QStringLiteral("assembly.idle"),
|
||||
/*.labelTemplate =*/QStringLiteral("Assembly: {name}"),
|
||||
/*.color =*/QLatin1String(CatppuccinMocha::Blue),
|
||||
/*.toolbars =*/
|
||||
{QStringLiteral("Assembly")},
|
||||
/*.priority =*/30,
|
||||
/*.match =*/
|
||||
[]() {
|
||||
auto* obj = getActivePartObject();
|
||||
return obj && objectIsDerivedFrom(obj, "Assembly::AssemblyObject");
|
||||
},
|
||||
});
|
||||
|
||||
// --- Spreadsheet ---
|
||||
registerContext({
|
||||
/*.id =*/QStringLiteral("spreadsheet"),
|
||||
/*.labelTemplate =*/QStringLiteral("Spreadsheet: {name}"),
|
||||
/*.color =*/QLatin1String(CatppuccinMocha::Yellow),
|
||||
/*.toolbars =*/
|
||||
{QStringLiteral("Spreadsheet")},
|
||||
/*.priority =*/30,
|
||||
/*.match =*/
|
||||
[]() {
|
||||
auto* obj = getActivePartObject();
|
||||
return obj && objectIsDerivedFrom(obj, "Spreadsheet::Sheet");
|
||||
},
|
||||
});
|
||||
|
||||
// --- Empty document ---
|
||||
registerContext({
|
||||
/*.id =*/QStringLiteral("empty_document"),
|
||||
/*.labelTemplate =*/QStringLiteral("New Document"),
|
||||
/*.color =*/QLatin1String(CatppuccinMocha::Surface1),
|
||||
/*.toolbars =*/
|
||||
{QStringLiteral("Structure")},
|
||||
/*.priority =*/10,
|
||||
/*.match =*/
|
||||
[]() { return Application::Instance->activeDocument() != nullptr; },
|
||||
});
|
||||
|
||||
// --- No document ---
|
||||
registerContext({
|
||||
/*.id =*/QStringLiteral("no_document"),
|
||||
/*.labelTemplate =*/QStringLiteral("Kindred Create"),
|
||||
/*.color =*/QLatin1String(CatppuccinMocha::Surface0),
|
||||
/*.toolbars =*/ {},
|
||||
/*.priority =*/0,
|
||||
/*.match =*/[]() { return true; },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Registration
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void EditingContextResolver::registerContext(const ContextDefinition& def)
|
||||
{
|
||||
// Remove any existing context with the same id
|
||||
unregisterContext(def.id);
|
||||
d->contexts.append(def);
|
||||
d->sortContexts();
|
||||
}
|
||||
|
||||
void EditingContextResolver::unregisterContext(const QString& id)
|
||||
{
|
||||
d->contexts.erase(
|
||||
std::remove_if(
|
||||
d->contexts.begin(),
|
||||
d->contexts.end(),
|
||||
[&](const ContextDefinition& c) { return c.id == id; }
|
||||
),
|
||||
d->contexts.end()
|
||||
);
|
||||
}
|
||||
|
||||
void EditingContextResolver::registerOverlay(const OverlayDefinition& def)
|
||||
{
|
||||
unregisterOverlay(def.id);
|
||||
d->overlays.append(def);
|
||||
}
|
||||
|
||||
void EditingContextResolver::unregisterOverlay(const QString& id)
|
||||
{
|
||||
d->overlays.erase(
|
||||
std::remove_if(
|
||||
d->overlays.begin(),
|
||||
d->overlays.end(),
|
||||
[&](const OverlayDefinition& o) { return o.id == id; }
|
||||
),
|
||||
d->overlays.end()
|
||||
);
|
||||
}
|
||||
|
||||
void EditingContextResolver::injectCommands(
|
||||
const QString& contextId,
|
||||
const QString& toolbarName,
|
||||
const QStringList& commands
|
||||
)
|
||||
{
|
||||
d->injections[contextId][toolbarName].append(commands);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Resolution
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
EditingContext EditingContextResolver::resolve() const
|
||||
{
|
||||
EditingContext ctx;
|
||||
|
||||
// Find the first matching primary context
|
||||
for (const auto& def : d->contexts) {
|
||||
if (def.match && def.match()) {
|
||||
ctx.id = def.id;
|
||||
ctx.color = def.color;
|
||||
ctx.toolbars = def.toolbars;
|
||||
|
||||
// Expand label template
|
||||
QString label = def.labelTemplate;
|
||||
if (label.contains(QStringLiteral("{name}"))) {
|
||||
// For edit-mode contexts, use the in-edit object name
|
||||
QString name = getInEditLabel();
|
||||
if (name.isEmpty()) {
|
||||
name = getActivePartLabel();
|
||||
}
|
||||
if (name.isEmpty()) {
|
||||
name = QStringLiteral("?");
|
||||
}
|
||||
label.replace(QStringLiteral("{name}"), name);
|
||||
}
|
||||
ctx.label = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Append overlay toolbars
|
||||
for (const auto& overlay : d->overlays) {
|
||||
if (overlay.match && overlay.match()) {
|
||||
for (const auto& tb : overlay.toolbars) {
|
||||
if (!ctx.toolbars.contains(tb)) {
|
||||
ctx.toolbars.append(tb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append any injected toolbar names that aren't already in the context
|
||||
auto injIt = d->injections.find(ctx.id);
|
||||
if (injIt != d->injections.end()) {
|
||||
for (auto it = injIt->begin(); it != injIt->end(); ++it) {
|
||||
if (!ctx.toolbars.contains(it.key())) {
|
||||
ctx.toolbars.append(it.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build breadcrumb
|
||||
ctx.breadcrumb = buildBreadcrumb(ctx);
|
||||
ctx.breadcrumbColors = buildBreadcrumbColors(ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
EditingContext EditingContextResolver::currentContext() const
|
||||
{
|
||||
return d->current;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Breadcrumb building
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
QStringList EditingContextResolver::buildBreadcrumb(const EditingContext& ctx) const
|
||||
{
|
||||
QStringList crumbs;
|
||||
|
||||
if (ctx.id == QStringLiteral("no_document") || ctx.id == QStringLiteral("empty_document")) {
|
||||
crumbs << ctx.label;
|
||||
return crumbs;
|
||||
}
|
||||
|
||||
// Always start with the active part/body/assembly label
|
||||
QString partLabel = getActivePartLabel();
|
||||
if (!partLabel.isEmpty()) {
|
||||
crumbs << partLabel;
|
||||
}
|
||||
|
||||
// If in edit mode, add the edited object
|
||||
auto* guiDoc = Application::Instance->activeDocument();
|
||||
if (guiDoc) {
|
||||
auto* vp = guiDoc->getInEdit();
|
||||
if (vp) {
|
||||
auto* vpd = dynamic_cast<ViewProviderDocumentObject*>(vp);
|
||||
if (vpd && vpd->getObject()) {
|
||||
QString editLabel = QString::fromUtf8(vpd->getObject()->Label.getValue());
|
||||
// Don't duplicate if the part label IS the edited object
|
||||
if (editLabel != partLabel) {
|
||||
crumbs << editLabel;
|
||||
}
|
||||
crumbs << QStringLiteral("[editing]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (crumbs.isEmpty()) {
|
||||
crumbs << ctx.label;
|
||||
}
|
||||
|
||||
return crumbs;
|
||||
}
|
||||
|
||||
QStringList EditingContextResolver::buildBreadcrumbColors(const EditingContext& ctx) const
|
||||
{
|
||||
QStringList colors;
|
||||
|
||||
if (ctx.breadcrumb.size() <= 1) {
|
||||
colors << ctx.color;
|
||||
return colors;
|
||||
}
|
||||
|
||||
// For multi-segment breadcrumbs:
|
||||
// - First segments (parent) use the parent context color
|
||||
// - Last segments (active edit) use the current context color
|
||||
// e.g., Body (mauve) > Sketch001 (green) > [editing] (green)
|
||||
|
||||
// Determine parent color
|
||||
QString parentColor = QLatin1String(CatppuccinMocha::Mauve); // default for Body
|
||||
auto* partObj = getActivePartObject();
|
||||
if (partObj) {
|
||||
if (objectIsDerivedFrom(partObj, "Assembly::AssemblyObject")) {
|
||||
parentColor = QLatin1String(CatppuccinMocha::Blue);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ctx.breadcrumb.size(); ++i) {
|
||||
if (i == 0 && ctx.breadcrumb.size() > 1) {
|
||||
colors << parentColor;
|
||||
}
|
||||
else {
|
||||
colors << ctx.color;
|
||||
}
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Apply context → toolbar state changes
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void EditingContextResolver::applyContext(const EditingContext& ctx)
|
||||
{
|
||||
if (ctx.id == d->current.id && ctx.toolbars == d->current.toolbars) {
|
||||
return; // No change
|
||||
}
|
||||
|
||||
auto* tbm = ToolBarManager::getInstance();
|
||||
if (!tbm) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide previously active context toolbars
|
||||
if (!d->current.toolbars.isEmpty()) {
|
||||
tbm->setState(d->current.toolbars, ToolBarManager::State::RestoreDefault);
|
||||
}
|
||||
|
||||
// Show new context toolbars
|
||||
if (!ctx.toolbars.isEmpty()) {
|
||||
tbm->setState(ctx.toolbars, ToolBarManager::State::ForceAvailable);
|
||||
}
|
||||
|
||||
d->current = ctx;
|
||||
Q_EMIT contextChanged(ctx);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Signal handlers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void EditingContextResolver::onInEdit(const ViewProviderDocumentObject& /*vp*/)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void EditingContextResolver::onResetEdit(const ViewProviderDocumentObject& /*vp*/)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void EditingContextResolver::onActiveDocument(const Document& /*doc*/)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void EditingContextResolver::onActivateView(const MDIView* /*view*/)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void EditingContextResolver::refresh()
|
||||
{
|
||||
applyContext(resolve());
|
||||
}
|
||||
|
||||
#include "moc_EditingContext.cpp"
|
||||
Reference in New Issue
Block a user