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.panel.tools;
021
022import java.awt.BorderLayout;
023import java.awt.CardLayout;
024import java.awt.Component;
025import java.awt.Container;
026import java.awt.FlowLayout;
027import java.awt.Insets;
028import java.awt.event.ActionEvent;
029import java.util.HashMap;
030import java.util.Map;
031import javax.swing.AbstractAction;
032import javax.swing.AbstractButton;
033import javax.swing.Action;
034import javax.swing.ButtonGroup;
035import javax.swing.JPanel;
036import javax.swing.JToggleButton;
037import net.sf.gridarta.gui.map.event.MouseOpListener;
038import net.sf.gridarta.gui.panel.objectchooser.ObjectChooser;
039import net.sf.gridarta.gui.panel.selectedsquare.SelectedSquareModel;
040import net.sf.gridarta.model.archetype.Archetype;
041import net.sf.gridarta.model.gameobject.GameObject;
042import net.sf.gridarta.model.maparchobject.MapArchObject;
043import net.sf.gridarta.model.mapmodel.InsertionModeSet;
044import net.sf.gridarta.model.mapviewsettings.MapViewSettings;
045import net.sf.gridarta.model.match.GameObjectMatcher;
046import net.sf.gridarta.model.pickmapsettings.PickmapSettings;
047import net.sf.japi.swing.action.ActionBuilder;
048import net.sf.japi.swing.action.ActionBuilderFactory;
049import org.jetbrains.annotations.NotNull;
050import org.jetbrains.annotations.Nullable;
051
052/**
053 * User interface for selecting a tool and displaying its options. Note: A
054 * ToolSelector automatically has always at least one Tool, the VoidTool.
055 * @author <a href="mailto:cher@riedquat.de">Christian Hujer</a>
056 */
057public class ToolSelector<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> extends JPanel {
058
059    /**
060     * The serial version UID.
061     */
062    private static final long serialVersionUID = 1L;
063
064    /**
065     * The Action Builder.
066     */
067    private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta.gui.panel.tools");
068
069    /**
070     * The pane with the selections.
071     */
072    @NotNull
073    private final Container selectionPane = new JPanel(new FlowLayout());
074
075    /**
076     * The CardLayout for the pane that shows a tool's options.
077     */
078    @NotNull
079    private final CardLayout optionCards = new CardLayout();
080
081    /**
082     * The ButtonGroup for the toggle buttons.
083     */
084    @NotNull
085    private final ButtonGroup selectionButtonGroup = new ButtonGroup();
086
087    /**
088     * The pane with the options of a tool.
089     */
090    @NotNull
091    private final Container optionsPane = new JPanel(optionCards);
092
093    /**
094     * The currently selected tool.
095     */
096    @NotNull
097    private Tool<G, A, R> selectedTool;
098
099    /**
100     * The tools.
101     */
102    @NotNull
103    private final Map<String, Tool<G, A, R>> tools = new HashMap<String, Tool<G, A, R>>();
104
105    /**
106     * Empty margin.
107     */
108    private static final Insets EMPTY_MARGIN = new Insets(0, 0, 0, 0);
109
110    /**
111     * Creates a new instance.
112     * @param defaultTool name of the tool that should be selected by default
113     * @param mapViewSettings the map view settings instance
114     * @param selectedSquareModel the selected square model
115     * @param objectChooser the object chooser to use
116     * @param pickmapSettings the pickmap settings to use
117     * @param floorGameObjectMatcher the floor matcher to use
118     * @param wallGameObjectMatcher the wall matcher to use
119     * @param monsterGameObjectMatcher the monster matcher to use
120     * @param insertionModeSet the insertion mode set to use
121     */
122    public ToolSelector(@NotNull final String defaultTool, @NotNull final MapViewSettings mapViewSettings, @NotNull final SelectedSquareModel<G, A, R> selectedSquareModel, @NotNull final ObjectChooser<G, A, R> objectChooser, @NotNull final PickmapSettings pickmapSettings, @Nullable final GameObjectMatcher floorGameObjectMatcher, @Nullable final GameObjectMatcher wallGameObjectMatcher, @Nullable final GameObjectMatcher monsterGameObjectMatcher, @NotNull final InsertionModeSet<G, A, R> insertionModeSet) {
123        createUI();
124        addTool(new VoidTool<G, A, R>(), defaultTool);
125        addTool(new SelectionTool<G, A, R>(objectChooser, insertionModeSet), defaultTool);
126        addTool(new DeletionTool<G, A, R>(mapViewSettings, objectChooser, pickmapSettings, floorGameObjectMatcher, wallGameObjectMatcher, monsterGameObjectMatcher), defaultTool);
127        addTool(new InsertionTool<G, A, R>(selectedSquareModel, objectChooser, pickmapSettings, insertionModeSet, mapViewSettings), defaultTool);
128    }
129
130    /**
131     * Adds a tool to this tool selector.
132     * @param tool the tool to add
133     * @param defaultTool the name of the default tool
134     */
135    private void addTool(@NotNull final Tool<G, A, R> tool, @NotNull final String defaultTool) {
136        add(tool, tool.getId().equals(defaultTool));
137    }
138
139    /**
140     * Creates the user interface elements of the ToolSelector.
141     */
142    private void createUI() {
143        setLayout(new BorderLayout());
144        add(selectionPane, BorderLayout.NORTH);
145        add(optionsPane, BorderLayout.CENTER);
146    }
147
148    /**
149     * Adds a tool to this tool selector.
150     * @param tool the tool to add
151     */
152    @SuppressWarnings("MethodOverloadsMethodOfSuperclass")
153    public void add(@NotNull final Tool<G, A, R> tool) {
154        add(tool, false);
155    }
156
157    /**
158     * Adds a tool to this tool selector.
159     * @param tool the tool to add
160     * @param selected <code>true</code> if the tool should be made the selected
161     * tool, otherwise <code>false</code>
162     */
163    private void add(@NotNull final Tool<G, A, R> tool, final boolean selected) {
164        @NotNull final Action selectionAction = new SelectionAction(tool);
165        @NotNull final AbstractButton toggleButton = new JToggleButton(selectionAction);
166        toggleButton.setMargin(EMPTY_MARGIN);
167        @NotNull final Component optionsView = createOptionsView(tool);
168        selectionButtonGroup.add(toggleButton);
169        selectionPane.add(toggleButton);
170        final Container panel = new JPanel(new BorderLayout());
171        panel.add(optionsView, BorderLayout.NORTH);
172        optionsPane.add(panel, tool.getId());
173        toggleButton.setSelected(selected);
174        tools.put(tool.getId(), tool);
175        if (selected) {
176            selectedTool = tool;
177            optionCards.show(optionsPane, tool.getId());
178        }
179    }
180
181    /**
182     * Creates the options view for a tool. This method is a delegate to {@link
183     * Tool#createOptionsView()} but will provide a fallback if the tool doesn't
184     * provide tweaking its options.
185     * @param tool the tool to create options view for
186     * @return the options view (the tool's options view or a dummy fallback if
187     *         the tool doesn't provide an options view)
188     */
189    @NotNull
190    private static <G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> Component createOptionsView(@NotNull final Tool<G, A, R> tool) {
191        @Nullable final Component optionsView = tool.createOptionsView();
192        return optionsView != null ? optionsView : new JPanel();
193    }
194
195    /**
196     * Makes a tool the currently selected tool to edit its options.
197     * @param tool the tool to select
198     * @pre the tool must be controlled by this tool-selector.
199     * @see #setSelectedTool(String)
200     */
201    private void setSelectedTool(@NotNull final Tool<G, A, R> tool) {
202        selectedTool = tool;
203        optionCards.show(optionsPane, tool.getId());
204    }
205
206    /**
207     * Makes a tool the currently selected tool to edit its options. This method
208     * exists to allow programs to store the currently selected tool in
209     * preferences and restore it after startup.
210     * @param id the ID of tool to select
211     * @pre the tool must be controlled by this tool-selector.
212     * @see #setSelectedTool(Tool)
213     * @see Tool#getId()
214     */
215    public void setSelectedTool(@NotNull final String id) {
216        setSelectedTool(tools.get(id));
217    }
218
219    /**
220     * Returns the tool that is currently selected.
221     * @return the currently selected tool
222     */
223    @NotNull
224    public MouseOpListener<G, A, R> getSelectedTool() {
225        return selectedTool;
226    }
227
228    /**
229     * Action for selecting a tool.
230     */
231    private class SelectionAction extends AbstractAction {
232
233        /**
234         * The serial version UID.
235         */
236        private static final long serialVersionUID = 1L;
237
238        /**
239         * The tool to select with this action.
240         */
241        @NotNull
242        private final Tool<G, A, R> tool;
243
244        /**
245         * Creates a SelectionAction.
246         * @param tool the tool to select with this action
247         */
248        private SelectionAction(@NotNull final Tool<G, A, R> tool) {
249            this.tool = tool;
250            ACTION_BUILDER.initAction(false, this, tool.getId());
251        }
252
253        @Override
254        public void actionPerformed(@NotNull final ActionEvent e) {
255            setSelectedTool(tool);
256        }
257
258        @Override
259        public Object clone() throws CloneNotSupportedException {
260            return super.clone();
261        }
262
263    }
264
265}