001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.vmd.game.model;
042:
043: import java.awt.BorderLayout;
044: import java.awt.Color;
045: import java.beans.PropertyChangeEvent;
046: import java.beans.PropertyChangeListener;
047: import java.net.URL;
048: import java.util.ArrayList;
049: import java.util.Collection;
050: import java.util.Collections;
051: import java.util.HashMap;
052: import java.util.Iterator;
053: import java.util.List;
054: import java.util.Map;
055: import javax.swing.Action;
056: import javax.swing.JComponent;
057: import javax.swing.JPanel;
058: import javax.swing.JScrollPane;
059: import javax.swing.event.EventListenerList;
060: import org.netbeans.modules.vmd.api.model.DesignDocument;
061: import org.netbeans.modules.vmd.game.view.ColorConstants;
062: import org.netbeans.modules.vmd.game.view.GameDesignNavigator;
063: import org.netbeans.modules.vmd.game.view.GameDesignOverViewPanel;
064: import org.netbeans.modules.vmd.game.view.main.MainView;
065: import org.openide.util.NbBundle;
066:
067: public class GlobalRepository implements PropertyChangeListener,
068: Editable {
069:
070: private JComponent editor;
071:
072: private DesignDocument designDocument;
073: private MainView mainView;
074:
075: public static final boolean DEBUG = false;
076:
077: EventListenerList listenerList = new EventListenerList();
078:
079: private GameDesignNavigator navigator;
080:
081: private HashMap<String, Layer> layers = new HashMap<String, Layer>();
082: private ArrayList<TiledLayer> tiledLayers = new ArrayList<TiledLayer>();
083: private ArrayList<Sprite> sprites = new ArrayList<Sprite>();
084: private ArrayList<Scene> scenes = new ArrayList<Scene>();
085: private Map<String, ImageResource> imgResourceMap = new HashMap<String, ImageResource>();
086:
087: public GlobalRepository(DesignDocument designDocument) {
088: this .designDocument = designDocument;
089: }
090:
091: public DesignDocument getDesignDocument() {
092: return this .designDocument;
093: }
094:
095: public void addGlobalRepositoryListener(GlobalRepositoryListener l) {
096: this .listenerList.add(GlobalRepositoryListener.class, l);
097: }
098:
099: public void removeGlobalRepositoryListener(
100: GlobalRepositoryListener l) {
101: this .listenerList.remove(GlobalRepositoryListener.class, l);
102: }
103:
104: public MainView getMainView() {
105: if (this .mainView == null) {
106: this .mainView = new MainView(this );
107: this .addGlobalRepositoryListener(this .mainView);
108: }
109: return this .mainView;
110: }
111:
112: public boolean removeIdentifiable(long id) {
113: Collection<Scene> tmpScene = new ArrayList<Scene>();
114: tmpScene.addAll(this .scenes);
115: for (Scene scene : tmpScene) {
116: if (scene.getId() == id) {
117: this .removeScene(scene);
118: return true;
119: }
120: }
121: List<Layer> tmpLayer = new ArrayList<Layer>();
122: tmpLayer.addAll(this .layers.values());
123: for (Layer layer : tmpLayer) {
124: if (layer.getId() == id) {
125: this .removeLayer(layer);
126: return true;
127: }
128: }
129: return false;
130: }
131:
132: /**
133: * Removes all layers, scenes
134: */
135: public void removeAllComponents() {
136: this .removeAllScenes();
137: this .removeAllLayers();
138: this .imgResourceMap.clear();
139: }
140:
141: private void removeAllScenes() {
142: Collection<Scene> tmp = new ArrayList<Scene>();
143: tmp.addAll(this .scenes);
144: for (Scene scene : tmp) {
145: this .removeScene(scene);
146: }
147: }
148:
149: private void removeAllLayers() {
150: List<Layer> tmp = new ArrayList<Layer>();
151: tmp.addAll(this .layers.values());
152: for (Layer layer : tmp) {
153: this .removeLayer(layer);
154: }
155: }
156:
157: /**
158: * May return null if the image resource hasn't yet been created.
159: */
160: public ImageResource getImageResource(String relativeResourcePath) {
161: return imgResourceMap.get(relativeResourcePath);
162: }
163:
164: /**
165: * Returns ImageResource instance.
166: */
167: public ImageResource getImageResource(URL imageURL,
168: String relativeResourcePath) {
169: ImageResource imgResource = imgResourceMap
170: .get(relativeResourcePath);
171: if (imgResource == null) {
172: imgResource = new ImageResource(this , imageURL,
173: relativeResourcePath);
174: imgResourceMap.put(relativeResourcePath, imgResource);
175: this .fireImageResourceAdded(imgResource);
176:
177: if (DEBUG) {
178: System.out.println("Added " + imageURL
179: + ". ImgResourceMap now contains:"); // NOI18N
180: for (Iterator iter = imgResourceMap.keySet().iterator(); iter
181: .hasNext();) {
182: Object url = iter.next();
183: System.out.println("\t" + url); // NOI18N
184: }
185: }//end DEBUG
186: }
187: return imgResource;
188: }
189:
190: public Collection<ImageResource> getImageResources() {
191: return Collections.unmodifiableCollection(this .imgResourceMap
192: .values());
193: }
194:
195: public ImageResource getImageResource(long id) {
196: for (ImageResource imgRes : this .getImageResources()) {
197: if (imgRes.getId() == id) {
198: return imgRes;
199: }
200: }
201: return null;
202: }
203:
204: private void fireImageResourceAdded(ImageResource imgRes) {
205: Object[] listeners = listenerList.getListenerList();
206: for (int i = listeners.length - 2; i >= 0; i -= 2) {
207: if (listeners[i] == GlobalRepositoryListener.class) {
208: ((GlobalRepositoryListener) listeners[i + 1])
209: .imageResourceAdded(imgRes);
210: }
211: }
212: }
213:
214: private void addTiledLayer(TiledLayer layer) {
215: this .tiledLayers.add(layer);
216: this .layers.put(layer.getName(), layer);
217: layer.addPropertyChangeListener(this );
218: Collections.sort(this .tiledLayers, new Layer.NameComparator());
219: int index = this .tiledLayers.indexOf(layer);
220: this .fireTiledLayerAdded(layer, index);
221: }
222:
223: private void fireTiledLayerAdded(TiledLayer layer, int index) {
224: Object[] listeners = listenerList.getListenerList();
225: for (int i = listeners.length - 2; i >= 0; i -= 2) {
226: if (listeners[i] == GlobalRepositoryListener.class) {
227: ((GlobalRepositoryListener) listeners[i + 1])
228: .tiledLayerAdded(layer, index);
229: }
230: }
231: }
232:
233: private void addSprite(Sprite layer) {
234: this .sprites.add(layer);
235: this .layers.put(layer.getName(), layer);
236: layer.addPropertyChangeListener(this );
237: Collections.sort(this .sprites, new Layer.NameComparator());
238: int index = this .sprites.indexOf(layer);
239: this .fireSpriteAdded(layer, index);
240: }
241:
242: private void fireSpriteAdded(Sprite layer, int index) {
243: Object[] listeners = listenerList.getListenerList();
244: for (int i = listeners.length - 2; i >= 0; i -= 2) {
245: if (listeners[i] == GlobalRepositoryListener.class) {
246: ((GlobalRepositoryListener) listeners[i + 1])
247: .spriteAdded(layer, index);
248: }
249: }
250: }
251:
252: private void removeTiledLayer(TiledLayer layer) {
253: this .removeLayerfromLayers(layer);
254: int index = this .tiledLayers.indexOf(layer);
255: this .tiledLayers.remove(layer);
256: this .fireTiledLayerRemoved(layer, index);
257: }
258:
259: private void fireTiledLayerRemoved(TiledLayer layer, int index) {
260: Object[] listeners = listenerList.getListenerList();
261: for (int i = listeners.length - 2; i >= 0; i -= 2) {
262: if (listeners[i] == GlobalRepositoryListener.class) {
263: ((GlobalRepositoryListener) listeners[i + 1])
264: .tiledLayerRemoved(layer, index);
265: }
266: }
267: }
268:
269: private void removeSprite(Sprite layer) {
270: this .removeLayerfromLayers(layer);
271: int index = this .sprites.indexOf(layer);
272: this .sprites.remove(layer);
273: this .fireSpriteRemoved(layer, index);
274: }
275:
276: private void fireSpriteRemoved(Sprite layer, int index) {
277: Object[] listeners = listenerList.getListenerList();
278: for (int i = listeners.length - 2; i >= 0; i -= 2) {
279: if (listeners[i] == GlobalRepositoryListener.class) {
280: ((GlobalRepositoryListener) listeners[i + 1])
281: .spriteRemoved(layer, index);
282: }
283: }
284: }
285:
286: void removeLayer(Layer layer) {
287: List<Scene> sceneList = this .getScenes();
288: for (Scene scene : sceneList) {
289: scene.remove(layer);
290: }
291: if (layer instanceof TiledLayer) {
292: TiledLayer tl = (TiledLayer) layer;
293: this .removeTiledLayer(tl);
294: } else if (layer instanceof Sprite) {
295: Sprite sprite = (Sprite) layer;
296: this .removeSprite(sprite);
297: }
298: }
299:
300: private void removeLayerfromLayers(Layer layer) {
301: this .layers.remove(layer.getName());
302: layer.removePropertyChangeListener(this );
303: }
304:
305: public Layer getLayerByName(String name) {
306: return this .layers.get(name);
307: }
308:
309: public Layer getLayer(long id) {
310: for (Layer layer : this .layers.values()) {
311: if (layer.getId() == id) {
312: return layer;
313: }
314: }
315: return null;
316: }
317:
318: private void addScene(Scene scene) {
319: this .scenes.add(scene);
320: Collections.sort(this .scenes, new Scene.NameComparator());
321: int index = this .scenes.indexOf(scene);
322: this .fireSceneAdded(scene, index);
323: }
324:
325: private void fireSceneAdded(Scene scene, int index) {
326: Object[] listeners = listenerList.getListenerList();
327: for (int i = listeners.length - 2; i >= 0; i -= 2) {
328: if (listeners[i] == GlobalRepositoryListener.class) {
329: ((GlobalRepositoryListener) listeners[i + 1])
330: .sceneAdded(scene, index);
331: }
332: }
333: }
334:
335: void removeScene(Scene scene) {
336: int index = this .scenes.indexOf(scene);
337: this .scenes.remove(scene);
338: this .fireSceneRemoved(scene, index);
339: }
340:
341: private void fireSceneRemoved(Scene scene, int index) {
342: Object[] listeners = listenerList.getListenerList();
343: for (int i = listeners.length - 2; i >= 0; i -= 2) {
344: if (listeners[i] == GlobalRepositoryListener.class) {
345: ((GlobalRepositoryListener) listeners[i + 1])
346: .sceneRemoved(scene, index);
347: }
348: }
349: }
350:
351: public boolean isComponentNameAvailable(String fieldName) {
352: List<String> derivedNames = deriveUsedNames(fieldName);
353: for (String derivedName : derivedNames) {
354: if (!this .isNameAvailable(derivedName)) {
355: return false;
356: }
357: }
358: return true;
359: }
360:
361: public static List<String> deriveUsedNames(String fieldName) {
362: List<String> derivedNames = new ArrayList<String>();
363: derivedNames.add(CodeUtils.decapitalize(fieldName));
364: derivedNames.add(CodeUtils.capitalize(fieldName));
365: derivedNames.add(CodeUtils.createGetterMethodName(fieldName));
366: derivedNames.add(CodeUtils.createSetterMethodName(fieldName));
367: return derivedNames;
368: }
369:
370: private boolean isNameAvailable(String name) {
371: if (this .getLayerByName(name) != null) {
372: return false;
373: }
374: if (this .getSceneByName(name) != null) {
375: return false;
376: }
377: for (ImageResource imgRes : this .getImageResources()) {
378: if (imgRes.getName(false).equals(name)) {
379: return false;
380: }
381: if (imgRes.getSequenceByName(name) != null) {
382: return false;
383: }
384: if (imgRes.getAnimatedTileByName(name) != null) {
385: return false;
386: }
387: }
388: return true;
389: }
390:
391: public String getNextAvailableComponentName(String name) {
392: String next = name;
393: int count = 1;
394: while (!isComponentNameAvailable(next)) {
395: next = name;
396: if (count < 100) {
397: next += "0";
398: }
399: if (count < 10) {
400: next += "0";
401: }
402: next += count++;
403: }
404: return next;
405: }
406:
407: public Scene getScene(long id) {
408: for (Iterator iter = this .scenes.iterator(); iter.hasNext();) {
409: Scene scene = (Scene) iter.next();
410: if (scene.getId() == id) {
411: return scene;
412: }
413: }
414: return null;
415: }
416:
417: public Scene getSceneByName(String name) {
418: for (Iterator iter = this .scenes.iterator(); iter.hasNext();) {
419: Scene scene = (Scene) iter.next();
420: if (scene.getName().equals(name)) {
421: return scene;
422: }
423: }
424: return null;
425: }
426:
427: public List<Scene> getScenes() {
428: return Collections.unmodifiableList(this .scenes);
429: }
430:
431: public List<TiledLayer> getTiledLayers() {
432: return Collections.unmodifiableList(this .tiledLayers);
433: }
434:
435: public List<Sprite> getSprites() {
436: return Collections.unmodifiableList(this .sprites);
437: }
438:
439: public void propertyChange(PropertyChangeEvent evt) {
440: if (DEBUG)
441: System.out
442: .println("GlobalRepository propertyChange() event: "
443: + evt); // NOI18N
444: if (evt.getSource() instanceof Layer) {
445: Layer layer = (Layer) evt.getSource();
446: if (evt.getPropertyName().equals(Editable.PROPERTY_NAME)) {
447: //layer name has changed re-key it in the layer table
448: this .layers.remove(evt.getOldValue());
449: this .layers.put((String) evt.getNewValue(), layer);
450: }
451: }
452: }
453:
454: public Scene createScene(String name) {
455: if (!this .isComponentNameAvailable(name)) {
456: throw new IllegalArgumentException(
457: "Scene cannot be created because component name '"
458: + name + "' already exists."); // NOI18N
459: }
460: Scene scene = new Scene(this , name);
461: this .addScene(scene);
462: return scene;
463: }
464:
465: public Scene createScene(String name, Scene original) {
466: if (!this .isComponentNameAvailable(name)) {
467: throw new IllegalArgumentException(
468: "Scene cannot be created because component name '"
469: + name + "' already exists."); // NOI18N
470: }
471: Scene scene = new Scene(this , name, original);
472: this .addScene(scene);
473: return scene;
474: }
475:
476: public TiledLayer createTiledLayer(String name,
477: ImageResource imageResource, int rows, int columns,
478: int tileWidth, int tileHeight) {
479: if (!this .isComponentNameAvailable(name)) {
480: throw new IllegalArgumentException(
481: "Scene cannot be created because component name '"
482: + name + "' already exists."); // NOI18N
483: }
484: TiledLayer layer = new TiledLayer(this , name, imageResource,
485: rows, columns, tileWidth, tileHeight);
486: this .addTiledLayer(layer);
487: return layer;
488: }
489:
490: public TiledLayer createTiledLayer(String name,
491: ImageResource imageResource, int[][] grid, int tileWidth,
492: int tileHeight) {
493: if (!this .isComponentNameAvailable(name)) {
494: throw new IllegalArgumentException(
495: "TiledLayer cannot be created because component name '"
496: + name + "' already exists."); // NOI18N
497: }
498: TiledLayer layer = new TiledLayer(this , name, imageResource,
499: grid, tileWidth, tileHeight);
500: this .addTiledLayer(layer);
501: return layer;
502: }
503:
504: public TiledLayer duplicateTiledLayer(String name,
505: TiledLayer original) {
506: if (!this .isComponentNameAvailable(name)) {
507: throw new IllegalArgumentException(
508: "TiledLayer cannot be created because component name '"
509: + name + "' already exists."); // NOI18N
510: }
511: TiledLayer layer = new TiledLayer(this , name, original);
512: this .addTiledLayer(layer);
513: return layer;
514: }
515:
516: public Sprite createSprite(String name,
517: ImageResource imageResource, int numberFrames,
518: int frameWidth, int frameHeight) {
519: assert (numberFrames >= 1);
520: if (!this .isComponentNameAvailable(name)) {
521: throw new IllegalArgumentException(
522: "Sprite cannot be created because component name '"
523: + name + "' already exists."); // NOI18N
524: }
525: Sprite sprite = new Sprite(this , name, imageResource,
526: numberFrames, frameWidth, frameHeight);
527: this .addSprite(sprite);
528: return sprite;
529: }
530:
531: public Sprite createSprite(String name,
532: ImageResource imageResource, Sequence defaultSequence) {
533: assert (defaultSequence != null);
534: if (!this .isComponentNameAvailable(name)) {
535: throw new IllegalArgumentException(
536: "Sprite cannot be created because component name '"
537: + name + "' already exists."); // NOI18N
538: }
539: Sprite sprite = new Sprite(this , name, imageResource,
540: defaultSequence);
541: this .addSprite(sprite);
542: return sprite;
543: }
544:
545: public String toString() {
546: return this .getName();
547: }
548:
549: public JComponent getEditor() {
550: //we will be able to keep a single editor once the GameDesignOverViewPanel implements listeners for
551: //scene, tiledlayer, and sprite so that it can redraw pewview components when changes occur
552: // if (this.editor == null) {
553: JPanel top = new JPanel(new BorderLayout());
554: top.setBackground(ColorConstants.COLOR_EDITOR_PANEL);
555: JScrollPane scroll = new JScrollPane();
556: scroll.setViewportView(new GameDesignOverViewPanel(this ));
557: scroll.getViewport().setBackground(Color.WHITE);
558: top.add(scroll, BorderLayout.CENTER);
559: this .editor = top;
560: // }
561: return this .editor;
562: }
563:
564: public ImageResourceInfo getImageResourceInfo() {
565: return null;
566: }
567:
568: public JComponent getNavigator() {
569: return this .navigator == null ? this .navigator = new GameDesignNavigator(
570: this )
571: : this .navigator;
572: }
573:
574: public String getName() {
575: return NbBundle.getMessage(GlobalRepository.class,
576: "GlobalRepository.name");
577: }
578:
579: public List<Action> getActions() {
580: return Collections.EMPTY_LIST;
581: }
582:
583: public void addPropertyChangeListener(PropertyChangeListener l) {
584: }
585:
586: public void removePropertyChangeListener(PropertyChangeListener l) {
587: }
588:
589: }
|