void LayerModel::toggleOtherLayers(int layerIndex) { if (mMap->layerCount() <= 1) // No other layers return; bool visibility = true; for (int i = 0; i < mMap->layerCount(); i++) { if (i == layerIndex) continue; Layer *layer = mMap->layerAt(i); if (layer->isVisible()) { visibility = false; break; } } QUndoStack *undoStack = mMapDocument->undoStack(); if (visibility) undoStack->beginMacro(tr("Show Other Layers")); else undoStack->beginMacro(tr("Hide Other Layers")); for (int i = 0; i < mMap->layerCount(); i++) { if (i == layerIndex) continue; if (visibility != mMap->layerAt(i)->isVisible()) undoStack->push(new SetLayerVisible(mMapDocument, i, visibility)); } undoStack->endMacro(); }
void ButtonTaskMenu::addToGroup(QAction *a) { QButtonGroup *bg = qvariant_cast<QButtonGroup *>(a->data()); Q_ASSERT(bg); QDesignerFormWindowInterface *fw = formWindow(); const ButtonList bl = buttonList(fw->cursor()); // Do we need to remove the buttons from an existing group? QUndoCommand *removeCmd = 0; if (bl.front()->group()) { removeCmd = createRemoveButtonsCommand(fw, bl); if (!removeCmd) return; } AddButtonsToGroupCommand *addCmd = new AddButtonsToGroupCommand(fw); addCmd->init(bl, bg); QUndoStack *history = fw->commandHistory(); if (removeCmd) { history->beginMacro(addCmd->text()); history->push(removeCmd); history->push(addCmd); history->endMacro(); } else { history->push(addCmd); } }
void MapDocumentActionHandler::delete_() { if (!mMapDocument) return; Layer *currentLayer = mMapDocument->currentLayer(); if (!currentLayer) return; TileLayer *tileLayer = dynamic_cast<TileLayer*>(currentLayer); const QRegion &selectedArea = mMapDocument->selectedArea(); const QList<MapObject*> &selectedObjects = mMapDocument->selectedObjects(); QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->beginMacro(tr("Delete")); if (tileLayer && !selectedArea.isEmpty()) { undoStack->push(new EraseTiles(mMapDocument, tileLayer, selectedArea)); } else if (!selectedObjects.isEmpty()) { foreach (MapObject *mapObject, selectedObjects) undoStack->push(new RemoveMapObject(mMapDocument, mapObject)); } selectNone(); undoStack->endMacro(); }
void PropertiesDock::removeProperties() { Object *object = mDocument->currentObject(); if (!object) return; const QList<QtBrowserItem*> items = mPropertyBrowser->selectedItems(); if (items.isEmpty() || !mPropertyBrowser->allCustomPropertyItems(items)) return; QStringList propertyNames; for (QtBrowserItem *item : items) propertyNames.append(item->property()->propertyName()); QUndoStack *undoStack = mDocument->undoStack(); undoStack->beginMacro(tr("Remove Property/Properties", nullptr, propertyNames.size())); for (const QString &name : propertyNames) { undoStack->push(new RemoveProperty(mDocument, mDocument->currentObjects(), name)); } undoStack->endMacro(); }
void MapPropertiesDialog::accept() { int format = mLayerDataCombo->currentIndex(); if (format == -1) { // this shouldn't happen! format = 0; } Map::LayerDataFormat newLayerDataFormat = static_cast<Map::LayerDataFormat>(format - 1); QUndoStack *undoStack = mMapDocument->undoStack(); QColor newColor = mColorButton->color(); if (newColor == Qt::darkGray) newColor = QColor(); const Map *map = mMapDocument->map(); bool localChanges = newColor != map->backgroundColor() || newLayerDataFormat != map->layerDataFormat(); if (localChanges) { undoStack->beginMacro(QCoreApplication::translate( "Undo Commands", "Change Map Properties")); undoStack->push(new ChangeMapProperties(mMapDocument, newColor, newLayerDataFormat)); } PropertiesDialog::accept(); if (localChanges) undoStack->endMacro(); }
void AddShape::performAction(Block* block) const { Node* node = static_cast<Node*>(block); GenerateShape dialog(_generator, PantinEngine::MainWindow()); if(dialog.createShape()) { K_ASSERT( node->instance()->fastInherits<Model>() ); // The instance HAS to be a model in Nigel. Only models can contain geometry. Model* model = static_cast<Model*>(node->instance()); QUndoStack* undoStack = PantinEngine::InstanceUndoStack( model ); undoStack->setActive(true); undoStack->beginMacro( tr("Adding new %1 to node %2") .arg(_generator->shape()->blockName(), node->blockName()) ); AddBlock* addGeometry = new AddBlock(model->geometries(), dialog.geometry()); undoStack->push(addGeometry); AddBlock* addReference = new AddBlock(node, dialog.geometryInstance()); undoStack->push(addReference); undoStack->endMacro(); } }
void EditPolygonTool::splitSegments() { if (mSelectedHandles.size() < 2) return; const PointIndexesByObject p = groupIndexesByObject(mSelectedHandles); QMapIterator<MapObject*, RangeSet<int> > i(p); QUndoStack *undoStack = mapDocument()->undoStack(); bool macroStarted = false; while (i.hasNext()) { MapObject *object = i.next().key(); const RangeSet<int> &indexRanges = i.value(); const bool closed = object->shape() == MapObject::Polygon; QPolygonF oldPolygon = object->polygon(); QPolygonF newPolygon = splitPolygonSegments(oldPolygon, indexRanges, closed); if (newPolygon.size() > oldPolygon.size()) { if (!macroStarted) { undoStack->beginMacro(tr("Split Segments")); macroStarted = true; } undoStack->push(new ChangePolygon(mapDocument(), object, newPolygon, oldPolygon)); } } if (macroStarted) undoStack->endMacro(); }
void ButtonTaskMenu::createGroup() { QDesignerFormWindowInterface *fw = formWindow(); const ButtonList bl = buttonList(fw->cursor()); // Do we need to remove the buttons from an existing group? QUndoCommand *removeCmd = 0; if (bl.front()->group()) { removeCmd = createRemoveButtonsCommand(fw, bl); if (!removeCmd) return; } // Add cmd CreateButtonGroupCommand *addCmd = new CreateButtonGroupCommand(fw); if (!addCmd->init(bl)) { qWarning("** WARNING Failed to initialize CreateButtonGroupCommand!"); delete addCmd; return; } // Need a macro [even if we only have the add command] since the command might trigger additional commands QUndoStack *history = fw->commandHistory(); history->beginMacro(addCmd->text()); if (removeCmd) history->push(removeCmd); history->push(addCmd); history->endMacro(); }
void ImageLayerPropertiesDialog::accept() { QUndoStack *undoStack = mMapDocument->undoStack(); const QColor newColor = mColorButton->color() != Qt::gray ? mColorButton->color() : QColor(); const QString newPath = mImage->text(); const bool localChanges = newColor != mImageLayer->transparentColor() || newPath != mImageLayer->imageSource(); if (localChanges) { undoStack->beginMacro(QCoreApplication::translate( "Undo Commands", "Change Image Layer Properties")); undoStack->push(new ChangeImageLayerProperties( mMapDocument, mImageLayer, newColor, newPath)); } PropertiesDialog::accept(); if (localChanges) undoStack->endMacro(); }
void PropertiesDock::pasteProperties() { auto clipboardManager = ClipboardManager::instance(); Properties pastedProperties = clipboardManager->properties(); if (pastedProperties.isEmpty()) return; const QList<Object *> objects = mDocument->currentObjects(); if (objects.isEmpty()) return; QList<QUndoCommand*> commands; for (Object *object : objects) { Properties properties = object->properties(); properties.merge(pastedProperties); if (object->properties() != properties) { commands.append(new ChangeProperties(mDocument, QString(), object, properties)); } } if (!commands.isEmpty()) { QUndoStack *undoStack = mDocument->undoStack(); undoStack->beginMacro(tr("Paste Property/Properties", nullptr, pastedProperties.size())); for (QUndoCommand *command : commands) undoStack->push(command); undoStack->endMacro(); } }
/** * Convenience method that deals with some of the logic related to pasting * a group of objects. */ void ClipboardManager::pasteObjectGroup(const ObjectGroup *objectGroup, MapDocument *mapDocument, const MapView *view, PasteFlags flags) { Layer *currentLayer = mapDocument->currentLayer(); if (!currentLayer) return; ObjectGroup *currentObjectGroup = currentLayer->asObjectGroup(); if (!currentObjectGroup) return; QPointF insertPos; if (!(flags & PasteInPlace)) { // Determine where to insert the objects const MapRenderer *renderer = mapDocument->renderer(); const QPointF center = objectGroup->objectsBoundingRect().center(); // Take the mouse position if the mouse is on the view, otherwise // take the center of the view. QPoint viewPos; if (view->underMouse()) viewPos = view->mapFromGlobal(QCursor::pos()); else viewPos = QPoint(view->width() / 2, view->height() / 2); const QPointF scenePos = view->mapToScene(viewPos); insertPos = renderer->screenToPixelCoords(scenePos) - center; SnapHelper(renderer).snap(insertPos); } QUndoStack *undoStack = mapDocument->undoStack(); QList<MapObject*> pastedObjects; pastedObjects.reserve(objectGroup->objectCount()); undoStack->beginMacro(tr("Paste Objects")); for (const MapObject *mapObject : objectGroup->objects()) { if (flags & PasteNoTileObjects && !mapObject->cell().isEmpty()) continue; MapObject *objectClone = mapObject->clone(); objectClone->resetId(); objectClone->setPosition(objectClone->position() + insertPos); pastedObjects.append(objectClone); undoStack->push(new AddMapObject(mapDocument, currentObjectGroup, objectClone)); } undoStack->endMacro(); mapDocument->setSelectedObjects(pastedObjects); }
void TilesetDock::removeTiles() { TilesetView *view = currentTilesetView(); if (!view) return; if (!view->selectionModel()->hasSelection()) return; const QModelIndexList indexes = view->selectionModel()->selectedIndexes(); const TilesetModel *model = view->tilesetModel(); QList<Tile*> tiles; for (const QModelIndex &index : indexes) if (Tile *tile = model->tileAt(index)) tiles.append(tile); auto matchesAnyTile = [&tiles] (const Cell &cell) { if (Tile *tile = cell.tile) return tiles.contains(tile); return false; }; const bool inUse = hasTileReferences(mMapDocument, matchesAnyTile); // If the tileset is in use, warn the user and confirm removal if (inUse) { QMessageBox warning(QMessageBox::Warning, tr("Remove Tiles"), tr("One or more of the tiles to be removed are " "still in use by the map!"), QMessageBox::Yes | QMessageBox::No, this); warning.setDefaultButton(QMessageBox::Yes); warning.setInformativeText(tr("Remove all references to these tiles?")); if (warning.exec() != QMessageBox::Yes) return; } QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->beginMacro(tr("Remove Tiles")); if (inUse) removeTileReferences(mMapDocument, matchesAnyTile); Tileset *tileset = view->tilesetModel()->tileset(); undoStack->push(new RemoveTiles(mMapDocument, tileset, tiles)); undoStack->endMacro(); // Clear the current tiles, will be referencing the removed tiles setCurrentTiles(nullptr); setCurrentTile(nullptr); }
void RaiseLowerHelper::push(const QList<QUndoCommand*> &commands, const QString &text) { if (commands.isEmpty()) return; QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->beginMacro(text); foreach (QUndoCommand *command, commands) undoStack->push(command); undoStack->endMacro(); }
void ButtonGroupMenu::breakGroup() { BreakButtonGroupCommand *cmd = new BreakButtonGroupCommand(m_formWindow); if (cmd->init(m_buttonGroup)) { // Need a macro since the command might trigger additional commands QUndoStack *history = m_formWindow->commandHistory(); history->beginMacro(cmd->text()); history->push(cmd); history->endMacro(); } else { qWarning("** WARNING Failed to initialize BreakButtonGroupCommand!"); delete cmd; } }
void TileCollisionDock::delete_(Operation operation) { if (!mDummyMapDocument) return; const QList<MapObject*> selectedObjects = mDummyMapDocument->selectedObjects(); if (selectedObjects.isEmpty()) return; QUndoStack *undoStack = mDummyMapDocument->undoStack(); undoStack->beginMacro(operation == Delete ? tr("Delete") : tr("Cut")); for (MapObject *mapObject : selectedObjects) undoStack->push(new RemoveMapObject(mDummyMapDocument, mapObject)); undoStack->endMacro(); }
/** * Removes the tileset at the given index. Prompting the user when the tileset * is in use by the map. */ void TilesetDock::removeTileset(int index) { auto &sharedTileset = mTilesets.at(index); int mapTilesetIndex = mMapDocument->map()->tilesets().indexOf(sharedTileset); if (mapTilesetIndex == -1) return; Tileset *tileset = sharedTileset.data(); const bool inUse = mMapDocument->map()->isTilesetUsed(tileset); // If the tileset is in use, warn the user and confirm removal if (inUse) { QMessageBox warning(QMessageBox::Warning, tr("Remove Tileset"), tr("The tileset \"%1\" is still in use by the " "map!").arg(tileset->name()), QMessageBox::Yes | QMessageBox::No, this); warning.setDefaultButton(QMessageBox::Yes); warning.setInformativeText(tr("Remove this tileset and all references " "to the tiles in this tileset?")); if (warning.exec() != QMessageBox::Yes) return; } QUndoCommand *remove = new RemoveTileset(mMapDocument, mapTilesetIndex); QUndoStack *undoStack = mMapDocument->undoStack(); if (inUse) { // Remove references to tiles in this tileset from the current map auto referencesTileset = [tileset] (const Cell &cell) { return cell.tileset() == tileset; }; undoStack->beginMacro(remove->text()); removeTileReferences(mMapDocument, referencesTileset); } undoStack->push(remove); if (inUse) undoStack->endMacro(); }
void TilesetEditor::removeTerrainType() { Terrain *terrain = mTerrainDock->currentTerrain(); if (!terrain) return; RemoveTerrain *removeTerrain = new RemoveTerrain(mCurrentTilesetDocument, terrain); /* * Clear any references to the terrain that is about to be removed with * an undo command, as a way of preserving them when undoing the removal * of the terrain. */ ChangeTileTerrain::Changes changes; for (Tile *tile : terrain->tileset()->tiles()) { unsigned tileTerrain = tile->terrain(); for (int corner = 0; corner < 4; ++corner) { if (tile->cornerTerrainId(corner) == terrain->id()) tileTerrain = setTerrainCorner(tileTerrain, corner, 0xFF); } if (tileTerrain != tile->terrain()) { changes.insert(tile, ChangeTileTerrain::Change(tile->terrain(), tileTerrain)); } } QUndoStack *undoStack = mCurrentTilesetDocument->undoStack(); if (!changes.isEmpty()) { undoStack->beginMacro(removeTerrain->text()); undoStack->push(new ChangeTileTerrain(mCurrentTilesetDocument, changes)); } mCurrentTilesetDocument->undoStack()->push(removeTerrain); if (!changes.isEmpty()) undoStack->endMacro(); }
void EditPolygonTool::deleteNodes() { if (mSelectedHandles.isEmpty()) return; PointIndexesByObject p = groupIndexesByObject(mSelectedHandles); QMapIterator<MapObject*, RangeSet<int> > i(p); QUndoStack *undoStack = mapDocument()->undoStack(); QString delText = tr("Delete %n Node(s)", "", mSelectedHandles.size()); undoStack->beginMacro(delText); while (i.hasNext()) { MapObject *object = i.next().key(); const RangeSet<int> &indexRanges = i.value(); QPolygonF oldPolygon = object->polygon(); QPolygonF newPolygon = oldPolygon; // Remove points, back to front to keep the indexes valid RangeSet<int>::Range it = indexRanges.end(); RangeSet<int>::Range begin = indexRanges.begin(); // assert: end != begin, since there is at least one entry do { --it; newPolygon.remove(it.first(), it.length()); } while (it != begin); if (newPolygon.size() < 2) { // We've removed the entire object undoStack->push(new RemoveMapObject(mapDocument(), object)); } else { undoStack->push(new ChangePolygon(mapDocument(), object, newPolygon, oldPolygon)); } } undoStack->endMacro(); }
void MapPropertiesDialog::accept() { QUndoStack *undoStack = mMapDocument->undoStack(); const QColor newColor = mColorButton->color() != Qt::gray ? mColorButton->color() : QColor(); const bool localChanges = newColor != mMapDocument->map()->backgroundColor(); if (localChanges) { undoStack->beginMacro(QCoreApplication::translate( "Undo Commands", "Change Map Properties")); undoStack->push(new ChangeMapProperties(mMapDocument, mColorButton->color())); } PropertiesDialog::accept(); if (localChanges) undoStack->endMacro(); }
void ObjectPropertiesDialog::accept() { const QString newName = mUi->name->text(); const QString newType = mUi->type->text(); const qreal newPosX = mUi->x->value(); const qreal newPosY = mUi->y->value(); const qreal newWidth = mUi->width->value(); const qreal newHeight = mUi->height->value(); bool changed = false; changed |= mMapObject->name() != newName; changed |= mMapObject->type() != newType; changed |= mMapObject->x() != newPosX; changed |= mMapObject->y() != newPosY; changed |= mMapObject->width() != newWidth; changed |= mMapObject->height() != newHeight; if (changed) { QUndoStack *undo = mMapDocument->undoStack(); undo->beginMacro(tr("Change Object")); undo->push(new ChangeMapObject(mMapDocument, mMapObject, newName, newType)); const QPointF oldPos = mMapObject->position(); mMapObject->setX(newPosX); mMapObject->setY(newPosY); undo->push(new MoveMapObject(mMapDocument, mMapObject, oldPos)); const QSizeF oldSize = mMapObject->size(); mMapObject->setWidth(newWidth); mMapObject->setHeight(newHeight); undo->push(new ResizeMapObject(mMapDocument, mMapObject, oldSize)); PropertiesDialog::accept(); // Let PropertiesDialog add its command undo->endMacro(); } else { PropertiesDialog::accept(); } }
static void removeTileReferences(MapDocument *mapDocument, std::function<bool(const Cell &)> condition) { QUndoStack *undoStack = mapDocument->undoStack(); undoStack->beginMacro(QCoreApplication::translate("Undo Commands", "Remove Tiles")); for (Layer *layer : mapDocument->map()->layers()) { if (TileLayer *tileLayer = layer->asTileLayer()) { const QRegion refs = tileLayer->region(condition); if (!refs.isEmpty()) undoStack->push(new EraseTiles(mapDocument, tileLayer, refs)); } else if (ObjectGroup *objectGroup = layer->asObjectGroup()) { for (MapObject *object : *objectGroup) { if (condition(object->cell())) undoStack->push(new RemoveMapObject(mapDocument, object)); } } } undoStack->endMacro(); }
void AbstractObjectTool::resetTileSize() { QList<QUndoCommand*> commands; for (auto mapObject : mapDocument()->selectedObjects()) { if (!isResizedTileObject(mapObject)) continue; commands << new ResizeMapObject(mapDocument(), mapObject, mapObject->cell().tile()->size(), mapObject->size()); } if (!commands.isEmpty()) { QUndoStack *undoStack = mapDocument()->undoStack(); undoStack->beginMacro(tr("Reset Tile Size")); for (auto command : commands) undoStack->push(command); undoStack->endMacro(); } }
void EditPolygonTool::finishMoving(const QPointF &pos) { Q_ASSERT(mMode == Moving); mMode = NoMode; if (mStart == pos || mOldPolygons.isEmpty()) // Move is a no-op return; QUndoStack *undoStack = mapDocument()->undoStack(); undoStack->beginMacro(tr("Move %n Point(s)", "", mSelectedHandles.size())); // TODO: This isn't really optimal. Would be better to have a single undo // command that supports changing multiple map objects. QMapIterator<MapObject*, QPolygonF> i(mOldPolygons); while (i.hasNext()) { i.next(); undoStack->push(new ChangePolygon(mapDocument(), i.key(), i.value())); } undoStack->endMacro(); mOldHandlePositions.clear(); mOldPolygons.clear(); }
void PropertiesDock::showContextMenu(const QPoint& pos) { const Object *object = mDocument->currentObject(); if (!object) return; const QList<QtBrowserItem *> items = mPropertyBrowser->selectedItems(); const bool customPropertiesSelected = !items.isEmpty() && mPropertyBrowser->allCustomPropertyItems(items); bool currentObjectHasAllProperties = true; QStringList propertyNames; for (QtBrowserItem *item : items) { const QString propertyName = item->property()->propertyName(); propertyNames.append(propertyName); if (!object->hasProperty(propertyName)) currentObjectHasAllProperties = false; } QMenu contextMenu(mPropertyBrowser); QAction *cutAction = contextMenu.addAction(tr("Cu&t")); QAction *copyAction = contextMenu.addAction(tr("&Copy")); QAction *pasteAction = contextMenu.addAction(tr("&Paste")); contextMenu.addSeparator(); QMenu *convertMenu = contextMenu.addMenu(tr("Convert To")); QAction *renameAction = contextMenu.addAction(tr("Rename...")); QAction *removeAction = contextMenu.addAction(tr("Remove")); cutAction->setShortcuts(QKeySequence::Cut); cutAction->setIcon(QIcon(QLatin1String(":/images/16x16/edit-cut.png"))); cutAction->setEnabled(customPropertiesSelected && currentObjectHasAllProperties); copyAction->setShortcuts(QKeySequence::Copy); copyAction->setIcon(QIcon(QLatin1String(":/images/16x16/edit-copy.png"))); copyAction->setEnabled(customPropertiesSelected && currentObjectHasAllProperties); pasteAction->setShortcuts(QKeySequence::Paste); pasteAction->setIcon(QIcon(QLatin1String(":/images/16x16/edit-paste.png"))); pasteAction->setEnabled(ClipboardManager::instance()->hasProperties()); renameAction->setEnabled(mActionRenameProperty->isEnabled()); renameAction->setIcon(mActionRenameProperty->icon()); removeAction->setEnabled(mActionRemoveProperty->isEnabled()); removeAction->setShortcuts(mActionRemoveProperty->shortcuts()); removeAction->setIcon(mActionRemoveProperty->icon()); Utils::setThemeIcon(cutAction, "edit-cut"); Utils::setThemeIcon(copyAction, "edit-copy"); Utils::setThemeIcon(pasteAction, "edit-paste"); Utils::setThemeIcon(removeAction, "remove"); if (customPropertiesSelected) { const int convertTo[] = { QVariant::Bool, QVariant::Color, QVariant::Double, filePathTypeId(), QVariant::Int, QVariant::String }; for (int toType : convertTo) { bool someDifferentType = false; bool allCanConvert = true; for (const QString &propertyName : propertyNames) { QVariant propertyValue = object->property(propertyName); if (propertyValue.userType() != toType) someDifferentType = true; if (!propertyValue.convert(toType)) { allCanConvert = false; break; } } if (someDifferentType && allCanConvert) { QAction *action = convertMenu->addAction(typeToName(toType)); action->setData(toType); } } } convertMenu->setEnabled(!convertMenu->actions().isEmpty()); connect(cutAction, &QAction::triggered, this, &PropertiesDock::cutProperties); connect(copyAction, &QAction::triggered, this, &PropertiesDock::copyProperties); connect(pasteAction, &QAction::triggered, this, &PropertiesDock::pasteProperties); connect(renameAction, &QAction::triggered, this, &PropertiesDock::renameProperty); connect(removeAction, &QAction::triggered, this, &PropertiesDock::removeProperties); const QPoint globalPos = mPropertyBrowser->mapToGlobal(pos); const QAction *selectedItem = contextMenu.exec(globalPos); if (selectedItem && selectedItem->parentWidget() == convertMenu) { QUndoStack *undoStack = mDocument->undoStack(); undoStack->beginMacro(tr("Convert Property/Properties", nullptr, items.size())); for (const QString &propertyName : propertyNames) { QVariant propertyValue = object->property(propertyName); int toType = selectedItem->data().toInt(); propertyValue.convert(toType); undoStack->push(new SetProperty(mDocument, mDocument->currentObjects(), propertyName, propertyValue)); } undoStack->endMacro(); } }
void AbstractAspect::endMacro() { QUndoStack *stack = undoStack(); if (stack) stack->endMacro(); }