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 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(); } }
void PropertyBrowser::applyImageLayerValue(PropertyId id, const QVariant &val) { ImageLayer *imageLayer = static_cast<ImageLayer*>(mObject); QUndoStack *undoStack = mMapDocument->undoStack(); switch (id) { case ImageSourceProperty: { const QString imageSource = val.toString(); const QColor &color = imageLayer->transparentColor(); undoStack->push(new ChangeImageLayerProperties(mMapDocument, imageLayer, color, imageSource)); break; } case ColorProperty: { QColor color = val.value<QColor>(); if (color == Qt::gray) color = QColor(); const QString &imageSource = imageLayer->imageSource(); undoStack->push(new ChangeImageLayerProperties(mMapDocument, imageLayer, color, imageSource)); break; } default: break; } }
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 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 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 SCgMainWindow::initializeActions() { QUndoStack* undoStack = mScene->undoStack(); QAction* actionRedo = undoStack->createRedoAction(mScene); actionRedo->setShortcut(QKeySequence::Redo); // actionRedo->setShortcutContext(Qt::WidgetShortcut); QAction* actionUndo = undoStack->createUndoAction(mScene); actionUndo->setShortcut(QKeySequence::Undo); // actionUndo->setShortcutContext(Qt::WidgetShortcut); QAction* actionDelete = new QAction("Delete", mScene); actionDelete->setShortcut(QKeySequence::Delete); connect(actionDelete, SIGNAL(triggered()), mInputHandler, SLOT(deleteSelected())); actionDelete->setShortcutContext(Qt::WidgetShortcut); QAction* actionDeleteJustContour = new QAction("Delete just contour", mScene); actionDeleteJustContour->setShortcut( QKeySequence(tr("Backspace")) ); connect(actionDeleteJustContour, SIGNAL(triggered()), mInputHandler, SLOT(deleteJustContour())); actionDeleteJustContour->setShortcutContext(Qt::WidgetShortcut); mView->addAction(actionDeleteJustContour); mView->addAction(actionDelete); mView->addAction(actionRedo); mView->addAction(actionUndo); }
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 eraseRegionObjectGroup(MapDocument *mapDocument, ObjectGroup *layer, const QRegion &where) { QUndoStack *undo = mapDocument->undoStack(); const auto objects = layer->objects(); for (MapObject *obj : objects) { // TODO: we are checking bounds, which is only correct for rectangles and // tile objects. polygons and polylines are not covered correctly by this // erase method (we are in fact deleting too many objects) // TODO2: toAlignedRect may even break rects. // Convert the boundary of the object into tile space const QRectF objBounds = obj->boundsUseTile(); QPointF tl = mapDocument->renderer()->pixelToTileCoords(objBounds.topLeft()); QPointF tr = mapDocument->renderer()->pixelToTileCoords(objBounds.topRight()); QPointF br = mapDocument->renderer()->pixelToTileCoords(objBounds.bottomRight()); QPointF bl = mapDocument->renderer()->pixelToTileCoords(objBounds.bottomLeft()); QRectF objInTileSpace; objInTileSpace.setTopLeft(tl); objInTileSpace.setTopRight(tr); objInTileSpace.setBottomRight(br); objInTileSpace.setBottomLeft(bl); const QRect objAlignedRect = objInTileSpace.toAlignedRect(); if (where.intersects(objAlignedRect)) undo->push(new RemoveMapObject(mapDocument, obj)); } }
void TilesetDock::embedTileset() { Tileset *tileset = currentTileset(); if (!tileset) return; if (!tileset->isExternal()) return; // To embed a tileset we clone it, since further changes to that tileset // should not affect the exteral tileset. SharedTileset embeddedTileset = tileset->clone(); QUndoStack *undoStack = mMapDocument->undoStack(); int mapTilesetIndex = mMapDocument->map()->tilesets().indexOf(tileset->sharedPointer()); // Tileset may not be part of the map yet if (mapTilesetIndex == -1) undoStack->push(new AddTileset(mMapDocument, embeddedTileset)); else undoStack->push(new ReplaceTileset(mMapDocument, mapTilesetIndex, embeddedTileset)); // Make sure the embedded tileset is selected int embeddedTilesetIndex = mTilesets.indexOf(embeddedTileset); if (embeddedTilesetIndex != -1) mTabBar->setCurrentIndex(embeddedTilesetIndex); }
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 TilesetDock::swapTiles(Tile *tileA, Tile *tileB) { if (!mMapDocument) return; QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->push(new SwapTiles(mMapDocument, tileA, tileB)); }
void ReactionArrowTool::mousePressEvent(QGraphicsSceneMouseEvent *event) { QPointF downPos = event->buttonDownScenePos(event->button()); QUndoStack *stack = scene()->stack(); ReactionArrow *arrow = new ReactionArrow; stack->push(new AddItem(arrow, scene())); arrow->setPos(downPos); }
void RedoOperation::initialize(IServiceLocator *serviceLocator) { QUndoStackAdapter* adapter = serviceLocator->locate<QUndoStackAdapter>(); QUndoStack *stack = adapter->wrappedStack(); m_action = stack->createRedoAction(this); setEnabled(m_action->isEnabled()); connect(m_action, &QAction::changed, this, &RedoOperation::onActionChanged); }
/** * 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); }
bool BookmarksModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if (action == Qt::IgnoreAction) return true; if (column > 0) return false; BookmarkNode *parentNode = node(parent); if (!data->hasFormat(MIMETYPE)) { if (!data->hasUrls()) return false; BookmarkNode *node = new BookmarkNode(BookmarkNode::Bookmark, parentNode); node->url = QString::fromUtf8(data->urls().at(0).toEncoded()); if (data->hasText()) node->title = data->text(); else node->title = node->url; m_bookmarksManager->addBookmark(parentNode, node, row); return true; } QByteArray ba = data->data(MIMETYPE); QDataStream stream(&ba, QIODevice::ReadOnly); if (stream.atEnd()) return false; QUndoStack *undoStack = m_bookmarksManager->undoRedoStack(); undoStack->beginMacro(QLatin1String("Move Bookmarks")); while (!stream.atEnd()) { QByteArray encodedData; stream >> encodedData; QBuffer buffer(&encodedData); buffer.open(QBuffer::ReadOnly); XbelReader reader; BookmarkNode *rootNode = reader.read(&buffer); QList<BookmarkNode*> children = rootNode->children(); for (int i = 0; i < children.count(); ++i) { BookmarkNode *bookmarkNode = children.at(i); rootNode->remove(bookmarkNode); row = qMax(0, row); m_bookmarksManager->addBookmark(parentNode, bookmarkNode, row); m_endMacro = true; } delete rootNode; } return true; }
void tst_QUndoGroup::addStackAndDie() { // Test that QUndoStack doesn't keep a reference to QUndoGroup after the // group is deleted. QUndoStack *stack = new QUndoStack; QUndoGroup *group = new QUndoGroup; group->addStack(stack); delete group; stack->setActive(true); delete stack; }
void AbstractAspect::exec(QUndoCommand *cmd) { Q_CHECK_PTR(cmd); QUndoStack *stack = undoStack(); if (stack) stack->push(cmd); else { cmd->redo(); delete cmd; } }
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 PropertyBrowser::applyTerrainValue(PropertyId id, const QVariant &val) { Terrain *terrain = static_cast<Terrain*>(mObject); if (id == NameProperty) { QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->push(new RenameTerrain(mMapDocument, terrain->tileset(), terrain->id(), val.toString())); } }
void PropertiesDock::removeProperty() { QtBrowserItem *item = mPropertyBrowser->currentItem(); Object *object = mMapDocument->currentObject(); if (!item || !object) return; const QString name = item->property()->propertyName(); QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->push(new RemoveProperty(mMapDocument, mMapDocument->currentObjects(), name)); // TODO: Would be nice to automatically select the next property }
void TileCollisionDock::applyChanges() { if (mSynchronizing) return; ObjectGroup *objectGroup = static_cast<ObjectGroup*>(mDummyMapDocument->map()->layerAt(1)); ObjectGroup *clonedGroup = objectGroup->clone(); QUndoStack *undoStack = mTilesetDocument->undoStack(); mApplyingChanges = true; undoStack->push(new ChangeTileObjectGroup(mTilesetDocument, mTile, clonedGroup)); mApplyingChanges = false; }
void TilesetDock::changeSelectedMapObjectsTile(Tile *tile) { if (!mMapDocument) return; // Only change tiles of tile objects QList<MapObject*> tileObjects = chooseTileObjects(mMapDocument->selectedObjects()); if (tileObjects.isEmpty()) return; QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->push(new ChangeMapObjectsTile(mMapDocument, tileObjects, tile)); }
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 CollectionListView::deleteCollection() { int collectionId = MetadataEngine::getInstance().getCurrentCollectionId(); if ((collectionId == 0) || SyncSession::IS_READ_ONLY) return; //0 stands for invalid //ask for confirmation QMessageBox box(QMessageBox::Question, tr("Delete Collection"), tr("Are you sure you want to delete the selected collection?" "<br><br><b>Warning:</b> This cannot be undone!"), QMessageBox::Yes | QMessageBox::No, this); box.setDefaultButton(QMessageBox::Yes); box.setWindowModality(Qt::WindowModal); int r = box.exec(); if (r == QMessageBox::No) return; //check all fields for delete triggers CollectionFieldCleaner cleaner(this); cleaner.cleanCollection(collectionId); //delete metadata and tables MetadataEngine::getInstance().deleteCollection(collectionId); //delete from model m_model->removeRow(currentIndex().row()); //delete settings about collection's column positions in TableView SettingsManager s; QString settingsKey = QString("collection_") + QString::number(collectionId); s.deleteObjectProperties(settingsKey); //reset cached id m_currentCollectionId = 0; //clear undo stack since this action is not undoable QUndoStack *stack = MainWindow::getUndoStack(); if (stack) stack->clear(); //set first collection as current one QModelIndex first = m_model->index(0, 1); if (first.isValid()) setCurrentIndex(first); else MetadataEngine::getInstance().setCurrentCollectionId(0); //set invalid //set local data changed SyncSession::LOCAL_DATA_CHANGED = true; }
void PropertiesDock::addProperty(const QString &name) { if (name.isEmpty()) return; Object *object = mMapDocument->currentObject(); if (!object) return; if (!object->hasProperty(name)) { QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->push(new SetProperty(mMapDocument, mMapDocument->currentObjects(), name, QString())); } mPropertyBrowser->editCustomProperty(name); }
void ObjectSelectionTool::keyPressed(QKeyEvent *event) { if (mAction != NoAction) { event->ignore(); return; } QPointF moveBy; switch (event->key()) { case Qt::Key_Up: moveBy = QPointF(0, -1); break; case Qt::Key_Down: moveBy = QPointF(0, 1); break; case Qt::Key_Left: moveBy = QPointF(-1, 0); break; case Qt::Key_Right: moveBy = QPointF(1, 0); break; default: AbstractObjectTool::keyPressed(event); return; } const QSet<MapObjectItem*> &items = mapScene()->selectedObjectItems(); const Qt::KeyboardModifiers modifiers = event->modifiers(); if (moveBy.isNull() || items.isEmpty() || (modifiers & Qt::ControlModifier)) { event->ignore(); return; } const bool moveFast = modifiers & Qt::ShiftModifier; const bool snapToFineGrid = Preferences::instance()->snapToFineGrid(); if (moveFast) { // TODO: This only makes sense for orthogonal maps moveBy.rx() *= mapDocument()->map()->tileWidth(); moveBy.ry() *= mapDocument()->map()->tileHeight(); if (snapToFineGrid) moveBy /= Preferences::instance()->gridFine(); } QUndoStack *undoStack = mapDocument()->undoStack(); undoStack->beginMacro(tr("Move %n Object(s)", "", items.size())); int i = 0; foreach (MapObjectItem *objectItem, items) { MapObject *object = objectItem->mapObject(); const QPointF oldPos = object->position(); const QPointF newPos = oldPos + moveBy; undoStack->push(new MoveMapObject(mapDocument(), object, newPos, oldPos)); ++i; }
void PropertiesDock::renameProperty(const QString &name) { if (name.isEmpty()) return; QtBrowserItem *item = mPropertyBrowser->currentItem(); if (!item) return; const QString oldName = item->property()->propertyName(); if (oldName == name) return; QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->push(new RenameProperty(mMapDocument, mMapDocument->currentObjects(), oldName, name)); }