View Javadoc

1   /* $Id: World2DPopupMenuListener.java 32 2013-05-04 13:29:36Z mihlon $ */
2   
3   //////////////////////////////////////////////////////////////////////////////
4   //                                                                          //
5   //   This program is free software: you can redistribute it and/or modify   //
6   //   it under the terms of the GNU General Public License as published by   //
7   //   the Free Software Foundation, either version 3 of the License, or      //
8   //   at your option any later version.                                      //
9   //                                                                          //
10  //   This program is distributed in the hope that it will be useful,        //
11  //   but WITHOUT ANY WARRANTY; without even the implied warranty of         //
12  //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          //
13  //   GNU General Public License for more details.                           //
14  //                                                                          //
15  //   You should have received a copy of the GNU General Public License      //
16  //   along with this program.  If not, see <http://www.gnu.org/licenses/>.  //
17  //                                                                          //
18  //////////////////////////////////////////////////////////////////////////////
19  
20  package cs.pancava.caltha.menu;
21  
22  import cs.pancava.caltha.Editor;
23  import cs.pancava.caltha.MainMenu;
24  import cs.pancava.caltha.graphics.EditorGraphicsWorld2D;
25  import cs.pancava.caltha.worlds.GameEntity;
26  import cs.pancava.caltha.worlds.Room;
27  import cs.pancava.caltha.worlds.Route;
28  import java.awt.Dimension;
29  import java.awt.Rectangle;
30  import java.awt.event.ActionEvent;
31  import java.awt.event.ActionListener;
32  import java.awt.event.MouseAdapter;
33  import java.awt.event.MouseEvent;
34  import javax.swing.JMenuItem;
35  import javax.swing.JPopupMenu;
36  
37  /**
38   * <p><b>Tato trida definuje popup menu pro ovladani editoru pro tvorbu 2D svetu.</b></p>
39   *
40   * @author Milan Vaclavik<br />
41   * @version $Revision: 32 $<br />
42   * $LastChangedBy: mihlon $<br />
43   */
44  public class World2DPopupMenuListener extends MouseAdapter
45  {
46      /**
47       * Hlavni popup menu editoru.
48       */
49      private static JPopupMenu popupMenu;
50          /**
51           * Nabidka popup menu - Pridat mistnost.
52           */
53          private static JMenuItem addRoomIM;
54          /**
55           * Nabidka popup menu - Spojit propojit mistnosti.
56           */
57          private static JMenuItem connectRoomIM;
58          /**
59           * Nabidka popup menu - Odstranit mistnost.
60           */
61          private static JMenuItem removeRoomIM;
62          /**
63           * Mab9dka popum menu - Rozpojeni propojeni mistnosti.
64           */
65          private static JMenuItem disconnectRoomIM;
66  
67      /**
68       * X-ova souradnice mysi v dobe stisku tlacitka mysi.
69       */
70      private int mouseX;
71  
72      /**
73       * Y-ova souradnice mysi v dobe stisku tlacitka mysi.
74       */
75      private int mouseY;
76  
77      /**
78       * Velikost zobrazovane mistnosti.
79       *
80       * TODO: Mozno nastavovat velikost primo v editoru a nastavenou hodnotu ukladat do konfiguracniho souboru.
81       */
82      private final int ROOM_SIZE = 50;
83  
84      /**
85       * Reference na tridu, ktera umoznuje prekreslit graficke objekty.
86       */
87      private EditorGraphicsWorld2D editorGraphicsWorld2D;
88  
89      /**
90       * Vzhledem k tomu, ze zobrazovane popup menu orizne nove vytvoreny graficky objekt,
91       * tak je treba vyvolat graficke prekresleni grafickych objektu, ktere obnovi oriznuty objekt.
92       * @param graphicsWorld2D EditorGraphicsWorld2D : Reference na tridu, ktera umoznuje prekreslit graficke objekty.
93       */
94      public World2DPopupMenuListener(final EditorGraphicsWorld2D graphicsWorld2D)
95      {
96          this.editorGraphicsWorld2D = graphicsWorld2D;
97  
98          World2DPopupMenuListener.popupMenu = new JPopupMenu();
99  
100         this.createItemMenuAddRoom();
101         this.createItemMenuConnectRoom();
102         this.createItemMenuRemoveRoom();
103         this.createItemMenuDisconnectRoom();
104     }
105 
106     /**
107      * Volano pri zmene jazyka - lokalizace.
108      */
109     public static void updateText()
110     {
111         if (World2DPopupMenuListener.addRoomIM != null)
112         {
113             World2DPopupMenuListener.addRoomIM.setText(Editor.getResourcesBundleString("cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuAddRoom_addRoomIM"));
114             MainMenu.updateTextTipMenuItem(World2DPopupMenuListener.addRoomIM, "cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuAddRoom_addRoomIM_tip");
115         }
116 
117         if (World2DPopupMenuListener.connectRoomIM != null)
118         {
119             World2DPopupMenuListener.connectRoomIM.setText(Editor.getResourcesBundleString("cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuConnectRoom_connectRoomIM"));
120             MainMenu.updateTextTipMenuItem(World2DPopupMenuListener.connectRoomIM, "cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuConnectRoom_connectRoomIM_tip");
121         }
122 
123         if  (World2DPopupMenuListener.removeRoomIM != null)
124         {
125             World2DPopupMenuListener.removeRoomIM.setText(Editor.getResourcesBundleString("cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuRemoveRoom_removeRoomIM"));
126             MainMenu.updateTextTipMenuItem(World2DPopupMenuListener.removeRoomIM, "cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuRemoveRoom_removeRoomIM_tip");
127         }
128 
129         if  (World2DPopupMenuListener.disconnectRoomIM != null)
130         {
131             World2DPopupMenuListener.disconnectRoomIM.setText(Editor.getResourcesBundleString("cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuDisconnectRoom_disconnectRoomIM"));
132             MainMenu.updateTextTipMenuItem(World2DPopupMenuListener.disconnectRoomIM, "cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuDisconnectRoom_disconnectRoomIM_tip");
133         }
134     }
135 
136     /**
137      * Prida na danou pozici mistnost v hernim svete.
138      * @param x : X-ova souradice umisteni mistnosti.
139      * @param y : Y-ova souradice umisteni mistnosti.
140      */
141     private void addRoom(final int x, final int y)
142     {
143         final GameEntity tmpRoom2 = new Room(x, y, this.ROOM_SIZE);
144         GameEntity tmpRoom1 = null;
145 
146         // TODO: Vyhledavani by slo optimalizovat tim, ze by jsme meli promennou, ktera by si pamatovala naposledy oznaceny objekt.
147         // TODO: Tim by se mozna vyresil i ten problem, kdy mohlo byt vice oznacenych mistnosti a proto bych nemusel vzdy preventivne mazat
148         // uplne vsechmy mistnosti.
149         for (GameEntity ge : Editor.getEditorDesktop().getWorld().getWorldRoomsAL())
150         {
151             if (ge.isSeleted())
152             {
153                 // Nalezli jsme oznacenou mistnost, proto vytvorime spoj mezi
154                 // touto a nove vytvorenou mistnosti.
155                 tmpRoom1 = ge;
156 
157                 // Ukoncime hledani, jelikoz je vzdy jen jedna mistnost oznacena.
158                 //return;
159             }
160         }
161 
162         Editor.getEditorDesktop().getWorld().addGameEntity(tmpRoom2);
163 
164         if (tmpRoom1 != null)
165         {
166             // Nema cenu vytvaret spoj mezi dvema objekty, kdyz jeden z nich neexistuje
167             Editor.getEditorDesktop().getWorld().addGameEntity(new Route(tmpRoom1, tmpRoom2));
168         }
169     }
170 
171     /**
172      * Zajisti pripadne propojeni dvou mistnosti.
173      */
174     private void connectRoom()
175     {
176         this.editorGraphicsWorld2D.setConnectRoom(true);
177     }
178 
179     /**
180      * Vytvori koncovou polozku menu - Pridat mistnost.
181      */
182     private void createItemMenuAddRoom()
183     {
184         World2DPopupMenuListener.addRoomIM = MainMenu.addMenuItem("cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuAddRoom_addRoomIM",
185                                                                   "cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuAddRoom_addRoomIM_tip",
186                                                                   true);
187 
188         World2DPopupMenuListener.addRoomIM.addActionListener(new ActionListener()
189         {
190             @Override
191             public void actionPerformed(final ActionEvent e)
192             {
193                 // TODO: Vsechmy metody uvnitr metody actionPerformed by meli byt mimo tuto tridu !
194                 //       Asi by idealne meli byt ve tride: EditorGraphicsWorld2D
195                 //       Je treba oddelit grafickou cast od vykonne casti !
196                 //       Dale se tu nejspis resi metody, ktere do teto tridy nepatri !
197                 addRoom(mouseX, mouseY);
198 
199                 // Nove vytvoreny graficky obekt je oriznut diky popup menu.
200                 // Proto je nutne opetovne prekresleni !
201                 editorGraphicsWorld2D.repaint();
202 
203                 // Test, zda-li je treba rozsirit plochu (kreslici oblast) vytvareni sveta.
204                 expandGraphicsWorld2DArea();
205 
206                 // Test, zda-li je treba posunout s viditelnou oblasti plochy pri vytvoreni noveho objektu,
207                 // aby byl nove vytvoreny objekt viditelny
208                 moveVisibleArea();                
209             }
210         });
211         World2DPopupMenuListener.popupMenu.add(World2DPopupMenuListener.addRoomIM);
212     }
213 
214     /**
215      * Vytvori koncovou polozku menu - Spojit mistnosti.
216      */
217     private void createItemMenuConnectRoom()
218     {
219         World2DPopupMenuListener.connectRoomIM = MainMenu.addMenuItem("cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuConnectRoom_connectRoomIM",
220                                                                       "cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuConnectRoom_connectRoomIM_tip",
221                                                                       false);
222 
223         World2DPopupMenuListener.connectRoomIM.addActionListener(new ActionListener()
224         {
225             @Override
226             public void actionPerformed(final ActionEvent e)
227             {
228                 // TODO: Vsechmy metody uvnitr metody actionPerformed by meli byt mimo tuto tridu !
229                 //       Asi by idealne meli byt ve tride: EditorGraphicsWorld2D
230                 //       Je treba oddelit grafickou cast od vykonne casti !
231                 //       Dale se tu nejspis resi metody, ktere do teto tridy nepatri !
232                 connectRoom();
233 
234                 // Nove vytvoreny graficky obekt je oriznut diky popup menu.
235                 // Proto je nutne opetovne prekresleni !
236                 editorGraphicsWorld2D.repaint();
237             }
238         });
239         World2DPopupMenuListener.popupMenu.add(World2DPopupMenuListener.connectRoomIM);
240     }
241 
242     /**
243      * Vytvori koncovou polozku menu - Rozpojit mistnosti.
244      */
245     private void createItemMenuDisconnectRoom()
246     {
247         World2DPopupMenuListener.disconnectRoomIM = MainMenu.addMenuItem("cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuDisconnectRoom_disconnectRoomIM",
248                                                                          "cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuDisconnectRoom_disconnectRoomIM_tip",
249                                                                          false);
250 
251         World2DPopupMenuListener.disconnectRoomIM.addActionListener(new ActionListener()
252         {
253             @Override
254             public void actionPerformed(final ActionEvent e)
255             {
256                 // TODO: Vsechmy metody uvnitr metody actionPerformed by meli byt mimo tuto tridu !
257                 //       Asi by idealne meli byt ve tride: EditorGraphicsWorld2D
258                 //       Je treba oddelit grafickou cast od vykonne casti !
259                 //       Dale se tu nejspis resi metody, ktere do teto tridy nepatri !
260                 disconnectRoom();
261 
262                 // Nove vytvoreny graficky obekt je oriznut diky popup menu.
263                 // Proto je nutne opetovne prekresleni !
264                 editorGraphicsWorld2D.repaint();
265             }
266         });
267         World2DPopupMenuListener.popupMenu.add(World2DPopupMenuListener.disconnectRoomIM);
268     }
269 
270     /**
271      * Vytvori koncovou polozku menu - Odtranit mistnost.
272      */
273     private void createItemMenuRemoveRoom()
274     {
275         World2DPopupMenuListener.removeRoomIM = MainMenu.addMenuItem("cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuRemoveRoom_removeRoomIM",
276                                                                      "cs.pancava.caltha.menu.World2DPopupMenuListener-createItemMenuRemoveRoom_removeRoomIM_tip",
277                                                                      true);
278 
279         World2DPopupMenuListener.removeRoomIM.addActionListener(new ActionListener()
280         {
281             @Override
282             public void actionPerformed(final ActionEvent e)
283             {
284                 // TODO: Vsechmy metody uvnitr metody actionPerformed by meli byt mimo tuto tridu !
285                 //       Asi by idealne meli byt ve tride: EditorGraphicsWorld2D
286                 //       Je treba oddelit grafickou cast od vykonne casti !
287                 //       Dale se tu nejspis resi metody, ktere do teto tridy nepatri !
288                 removeRoom();
289 
290                 // Nove vytvoreny graficky obekt je oriznut diky popup menu.
291                 // Proto je nutne opetovne prekresleni !
292                 editorGraphicsWorld2D.repaint();
293             }
294         });
295         World2DPopupMenuListener.popupMenu.add(World2DPopupMenuListener.removeRoomIM);
296     }
297 
298     /**
299      * Zajisti pripadne rozpojeni dvou mistnosti.
300      */
301     private void disconnectRoom()
302     {
303         this.editorGraphicsWorld2D.setDisconnectRoom(true);
304     }
305 
306     /**
307      * Metoda testuje, zda-li jsme vytvotili novy objekt na samem kraji kreslici oblasti.
308      * Pokud ano, tak zvetsime kreslici oblast.
309      * Pokud ne, nic dalsiho delat nebudem.
310      */
311     private void expandGraphicsWorld2DArea()
312     {
313         // Ziskani aktualni velikosti kreslici plochy
314         Dimension tmpDimension = editorGraphicsWorld2D.getPreferredSize();
315 
316         // Urcuje, zda-li jsme klikli do oblasti, ktera umoznuje rozsirit kreslici plochu
317         boolean scrollbarGrowingArea = false;
318                 
319         if (tmpDimension.width - editorGraphicsWorld2D.getScrollbarGrowingAreaX() < mouseX)
320         {
321             tmpDimension.setSize(tmpDimension.width + editorGraphicsWorld2D.getNewAreaX(), tmpDimension.height);
322             scrollbarGrowingArea = true;
323         }
324                 
325         if (tmpDimension.height - editorGraphicsWorld2D.getScrollbarGrowingAreaY() < mouseY)
326         {
327             tmpDimension.setSize(tmpDimension.width, tmpDimension.height + editorGraphicsWorld2D.getNewAreaY());
328             scrollbarGrowingArea = true;
329         }
330 
331         if (scrollbarGrowingArea)
332         {
333             // Doslo ke zmene velikosti kreslici plochy - musime nastavit novou hodnotu
334             editorGraphicsWorld2D.setPreferredSize(tmpDimension);
335             editorGraphicsWorld2D.revalidate();
336         }
337      }
338 
339     /**
340      * Jednorazova udalost mysi - Stisknuti tlacitka mysi.
341      * @param e MouseEvent
342      */
343     @Override
344     public final void mousePressed(final MouseEvent e)
345     {
346         // Pokud je nejaka mistnost vybrana, tak jsou dodatecne aktivovany nasledujici polozky popup menu.
347         // Jakmile neni zadna mistnost vybrana, tak se deaktivuji !
348         // FIXME: Jakmile dojde ke smazani nejake mistnosti, tak stale zustavaji nasleduji polozky aktivni v popup menu !
349         World2DPopupMenuListener.connectRoomIM.setEnabled(this.editorGraphicsWorld2D.getSelectedObject());
350         World2DPopupMenuListener.disconnectRoomIM.setEnabled(this.editorGraphicsWorld2D.getSelectedObject());
351 
352         this.maybeShowPopup(e);
353     }
354 
355     /**
356      * Jednorazova udalost mysi - Uvolneni tlacitka mysi.
357      * @param e MouseEvent
358      */
359     @Override
360     public final void mouseReleased(final MouseEvent e)
361     {
362         this.maybeShowPopup(e);
363     }
364 
365     /**
366      * Metoda testuje, zda-li jsme vytvotili novy objekt na kraji viditelne kreslici oblasti.
367      * Pokud ano, tak posuneme kreslici oblasti tak, aby byl videt cely nove vkladany objekt.
368      * Pokud ne, nic dalsiho delat nebudem.
369      */
370     private void moveVisibleArea()
371     {
372         Rectangle tmpVisibleArea = new Rectangle(editorGraphicsWorld2D.getVisibleRect());
373                 
374         if (tmpVisibleArea.x + ROOM_SIZE > mouseX)
375         {
376             editorGraphicsWorld2D.scrollRectToVisible(new Rectangle(tmpVisibleArea.x - ROOM_SIZE, tmpVisibleArea.y, tmpVisibleArea.width, tmpVisibleArea.height));
377             // Jelikoz jsme posunuli s viditelnou oblasti, musi se znovu nacist aktualni hodnota viditelne oblasti
378             tmpVisibleArea = new Rectangle(editorGraphicsWorld2D.getVisibleRect());
379         }
380                 
381         if (tmpVisibleArea.x + tmpVisibleArea.width - ROOM_SIZE < mouseX)
382         {
383             editorGraphicsWorld2D.scrollRectToVisible(new Rectangle(tmpVisibleArea.x + ROOM_SIZE, tmpVisibleArea.y, tmpVisibleArea.width, tmpVisibleArea.height));
384             tmpVisibleArea = new Rectangle(editorGraphicsWorld2D.getVisibleRect());
385         }
386                 
387         if (tmpVisibleArea.y + ROOM_SIZE > mouseY)
388         {
389             editorGraphicsWorld2D.scrollRectToVisible(new Rectangle(tmpVisibleArea.x, tmpVisibleArea.y - ROOM_SIZE, tmpVisibleArea.width, tmpVisibleArea.height));
390             tmpVisibleArea = new Rectangle(editorGraphicsWorld2D.getVisibleRect());
391         }
392                 
393         if (tmpVisibleArea.y + tmpVisibleArea.height - ROOM_SIZE < mouseY)
394         {
395             editorGraphicsWorld2D.scrollRectToVisible(new Rectangle(tmpVisibleArea.x, tmpVisibleArea.y + ROOM_SIZE, tmpVisibleArea.width, tmpVisibleArea.height));
396             // Jelikoz se uz vycerpaly vsechny moznosti (strany + rohy oblasti), tak neni treba znovu aktualizovat hodnotu tmpVisibleArea.
397         }
398     }
399     
400     /**
401      * Zobrazi popup menu na danych souradnicich mysi.
402      * @param e MouseEvent
403      */
404     private void maybeShowPopup(final MouseEvent e)
405     {
406         if (e.isPopupTrigger())
407         {
408             this.mouseX = e.getX();
409             this.mouseY = e.getY();
410 
411             World2DPopupMenuListener.popupMenu.show(e.getComponent(), e.getX(), e.getY());
412         }
413     }
414 
415     /**
416      * Zajisti pripadne odstraneni mistnosti.
417      */
418     private void removeRoom()
419     {
420         this.editorGraphicsWorld2D.setRemoveRoom(true);
421     }
422 }