Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: jcurses/widgets/Window.java


1   package jcurses.widgets;
2   
3   
4   import jcurses.event.WindowEvent;
5   import jcurses.event.WindowListener;
6   import jcurses.event.WindowListenerManager;
7   import jcurses.system.CharColor;
8   import jcurses.system.InputChar;
9   import jcurses.system.Toolkit;
10  import jcurses.util.Protocol;
11  import jcurses.util.Rectangle;
12  
13  import java.util.Collections;
14  import java.util.Comparator;
15  import java.util.Hashtable;
16  import java.util.Vector;
17  
18  /**
19  * This class is a jcurses implementation of an text based window. An window 
20  *  under jcurses is, differnt from other GUI libraries, not a widget, this 
21  *  contains a panel ( a the called root panel ), that contains all widgets.
22  *  A window can, but doesn't must, have a border and a title.
23  *  All windows under jcurses are managed in a stack, the topmost visible window
24  *  window on the stack gets all input chars for handling, this is so called focus
25  *  window. If an window are created, it gets automatically to the top of the stack
26  *  and leaves the until an other window is created or explicitly brought to the top.
27  *  
28  */
29  
30  public class Window {
31  
32    private Panel _root = null;
33    
34    private Vector _focusableChilds = null;
35    private int _currentIndex = -1;
36    
37    private boolean _visible = false;
38    
39    private Rectangle _rect = null;
40    
41    private boolean _border = false;
42    private String _title = null;
43    
44    private boolean _hasShadow = true;
45    
46    private Vector _shortCutsList = new Vector();
47    private Hashtable _shortCutsTable = new Hashtable();
48    
49    boolean _closed = false;
50    
51  
52    
53     /**
54     *  The constructor
55     * 
56     * @param x the the top left corner's x coordinate
57     * @param y the top left corner's y coordinate
58     * @param width window's width
59     * @param height window's height
60     * @param border true, if the window has a border, false in other case
61     */
62    public Window (int x, int y, int width, int height, boolean border, String title) {
63      _border = border;
64      _title = title;
65      _rect = new Rectangle(width, height);
66      _rect.setLocation(x, y);
67      
68      int x1 = border?x+1:x;
69      int y1 = border?y+1:y;
70      int w = border?width-2:width;
71      int h = border?height-2:height;
72      
73      _root = new Panel(w, h);
74      _root.setSize(new Rectangle(w, h));
75      _root.setX(x1);
76      _root.setY(y1);
77      _root.setWindow(this);
78      WindowManager.createWindow(this);
79    }
80    
81    
82     /**
83     *  The constructor. A window created with this constructor is centered on the screen.
84     *
85     * @param width window's width
86     * @param height window's height
87     * @param border true, if the window has a border, false in other case
88     */
89    public Window (int width, int height, boolean border, String title) {
90      this((Toolkit.getScreenWidth()-width)/2,(Toolkit.getScreenHeight()-height)/2, width, height, border, title); 
91    }
92    
93    
94    private void configureRootPanel() {
95      if (_root == null) {
96        _root = new Panel();
97      }
98      
99      int x = _rect.getX();
100     int y = _rect.getY();
101     int width = _rect.getWidth();
102     int height = _rect.getHeight();
103     
104     int x1 = _border?x+1:x;
105     int y1 = _border?y+1:y;
106     int w =  _border?width-2:width;
107     int h =  _border?height-2:height;
108     
109     _root.setSize(new Rectangle(w, h));
110     _root.setX(x1);
111     _root.setY(y1);
112     
113   }
114   
115   
116   /**
117   *  The method shows the window
118   */
119   public void show() {
120     setVisible(true);
121   }
122   
123   /**
124   *  The method hides the window
125   */
126   
127   public void hide() {
128     setVisible(false);
129   }
130   
131   
132   /**
133   * The method changes the window's visibility status
134     * 
135     * @param value true, if the window becomes visible, false in other case
136   */
137   
138   public void setVisible(boolean value){
139     Window oldTop = WindowManager.getTopWindow();
140     if (value) {
141       pack();
142       _visible = value;
143       WindowManager.makeWindowVisible(this, oldTop);
144     } else {
145       _visible = value;
146       WindowManager.makeWindowInvisible(this, oldTop);
147     }
148   }
149   
150   
151     /**
152     *  The method returns the window's visibility status
153     * @return true, if the window becomes visible, false in other case
154     */
155   public boolean isVisible() {
156     return _visible;
157   }
158   
159     /**
160     *  The method paint's the window
161     */
162   
163   protected void paint() {
164     drawThingsIfNeeded();
165     _root.paint();
166   }
167   
168     
169     /**
170     *  Currently the method makes the same as repaint, in next versions the method
171     * will repaint only the part of the window, that was hided.
172     */
173   
174   protected void repaint() {
175     drawThingsIfNeeded();
176     _root.repaint();
177   }
178   
179   /**
180   *  @return the rectangle occupied by the window
181   */
182   
183   protected Rectangle getRectangle() {
184     return _rect;
185   }
186   
187   /**
188   *  The method closed the window, that is removes it from window stack an
189     *  evantually from screen, if it was visible. 
190   */
191   
192   public void close() {
193     WindowManager.removeWindow(this);
194   }
195     
196   
197   /**
198   * The method moves the window to the top of the stack
199   */
200   
201   public void moveToTheTop() {
202     WindowManager.moveToTop(this);
203   }
204   
205   /**
206   *  Folgende Methoden bestimmen das zeichen das benutzt wird, um das Fenster zu schließen
207   */
208   
209   private static InputChar __defaultClosingChar = new InputChar(27);//escape character
210   private InputChar  _closingChar = getDefaultClosingChar();
211   
212   
213   private InputChar getDefaultClosingChar() {
214     return __defaultClosingChar;
215   }
216   
217   
218     /**
219     *  The method returns the character to close window. 
220     * As default is escape characted defined
221     * 
222     * @return window's closing character
223     */
224   public InputChar getClosingChar() {
225     return _closingChar;
226   }
227   
228   
229   
230     /**
231     *  The method defines a new window's closing character. Default is escape.
232     * @param character new  window's closing character
233     */
234   public void setClosingChar(InputChar character) {
235      _closingChar = character;
236   }
237   
238   
239   
240   private static InputChar __defaultFocusChangeChar = new InputChar('\t');//tab character
241   private InputChar  _focusChangeChar = getDefaultFocusChangeChar();
242   
243   
244   private InputChar getDefaultFocusChangeChar() {
245     return __defaultFocusChangeChar;
246   }
247   
248   /**
249   *  The method returns the charater used to navigate (change the focus) between widgets
250     * within the window. Default is 'tab'
251     * 
252     * @return window's focus changing charater
253   */
254   public InputChar getFocusChangeChar() {
255     return _focusChangeChar;
256   }
257   
258   
259   /**
260   *  The method defined the charater used to navigate (change the focus) between widgets
261     * within the window. Default is 'tab'
262     * 
263     * @param character new window's focus changing charater
264   */
265   public void setFocusChangeChar(InputChar character) {
266      _focusChangeChar = character;
267   }
268   
269   /**
270   *  Behandlung der Eingabe. 
271   *  Vier mögliche Fälle:
272   *  1. Fenster schliessen.
273   *  2. Zum nächsten Widget springen.
274   *  3. Shortcut bearbeiten.
275   *  3. Eingabe vom aktuell Fokus habenden Kind bearbeiten lassen. 
276   */
277   
278   
279   private boolean isShortCut(InputChar inp) {
280     return (_shortCutsList.indexOf(inp)!=-1);
281   }
282   
283   
284   private Widget getWidgetByShortCut(InputChar inp) {
285     return (Widget)_shortCutsTable.get(inp);
286   }
287   
288   
289   private static InputChar __upChar = new InputChar(InputChar.KEY_UP);
290   private static InputChar __downChar = new InputChar(InputChar.KEY_DOWN);
291   private static InputChar __leftChar = new InputChar(InputChar.KEY_LEFT);
292   private static InputChar __rightChar = new InputChar(InputChar.KEY_RIGHT);
293   
294   /**
295   *  The method tries to close the window, after the user has typed 'escape' 
296     * or an other closing character. The procedure is as following:
297     * If the window has listeners, than an event is sent to the listeners. The window
298     * can be closed bei listeners. Did'nt listeners close the window, in leaves open.
299     * Has the window no listeners, than the method closes it.
300     * 
301   */
302   
303   public boolean tryToClose() {
304     if (_listenerManager.countListeners() > 0) {
305       _listenerManager.handleEvent(new WindowEvent(this, WindowEvent.CLOSING));
306       return isClosed();
307     } else {
308       close();
309       return true;
310     }
311   }
312   
313     
314     /**
315     *  @return true, if the window is already closed, false in othe case.
316     */
317   
318   public boolean isClosed() {
319     return _closed;
320   }
321   
322   
323     /**
324     *  The method is called by the libray to handle an input character, if the window has the focus.
325     */
326   protected void handleInput(InputChar inp) {
327     if (inp.equals(getClosingChar())) {
328       tryToClose();
329     }  else if (inp.equals(getFocusChangeChar())) {
330        changeFocus();
331     }  else if (inp.equals(__upChar)) {
332        Widget cur = getCurrentWidget();
333        if (cur != null) {
334            boolean result = cur.handleInput(inp);
335         if (!result) {
336          changeFocus(2);  
337         }  
338        }
339     }  else if (inp.equals(__downChar)) {
340        Widget cur = getCurrentWidget();
341        if (cur != null) {
342            boolean result = cur.handleInput(inp);
343         if (!result) {
344          changeFocus(3);  
345         }  
346        }
347     }  else if (inp.equals(__leftChar)) {
348        Widget cur = getCurrentWidget();
349        if (cur != null) {
350            boolean result = cur.handleInput(inp);
351         if (!result) {
352          changeFocus(0);  
353         }  
354        }
355     }  else if (inp.equals(__rightChar)) {
356        Widget cur = getCurrentWidget();
357        if (cur != null) {
358            boolean result = cur.handleInput(inp);
359         if (!result) {
360          changeFocus(1);  
361         }  
362        }
363     } else if (isShortCut(inp)) {
364       Widget cur = getCurrentWidget();
365       if  (cur!=null) {
366         boolean result = cur.handleInput(inp);
367         if (!result) {
368           getWidgetByShortCut(inp).handleInput(inp);  
369         }
370       }
371     }  else {
372       if (!handleInputByCurrentChild(inp)) {
373         onChar(inp);
374       } 
375     }
376   }
377   
378   
379   /**
380   * The method is called by <code>handleInput</code>, if no widget has handled
381     * the input. Derived classes can override the method to define additional shortcuts.
382   */
383   
384   protected void onChar(InputChar inp) {
385     //default nothing
386   }
387   
388   
389   private void changeFocus() {
390     if (_currentIndex != -1) {
391       int newIndex = (_currentIndex == (_focusableChilds.size()-1))?0:(_currentIndex+1);
392       if (newIndex!=_currentIndex) {
393         ((Widget)_focusableChilds.elementAt(_currentIndex)).setFocus(false);
394         ((Widget)_focusableChilds.elementAt(newIndex)).setFocus(true);
395         _currentIndex = newIndex;
396       }
397     } 
398   }
399   
400   
401   private void changeFocus(int direction) {
402     if (_currentIndex != -1) {
403       changeFocus(getNextWidget(direction));
404     }
405   }
406   
407   
408   
409   private Widget getNextWidget(int direction) { 
410     Widget result = getCurrentWidget();
411     Widget current = getCurrentWidget();
412     int x = result.getAbsoluteX();
413     int y = result.getAbsoluteY();
414     int searchDirection = ((direction == 0) || (direction == 2))?-1:1;
415     
416     Vector widgets = _focusableChilds;
417     int index = widgets.indexOf(result);
418     if (index < 0) {
419       throw new RuntimeException("widget in the sorted queue not found!!");
420     }
421     
422     int distance = Integer.MAX_VALUE; 
423     while (index < widgets.size() && index > -1)  {
424       index+=searchDirection;
425       if (index < widgets.size() && index > -1) {
426         Widget candidate = (Widget)widgets.get(index);
427         if (((direction == 0) && WindowWidgetComparator.toTheLeftOf(candidate, current)) ||
428           ((direction == 1) && WindowWidgetComparator.toTheRightOf(candidate, current)) ||
429           ((direction == 2) && WindowWidgetComparator.atTheTopOf(candidate, current)) ||
430           ((direction == 3) && WindowWidgetComparator.atTheBottomOf(candidate, current))) {
431           int newDistance = WindowWidgetComparator.getDistance(candidate, current);
432           if (newDistance < distance) {
433             distance = newDistance;
434             result = candidate;
435           }
436         }
437       }
438         
439     }
440     
441     return result;
442     
443   }
444   
445   
446   
447   
448   void changeFocus(Widget widget) {
449     int newIndex = _focusableChilds.indexOf(widget);
450     if (newIndex!=-1) {
451       if (_currentIndex == -1) {
452         widget.setFocus(true);
453         _currentIndex = newIndex;
454       } else if (_currentIndex == newIndex) {
455       } else {
456         widget.setFocus(true);
457         ((Widget)_focusableChilds.elementAt(_currentIndex)).setFocus(false);
458          _currentIndex = newIndex;
459       }
460         
461     }
462   }
463   
464   
465   private Widget getCurrentWidget() {
466     if (_currentIndex != -1) {
467       return  ((Widget)_focusableChilds.elementAt(_currentIndex));
468     } else {
469       return null;
470     }
471   }
472   
473   private boolean handleInputByCurrentChild(InputChar inp) {
474     if (_currentIndex != -1) {
475       return ((Widget)_focusableChilds.elementAt(_currentIndex)).handleInput(inp);
476     } 
477     
478     return false;
479   }
480   
481   
482   
483   private void loadShortcuts() {
484     _shortCutsList.clear();
485     _shortCutsTable.clear();
486     
487     Vector list = _root.getListOfWidgetsWithShortCuts();
488     for (int i=0; i<list.size(); i++) {
489       Widget widget = (Widget)list.elementAt(i);
490       Vector shortCuts = widget.getShortCutsList();
491       _shortCutsList.addAll(shortCuts);
492       for (int j=0; j< shortCuts.size(); j++) {
493         _shortCutsTable.put(shortCuts.elementAt(j), widget);
494       }
495     }
496     
497   }
498   
499   private void loadFocusableChilds() {
500     _focusableChilds = _root.getListOfFocusables();
501     if (_focusableChilds.size() == 0) {
502       _currentIndex = -1;
503     } else {
504       Collections.sort(_focusableChilds, new WindowWidgetComparator());
505       _currentIndex = 0;
506       ((Widget)_focusableChilds.elementAt(0)).setFocus(true);
507     }
508   }
509   
510   
511     /**
512     *  The method computes new window's layout.
513   *  The method must already be called, if anything on the window building
514   *  is changed, for example, an widget is removed or isn't more focusable
515   * ( because not visible or other ).
516     */
517   public void pack() {
518     cutIfNeeded();
519     configureRootPanel();
520     _root.pack();
521     loadFocusableChilds();
522     loadShortcuts();
523     
524   }
525   
526   
527   private void cutIfNeeded() {
528     int maxWidth = Toolkit.getScreenWidth()-_rect.getX()-(_hasShadow?1:0);
529     int maxHeight = Toolkit.getScreenHeight()-_rect.getY()-(_hasShadow?1:0);
530     
531       
532     if (_rect.getWidth() > maxWidth) {
533       _rect.setWidth(maxWidth);
534     }
535     
536     if (_rect.getHeight() > maxHeight) {
537       _rect.setHeight(maxHeight);
538     }
539     
540   
541     
542   }
543   
544   
545   
546     /**
547     *  @return the root panel of the window
548     */
549   public Panel getRootPanel() {
550     //Ein kommentar
551     return _root;
552   }
553   
554     
555     /**
556     *  Sets the root panel of the window. This is the top most widget container in the 
557     *  window's widget hierarchy. It occupies the entire window out of the border (if exists ).
558     */
559   
560   public void setRootPanel(Panel root) {
561     _root = root;  
562     _root.setWindow(this);
563   }
564   
565   
566   private void drawThingsIfNeeded() {
567     if (_border) {
568       Toolkit.drawBorder(_rect, getBorderColors());
569     }
570     
571     paintTitle();
572     
573     if (hasShadow()) {
574       Toolkit.drawRectangle(_rect.getX()+_rect.getWidth(),
575                   _rect.getY()+1,
576                   1,
577                   _rect.getHeight(), getShadowColors());
578       Toolkit.drawRectangle(_rect.getX()+1,
579                   _rect.getY()+_rect.getHeight(),
580                   _rect.getWidth(),
581                   1, getShadowColors());
582                     
583     }
584   }
585   
586   
587   private void paintTitle() {
588     if (_title!=null) {
589       CharColor color = getTitleColors();
590       Toolkit.printString( _title, _rect.getX()+(_rect.getWidth()-_title.length())/2,_rect.getY(), color);
591     }
592   }
593   
594   
595   
596   private static CharColor __defaultBorderColors = new CharColor(CharColor.WHITE, CharColor.BLACK);
597   private CharColor _borderColors = getDefaultBorderColors();
598   
599   public CharColor getDefaultBorderColors() {
600     return __defaultBorderColors;
601   }
602   
603   
604   public CharColor getBorderColors() {
605     return _borderColors;
606   }
607   
608   
609   public void setBorderColors(CharColor colors) {
610     _borderColors = colors;
611   }
612   
613   /**
614   *  Normaler title
615   */
616   
617   
618   private static CharColor __defaultTitleColors = new CharColor(CharColor.WHITE, CharColor.RED);
619   private CharColor _titleColors = getDefaultTitleColors();
620   
621   public CharColor getDefaultTitleColors() {
622     return __defaultTitleColors;
623   }
624   
625   
626   public CharColor getTitleColors() {
627     return _titleColors;
628   }
629   
630   
631   public void setTitleColors(CharColor colors) {
632     _titleColors = colors;
633   }
634   
635   /**
636   * The method defines, whether the window is to paint with a shadow
637     * 
638     * @param value true if a shadow is to paint, false in othe case
639   */
640   public void setShadow(boolean value) {
641     _hasShadow=value;
642   }
643   
644   
645   boolean hasShadow() {
646     return _hasShadow;
647   }
648   
649   
650   private static CharColor __shadowColors = new CharColor(CharColor.BLACK, CharColor.BLACK);
651   
652   private CharColor getShadowColors() {
653     return __shadowColors;
654   }
655   
656   
657   //Listener-Zeugs
658   
659   private WindowListenerManager _listenerManager = new WindowListenerManager();
660   
661   /**
662   *  The method adds a listener to the window
663     * 
664     * @param listener the listener to add
665   */
666   public void addListener(WindowListener listener) {
667     _listenerManager.addListener(listener);
668   }
669   
670   
671     /**
672   *  The method remove a listener from the window
673     * 
674     * @param listener the listener to remove
675   */
676   public void removeListener(WindowListener listener) {
677     _listenerManager.removeListener(listener);
678   }
679   
680   
681     /**
682     *  The method is called, if the window gets focus.
683     */
684   protected void activate() {
685     _listenerManager.handleEvent(new WindowEvent(this, WindowEvent.ACTIVATED));
686   }
687   
688   
689     /**
690     *  The method is called, if the window loses focus.
691     */
692   protected void deactivate() {
693     _listenerManager.handleEvent(new WindowEvent(this, WindowEvent.DEACTIVATED));
694   }
695   
696   /**
697     *  The method is called, if the window is closed.
698     */
699   protected void closed() {
700     _closed = true;
701     _listenerManager.handleEvent(new WindowEvent(this, WindowEvent.CLOSED));
702   }
703   
704   
705    
706   protected void resize(int width, int height) {
707     _rect.setWidth(width);
708     _rect.setHeight(height);
709   }
710   
711   
712   
713   
714   
715   
716   
717   
718   
719   
720   
721 
722 }
723 
724 
725 class WindowWidgetComparator implements Comparator {
726   
727   
728   
729   // methods to compare widget positions
730   static boolean toTheLeftOf(Widget widget1, Widget widget2) {
731     Rectangle rect1 = widget1.getRectangle();
732     Rectangle rect2 = widget2.getRectangle();
733     boolean result = ((rect1.getX()+rect1.getWidth()-1) < rect2.getX());
734     return result; 
735   }
736   
737 
738   static boolean toTheRightOf(Widget widget1, Widget widget2) {
739     Rectangle rect1 = widget1.getRectangle();
740     Rectangle rect2 = widget2.getRectangle();
741     boolean result = ((rect1.getX()) > (rect2.getX()+rect2.getWidth()-1)); 
742     return  result;
743   }
744   
745   static boolean atTheTopOf(Widget widget1, Widget widget2) {
746     Rectangle rect1 = widget1.getRectangle();
747     Rectangle rect2 = widget2.getRectangle();
748     boolean result = ((rect1.getY()+rect1.getHeight()-1) < rect2.getY()); 
749     return result;
750   }
751   
752   static boolean atTheBottomOf(Widget widget1, Widget widget2) {
753     Rectangle rect1 = widget1.getRectangle();
754     Rectangle rect2 = widget2.getRectangle();
755     boolean result = ((rect1.getY()) > (rect2.getY()+rect2.getHeight()-1)); 
756     return  result;
757   }
758   
759   static int getDistance(Widget widget1, Widget widget2) {
760     Rectangle rect1 = widget1.getRectangle();
761     Rectangle rect2 = widget2.getRectangle();
762     int x1 = rect1.getX()+(rect1.getWidth()/2);
763     int y1 = rect1.getY()+(rect1.getHeight()/2);
764     int x2 = rect2.getX()+(rect2.getWidth()/2);
765     int y2 = rect2.getY()+(rect2.getHeight()/2);
766     
767     return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
768     
769   }
770   
771   
772   public int compare(Object obj1, Object obj2) {
773     if ((!(obj1 instanceof Widget)) || (!(obj2 instanceof Widget))) {
774       throw new RuntimeException("unknown classes to compare");
775     }
776     
777     Widget widget1 = (Widget)obj1;
778     Widget widget2 = (Widget)obj2;
779     
780     int result = 0;
781     
782     if (atTheTopOf(widget1, widget2)) {
783       result = -1;
784     } else if  (atTheBottomOf(widget1, widget2)) {
785       result = 1;
786     } else {
787       if (toTheLeftOf(widget1, widget2)) {
788         result = -1;
789       } else if (toTheRightOf(widget1, widget2)) {
790         result = 1;
791       } else {
792         result = 0;
793       }
794     }
795     
796     
797     return result;
798     
799   }
800   
801 }