001/* 002 * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games. 003 * Copyright (C) 2000-2011 The Gridarta Developers. 004 * 005 * This program is free software; you can redistribute it and/or modify 006 * it under the terms of the GNU General Public License as published by 007 * the Free Software Foundation; either version 2 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License along 016 * with this program; if not, write to the Free Software Foundation, Inc., 017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 018 */ 019 020package net.sf.gridarta.gui.dialog.replace; 021 022import java.awt.Component; 023import java.awt.Container; 024import java.awt.FlowLayout; 025import java.awt.event.ItemEvent; 026import java.awt.event.ItemListener; 027import java.util.ArrayList; 028import java.util.Collection; 029import java.util.Iterator; 030import java.util.List; 031import javax.swing.BorderFactory; 032import javax.swing.Box; 033import javax.swing.BoxLayout; 034import javax.swing.Icon; 035import javax.swing.JButton; 036import javax.swing.JComboBox; 037import javax.swing.JComponent; 038import javax.swing.JDialog; 039import javax.swing.JLabel; 040import javax.swing.JOptionPane; 041import javax.swing.JPanel; 042import javax.swing.JTextField; 043import javax.swing.WindowConstants; 044import javax.swing.text.JTextComponent; 045import net.sf.gridarta.gui.copybuffer.CopyBuffer; 046import net.sf.gridarta.gui.map.mapview.MapView; 047import net.sf.gridarta.gui.panel.objectchooser.ObjectChooser; 048import net.sf.gridarta.gui.panel.objectchooser.ObjectChooserListener; 049import net.sf.gridarta.model.archetype.Archetype; 050import net.sf.gridarta.model.baseobject.BaseObject; 051import net.sf.gridarta.model.face.FaceObjectProviders; 052import net.sf.gridarta.model.face.FaceObjectProvidersListener; 053import net.sf.gridarta.model.gameobject.GameObject; 054import net.sf.gridarta.model.maparchobject.MapArchObject; 055import net.sf.gridarta.model.mapcontrol.MapControl; 056import net.sf.gridarta.model.mapmodel.InsertionModeSet; 057import net.sf.gridarta.model.mapmodel.MapModel; 058import net.sf.gridarta.model.mapmodel.MapSquare; 059import net.sf.gridarta.model.select.ArchetypeNameMatchCriteria; 060import net.sf.gridarta.model.select.MatchCriteria; 061import net.sf.gridarta.model.select.ObjectNameMatchCriteria; 062import net.sf.gridarta.utils.ActionBuilderUtils; 063import net.sf.gridarta.utils.RandomUtils; 064import net.sf.japi.swing.action.ActionBuilder; 065import net.sf.japi.swing.action.ActionBuilderFactory; 066import net.sf.japi.swing.action.ActionMethod; 067import org.jetbrains.annotations.NotNull; 068import org.jetbrains.annotations.Nullable; 069 070/** 071 * This dialog manages the replace action. 072 * @author <a href="mailto:andi.vogl@gmx.net">Andreas Vogl</a> 073 * @author <a href="mailto:cher@riedquat.de">Christian.Hujer</a> 074 */ 075public class ReplaceDialog<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> extends JOptionPane { 076 077 /** 078 * Serial Version UID. 079 */ 080 private static final long serialVersionUID = 1L; 081 082 /** 083 * Action Builder. 084 */ 085 @NotNull 086 private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta"); 087 088 /** 089 * Index for {@link #replaceWithBox}: replace with object chooser 090 * selection. 091 */ 092 private static final int REPLACE_WITH_OBJECT_CHOOSER = 0; 093 094 /** 095 * Index for {@link #replaceWithBox}: replace with copy buffer contents. 096 */ 097 private static final int REPLACE_WITH_COPY_BUFFER = 1; 098 099 /** 100 * Index for {@link #replaceWithBox}: replace with pickmap contents. 101 */ 102 private static final int REPLACE_WITH_PICKMAP = 2; 103 104 /** 105 * Index for {@link #replaceWithBox}: delete matching game objects. 106 */ 107 private static final int REPLACE_WITH_NOTHING = 3; 108 109 /** 110 * Index for {@link #replaceEntireBox}: replace map. 111 */ 112 private static final int REPLACE_ON_MAP = 0; 113 114 /** 115 * Index for {@link #replaceEntireBox}: replace selection. 116 */ 117 private static final int REPLACE_ON_SELECTION = 1; 118 119 /** 120 * The {@link InsertionModeSet} to use. 121 */ 122 @NotNull 123 private final InsertionModeSet<G, A, R> insertionModeSet; 124 125 /** 126 * The dialog instance. 127 */ 128 @NotNull 129 private final JDialog dialog; 130 131 /** 132 * The parent component for dialogs. 133 */ 134 @NotNull 135 private final Component parent; 136 137 /** 138 * The {@link CopyBuffer}. 139 */ 140 @NotNull 141 private final CopyBuffer<G, A, R> copyBuffer; 142 143 /** 144 * The object chooser to use. 145 */ 146 @NotNull 147 private final ObjectChooser<G, A, R> objectChooser; 148 149 /** 150 * The {@link FaceObjectProviders} for looking up faces. 151 */ 152 @NotNull 153 private final FaceObjectProviders faceObjectProviders; 154 155 /** 156 * Whether this replace dialog has been displayed. 157 */ 158 private boolean isBuilt; 159 160 /** 161 * The {@link MapView} to operate on. 162 */ 163 @NotNull 164 private MapView<G, A, R> mapView; 165 166 /** 167 * Objects will be replaced with this game object. 168 */ 169 @Nullable 170 private BaseObject<G, A, R, ?> replaceArch; 171 172 @NotNull 173 private List<G> replaceCopyBuffer; // objects in CopyBuffer 174 175 @NotNull 176 private List<? extends BaseObject<G, A, R, ?>> replacePickmap; // selected objects in pickmap or all if none is selected 177 178 @NotNull 179 private JLabel rfHeading; 180 181 @Nullable 182 private JLabel rfArchName; 183 184 @NotNull 185 private JLabel iconLabel; 186 187 @NotNull 188 private JLabel colonLabel; 189 190 @NotNull 191 private JComboBox replaceCriteria; 192 193 @NotNull 194 private JComboBox replaceWithBox; 195 196 @NotNull 197 private JComboBox replaceEntireBox; 198 199 @NotNull 200 private JTextComponent replaceInput1; 201 202 /** 203 * Input field for replace density value. 204 */ 205 @NotNull 206 private JTextComponent replaceDensityInput; 207 208 private int lastSelectedIndex = REPLACE_WITH_OBJECT_CHOOSER; 209 210 /** 211 * The {@link ObjectChooserListener} for tracking the selection. 212 */ 213 @NotNull 214 private final ObjectChooserListener<G, A, R> objectChooserListener = new ObjectChooserListener<G, A, R>() { 215 216 @Override 217 public void pickmapActiveChanged(final boolean pickmapActive) { 218 // ignore 219 } 220 221 @Override 222 public void selectionChanged(@Nullable final BaseObject<G, A, R, ?> gameObject) { 223 updateArchSelection(gameObject, false); 224 } 225 226 }; 227 228 /** 229 * The {@link FaceObjectProvidersListener} for detecting reloaded faces. 230 */ 231 @NotNull 232 private final FaceObjectProvidersListener faceObjectProvidersListener = new FaceObjectProvidersListener() { 233 234 @Override 235 public void facesReloaded() { 236 updateArchSelection(objectChooser.getSelection(), false); 237 } 238 239 }; 240 241 /** 242 * Creates a new instance. 243 * @param parent the parent component for dialogs 244 * @param copyBuffer the copy buffer's 245 * @param objectChooser the object chooser to use 246 * @param faceObjectProviders the face object providers for looking up 247 * faces 248 * @param insertionModeSet the insertion mode set to use 249 */ 250 public ReplaceDialog(@NotNull final Component parent, @NotNull final CopyBuffer<G, A, R> copyBuffer, @NotNull final ObjectChooser<G, A, R> objectChooser, @NotNull final FaceObjectProviders faceObjectProviders, @NotNull final InsertionModeSet<G, A, R> insertionModeSet) { 251 this.insertionModeSet = insertionModeSet; 252 dialog = createDialog(parent, ActionBuilderUtils.getString(ACTION_BUILDER, "replaceTitle")); 253 dialog.setModal(false); 254 dialog.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); 255 this.parent = parent; 256 this.copyBuffer = copyBuffer; 257 this.objectChooser = objectChooser; 258 this.faceObjectProviders = faceObjectProviders; 259 objectChooser.addObjectChooserListener(objectChooserListener); 260 faceObjectProviders.addFaceObjectProvidersListener(faceObjectProvidersListener); 261 } 262 263 /** 264 * Replace objects on the map. 265 * @param mapView map view of the active map where the action was invoked 266 */ 267 public void display(@NotNull final MapView<G, A, R> mapView) { 268 replaceArch = objectChooser.getCursorSelection(); // highlighted arch 269 replacePickmap = objectChooser.getSelections(); // selected arches 270 replaceCopyBuffer = copyBuffer.getAllGameObjects(); 271 272 if (isBuilt) { 273 // just set fields and show 274 rfHeading.setText("\"" + mapView.getMapControl().getMapModel().getMapArchObject().getMapName() + "\":"); 275 replaceInput1.setText(""); 276 277 this.mapView = mapView; 278 if (replaceArch == null) { 279 replaceWithBox.setSelectedIndex(REPLACE_WITH_COPY_BUFFER); 280 iconLabel.setIcon(null); 281 rfArchName.setText(""); 282 colonLabel.setText(""); 283 } else { 284 replaceWithBox.setSelectedIndex(REPLACE_WITH_OBJECT_CHOOSER); 285 iconLabel.setIcon(faceObjectProviders.getFace(replaceArch)); 286 rfArchName.setText(" " + replaceArch.getBestName()); 287 colonLabel.setText(":"); 288 } 289 290 if (mapView.getSelectedSquares().size() > 1) { 291 replaceEntireBox.setSelectedIndex(REPLACE_ON_SELECTION); 292 } else { 293 replaceEntireBox.setSelectedIndex(REPLACE_ON_MAP); 294 } 295 296 replaceDensityInput.setText("100"); 297 298 dialog.pack(); 299 dialog.toFront(); 300 } else { 301 this.mapView = mapView; 302 final JPanel mainPanel = new JPanel(); 303 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); 304 mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 2, 5)); 305 306 // first line: heading 307 final Container line1 = new JPanel(new FlowLayout(FlowLayout.LEFT)); 308 final JComponent labelOn = ActionBuilderUtils.newLabel(ACTION_BUILDER, "replaceOn"); 309 labelOn.setToolTipText(ActionBuilderUtils.getString(ACTION_BUILDER, "replaceOn.shortdescription")); 310 line1.add(labelOn); 311 line1.add(Box.createVerticalStrut(3)); 312 replaceEntireBox = new JComboBox(new String[] { ActionBuilderUtils.getString(ACTION_BUILDER, "replaceOnMap"), ActionBuilderUtils.getString(ACTION_BUILDER, "replaceOnSelection") }); 313 replaceEntireBox.setToolTipText(ActionBuilderUtils.getString(ACTION_BUILDER, "replaceOn.shortdescription")); 314 if (mapView.getSelectedSquares().size() > 1) { 315 replaceEntireBox.setSelectedIndex(REPLACE_ON_SELECTION); 316 } else { 317 replaceEntireBox.setSelectedIndex(REPLACE_ON_MAP); 318 } 319 line1.add(replaceEntireBox); 320 line1.add(Box.createVerticalStrut(3)); 321 rfHeading = new JLabel("\"" + mapView.getMapControl().getMapModel().getMapArchObject().getMapName() + "\":"); 322 line1.add(rfHeading); 323 mainPanel.add(line1); 324 325 // second line: replace what? 326 final Container line2 = new JPanel(new FlowLayout(FlowLayout.LEFT)); 327 final JComponent label1 = ActionBuilderUtils.newLabel(ACTION_BUILDER, "replaceDelete"); 328 label1.setToolTipText(ActionBuilderUtils.getString(ACTION_BUILDER, "replaceDelete.shortdescription")); 329 line2.add(label1); 330 line2.add(Box.createVerticalStrut(5)); 331 332 replaceCriteria = new JComboBox(new String[] { ActionBuilderUtils.getString(ACTION_BUILDER, "replaceArchetype"), ActionBuilderUtils.getString(ACTION_BUILDER, "replaceName") }); 333 replaceCriteria.setSelectedIndex(0); 334 replaceCriteria.setToolTipText(ActionBuilderUtils.getString(ACTION_BUILDER, "replaceDelete.shortdescription")); 335 line2.add(replaceCriteria); 336 line2.add(Box.createVerticalStrut(5)); 337 338 replaceInput1 = new JTextField(20); 339 replaceInput1.setToolTipText(ActionBuilderUtils.getString(ACTION_BUILDER, "replaceInput1.shortdescription")); 340 line2.add(replaceInput1); 341 mainPanel.add(line2); 342 343 // third line: replace by? 344 final Container line3 = new JPanel(new FlowLayout(FlowLayout.LEFT)); 345 final JComponent label2 = ActionBuilderUtils.newLabel(ACTION_BUILDER, "replaceBy"); 346 label2.setToolTipText(ActionBuilderUtils.getString(ACTION_BUILDER, "replaceBy.shortdescription")); 347 line3.add(label2); 348 line3.add(Box.createVerticalStrut(5)); 349 replaceWithBox = new JComboBox(new String[] { ActionBuilderUtils.getString(ACTION_BUILDER, "replaceByObject"), ActionBuilderUtils.getString(ACTION_BUILDER, "replaceByCopyBuffer"), ActionBuilderUtils.getString(ACTION_BUILDER, "replaceByPickmap"), ActionBuilderUtils.getString(ACTION_BUILDER, "replaceByNothing") }); 350 replaceWithBox.setToolTipText(ActionBuilderUtils.getString(ACTION_BUILDER, "replaceBy.shortdescription")); 351 //noinspection VariableNotUsedInsideIf 352 if (replaceArch == null) { 353 replaceWithBox.setSelectedIndex(REPLACE_WITH_NOTHING); 354 } else { 355 replaceWithBox.setSelectedIndex(REPLACE_WITH_OBJECT_CHOOSER); 356 } 357 replaceWithBox.addItemListener(new ReplaceWithBoxItemListener()); 358 lastSelectedIndex = replaceWithBox.getSelectedIndex(); 359 line3.add(replaceWithBox); 360 361 iconLabel = new JLabel(); 362 if (replaceArch != null) { 363 colonLabel = new JLabel(":"); 364 iconLabel.setIcon(faceObjectProviders.getFace(replaceArch)); 365 rfArchName = new JLabel(" " + replaceArch.getBestName()); 366 } else { 367 colonLabel = new JLabel(""); 368 rfArchName = new JLabel(""); 369 } 370 line3.add(colonLabel); 371 line3.add(Box.createVerticalStrut(5)); 372 line3.add(iconLabel); 373 line3.add(rfArchName); 374 mainPanel.add(line3); 375 376 // fourth line: replace density 377 final Container line4 = new JPanel(new FlowLayout(FlowLayout.LEFT)); 378 final JComponent label4 = ActionBuilderUtils.newLabel(ACTION_BUILDER, "replaceDensity"); 379 label4.setToolTipText(ActionBuilderUtils.getString(ACTION_BUILDER, "replaceDensity.shortdescription")); 380 line4.add(label4); 381 line4.add(Box.createVerticalStrut(5)); 382 replaceDensityInput = new JTextField(5); 383 replaceDensityInput.setToolTipText(ActionBuilderUtils.getString(ACTION_BUILDER, "replaceDensity.shortdescription")); 384 line4.add(replaceDensityInput); 385 replaceDensityInput.setText("100"); 386 mainPanel.add(line4); 387 388 final JButton okButton = new JButton(ACTION_BUILDER.createAction(false, "replaceOk", this)); 389 final JButton applyButton = new JButton(ACTION_BUILDER.createAction(false, "replaceApply", this)); 390 final JButton cancelButton = new JButton(ACTION_BUILDER.createAction(false, "replaceCancel", this)); 391 392 setMessage(mainPanel); 393 setOptions(new Object[] { okButton, applyButton, cancelButton }); 394 dialog.getRootPane().setDefaultButton(okButton); 395 dialog.pack(); 396 dialog.setLocationRelativeTo(parent); 397 isBuilt = true; 398 } 399 dialog.setVisible(true); 400 } 401 402 /** 403 * Update which arch is displayed as replace object. 404 * @param newArch the new 'replaceArch' to be shown and stored 405 * @param alwaysPack if false, the frame is packed only when icon size 406 * changed if true, the frame is always packed (packing resizes but also 407 * causes flicker) 408 */ 409 private void updateArchSelection(@Nullable final BaseObject<G, A, R, ?> newArch, final boolean alwaysPack) { 410 if (isShowing() && replaceWithBox.getSelectedIndex() == REPLACE_WITH_OBJECT_CHOOSER) { 411 replaceArch = newArch; 412 if (newArch != null) { 413 final Icon oldIcon = iconLabel.getIcon(); 414 415 iconLabel.setIcon(faceObjectProviders.getFace(newArch)); 416 rfArchName.setText(" " + newArch.getBestName()); 417 colonLabel.setText(":"); 418 419 // pack frame only if height of icon changed 420 if (alwaysPack || (oldIcon == null && iconLabel.getIcon() != null) || (oldIcon != null && iconLabel.getIcon() == null) || (oldIcon != iconLabel.getIcon() && oldIcon != null && oldIcon.getIconHeight() != iconLabel.getIcon().getIconHeight())) { 421 dialog.pack(); 422 } 423 } else { 424 iconLabel.setIcon(null); 425 rfArchName.setText(""); 426 colonLabel.setText(""); 427 } 428 } 429 } 430 431 /** 432 * This method performs the actual replace action on a map. 433 * @param matchCriteria matching criteria for replace 434 * @param entireMap if true, the entire map is affected - if false, only 435 * highlighted area 436 * @param deleteOnly if true matching arches get only deleted and not 437 * replaced 438 * @param replaceDensity the replace density in % 439 * @return number of arches that have been replaced 440 */ 441 private int doReplace(@NotNull final MatchCriteria<G, A, R> matchCriteria, final boolean entireMap, final boolean deleteOnly, final int replaceDensity) { 442 @Nullable final List<? extends BaseObject<G, A, R, ?>> replaceList; 443 switch (lastSelectedIndex) { 444 case REPLACE_WITH_OBJECT_CHOOSER: 445 if (replaceArch == null) { 446 replaceList = null; 447 } else { 448 replaceList = newList(replaceArch); 449 } 450 break; 451 452 case REPLACE_WITH_COPY_BUFFER: 453 replaceList = replaceCopyBuffer; 454 break; 455 456 case REPLACE_WITH_PICKMAP: 457 replaceList = replacePickmap; 458 break; 459 460 default: // REPLACE_WITH_NOTHING 461 replaceList = null; 462 break; 463 } 464 final Collection<G> objectsToReplace = new ArrayList<G>(); 465 final int replaceListSize = replaceList == null ? 0 : replaceList.size(); 466 final MapControl<G, A, R> mapControl = mapView.getMapControl(); 467 final MapModel<G, A, R> mapModel = mapControl.getMapModel(); 468 mapModel.beginTransaction("Replace"); // TODO: I18N/L10N 469 try { 470 int replaceCount = 0; 471 for (final MapSquare<G, A, R> square : entireMap ? mapModel : mapView.getSelectedSquares()) { 472 // Operate on a copy of the nodes to prevent ConcurrentModificationException 473 474 // find objects to replace 475 objectsToReplace.clear(); 476 for (final G node : square) { 477 if (node.isHead() && matchCriteria.matches(node)) { 478 if (replaceDensity > RandomUtils.rnd.nextInt(100)) { 479 objectsToReplace.add(node); 480 } 481 } 482 } 483 484 // actually replace the objects 485 for (final G objectToReplace : objectsToReplace) { 486 final Iterator<G> it = square.iterator(); 487 G prevArch = null; 488 G node = null; 489 while (it.hasNext()) { 490 node = it.next(); 491 492 if (node == objectToReplace) { 493 break; 494 } 495 496 prevArch = node; 497 } 498 assert node != null; 499 500 // first, delete the old arch 501 node.remove(); 502 503 if (replaceListSize > 0 && !deleteOnly) { 504 final BaseObject<G, A, R, ?> randomArch; 505 if (replaceListSize == 1) { 506 randomArch = replaceList.get(0); 507 } else { 508 randomArch = replaceList.get(RandomUtils.rnd.nextInt(replaceList.size())); 509 } 510 // insert replacement object 511 if (randomArch.isMulti()) { 512 mapModel.insertBaseObject(randomArch, square.getMapLocation(), false, false, insertionModeSet.getTopmostInsertionMode()); 513 } else { 514 mapModel.insertArchToMap(randomArch, prevArch, square.getMapLocation(), false); 515 } 516 } 517 replaceCount++; 518 } 519 } 520 return replaceCount; 521 } finally { 522 mapModel.endTransaction(); 523 } 524 } 525 526 /** 527 * Creates a new list containing one element. 528 * @param element the element 529 * @return the list 530 */ 531 @NotNull 532 private static <T> List<T> newList(@NotNull final T element) { 533 final List<T> list = new ArrayList<T>(1); 534 list.add(element); 535 return list; 536 } 537 538 /** 539 * Item-listener for the "replace with"-selection box. 540 */ 541 private class ReplaceWithBoxItemListener implements ItemListener { 542 543 @Override 544 public void itemStateChanged(@NotNull final ItemEvent e) { 545 final int selectedIndex = replaceWithBox.getSelectedIndex(); 546 if (e.getStateChange() == ItemEvent.SELECTED && lastSelectedIndex != selectedIndex) { 547 final int size; 548 switch (selectedIndex) { 549 case REPLACE_WITH_OBJECT_CHOOSER: 550 replaceArch = objectChooser.getSelection(); // selected arch 551 updateArchSelection(replaceArch, true); 552 break; 553 554 case REPLACE_WITH_COPY_BUFFER: 555 replaceCopyBuffer = copyBuffer.getAllGameObjects(); 556 iconLabel.setIcon(null); 557 size = replaceCopyBuffer.size(); 558 rfArchName.setText(String.valueOf(size)); 559 colonLabel.setText(":"); 560 dialog.pack(); 561 break; 562 563 case REPLACE_WITH_PICKMAP: 564 replacePickmap = objectChooser.getSelections(); // selected arches 565 iconLabel.setIcon(null); 566 size = replacePickmap.size(); 567 rfArchName.setText(String.valueOf(size)); 568 colonLabel.setText(":"); 569 dialog.pack(); 570 break; 571 572 case REPLACE_WITH_NOTHING: 573 iconLabel.setIcon(null); 574 rfArchName.setText(""); 575 colonLabel.setText(""); 576 dialog.pack(); 577 break; 578 } 579 lastSelectedIndex = selectedIndex; 580 } 581 } 582 583 } 584 585 /** 586 * Action method for Ok button. 587 */ 588 @ActionMethod 589 public void replaceOk() { 590 if (doReplace()) { 591 dialog.setVisible(false); 592 } 593 } 594 595 /** 596 * Action method for Apply button. 597 */ 598 @ActionMethod 599 public void replaceApply() { 600 doReplace(); 601 } 602 603 /** 604 * Executes one replace operation. 605 * @return whether the replace operation was successful 606 */ 607 private boolean doReplace() { 608 final String matchString = replaceInput1.getText().trim(); 609 final boolean deleteOnly = replaceWithBox.getSelectedIndex() == REPLACE_WITH_NOTHING; 610 final boolean entireMap = replaceEntireBox.getSelectedIndex() == REPLACE_ON_MAP; 611 612 if (!entireMap && mapView.getMapGrid().getSelectedRec() == null) { 613 // user selected "replace highlighted" but nothing is highlighted 614 ACTION_BUILDER.showMessageDialog(this, "replaceMapNoSelection", mapView.getMapControl().getMapModel().getMapArchObject().getMapName()); 615 return false; 616 } 617 618 final MatchCriteria<G, A, R> matchCriteria; 619 if (replaceCriteria.getSelectedIndex() == 0) { 620 matchCriteria = new ArchetypeNameMatchCriteria<G, A, R>(matchString); 621 } else if (replaceCriteria.getSelectedIndex() == 1) { 622 matchCriteria = new ObjectNameMatchCriteria<G, A, R>(matchString); 623 } else { 624 return false; 625 } 626 627 final int replaceDensity; 628 try { 629 replaceDensity = Integer.parseInt(replaceDensityInput.getText()); 630 } catch (final NumberFormatException ignored) { 631 ACTION_BUILDER.showMessageDialog(this, "replaceInvalidDensity"); 632 return false; 633 } 634 if (replaceDensity < 1 || replaceDensity > 100) { 635 ACTION_BUILDER.showMessageDialog(this, "replaceInvalidDensity"); 636 return false; 637 } 638 639 final int replaceCount = doReplace(matchCriteria, entireMap, deleteOnly, replaceDensity); 640 if (replaceCount <= 0) { 641 ACTION_BUILDER.showMessageDialog(this, "replacedZero"); 642 return false; 643 } 644 645 if (replaceCount == 1) { 646 ACTION_BUILDER.showMessageDialog(this, "replacedOne"); 647 } else { 648 ACTION_BUILDER.showMessageDialog(this, "replacedMany", replaceCount); 649 } 650 return true; 651 } 652 653 /** 654 * Action method for Cancel button. 655 */ 656 @ActionMethod 657 public void replaceCancel() { 658 dialog.setVisible(false); 659 } 660 661 /** 662 * Disposes the replace dialog. 663 * @param mapView the map view to dispose the dialog of; do nothing if no 664 */ 665 public void dispose(@NotNull final MapView<G, A, R> mapView) { 666 if (mapView == this.mapView) { 667 dialog.setVisible(false); 668 } 669 } 670 671}