Source code: com/yaftp/utils/ExtendedDesktopPane.java
1 /**
2 *
3 * CopyRights Jean-Yves MENGANT 1999,2000,2001,2002
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or 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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 package com.yaftp.utils ;
20
21 import javax.swing.*;
22 import java.awt.*;
23 import java.awt.event.*;
24
25 /**
26
27 this components simulates a MDI like framework
28
29 A desktop pane that supports tiling and cascading
30 NB : a null layoutManager is associated with this class ,
31 caller should be cautious since some of the algorithms used
32 inside suppose that the JDesktopPane is known
33
34 @author Jean-Yves MENGANT
35
36
37 */
38
39 public class ExtendedDesktopPane
40 extends JDesktopPane {
41
42 private final ImageIcon _TILE_ICON_ = new ImageIcon(
43 getClass().getResource("images/tiled.gif") ,
44 "tiled"
45 ) ;
46
47 private final ImageIcon _CASCADE_ICON_ = new ImageIcon(
48 getClass().getResource("images/cascade.gif") ,
49 "cascade"
50 ) ;
51
52 protected int nextX; // Next X position
53 protected int nextY; // Next Y position
54 protected int offsetX = DEFAULT_OFFSETX;
55 protected int offsetY = DEFAULT_OFFSETY;
56
57 protected static final int DEFAULT_OFFSETX = 24;
58 protected static final int DEFAULT_OFFSETY = 24;
59 protected static final int UNUSED_HEIGHT = 48;
60
61 /** defaulted to tile */
62 protected boolean _cascaded = false ;
63
64 /** used for debugging purposes if set to true */
65 private boolean _debug = false ;
66
67 private JFrame _parent ;
68
69 public void set_parent( JFrame parent )
70 { _parent = parent ; }
71
72 /**
73 provide a reasonable preffered size
74 */
75 public Dimension getPreferredSize()
76 { return new Dimension(400,200) ; }
77
78 /**
79 Layout all of the children of this container
80 so that they are cascaded.
81 */
82 public void cascadeAll()
83 {
84 Component[] comps = getComponents();
85 int count = comps.length;
86 nextX = 0;
87 nextY = 0;
88 for (int i = count - 1; i >= 0; i--)
89 {
90 Component comp = comps[i];
91 if (comp instanceof JInternalFrame && comp.isVisible())
92 cascade(comp);
93 }
94 }
95
96 /**
97 Layout all of the children of this container
98 so that they are tiled.
99 */
100 public void tileAll()
101 {
102 DesktopManager manager = getDesktopManager();
103 // No desktop manager - do nothing
104 if (manager == null)
105 return;
106
107 Component[] comps = getComponents();
108 Component comp;
109 int count = 0;
110 // Count and handle only the internal frames
111 for (int i = 0; i < comps.length; i++)
112 {
113 comp = comps[i];
114 if (comp instanceof JInternalFrame && comp.isVisible())
115 count++;
116 }
117 if (count != 0)
118 {
119 double root = Math.sqrt((double)count);
120 int rows = (int)root;
121 int columns = count/rows;
122 int spares = count - (columns * rows);
123 Dimension paneSize = getSize();
124 if ( _debug )
125 System.out.println("paneSize="+paneSize) ;
126 int columnWidth = paneSize.width/columns;
127 // We leave some space at the bottom that doesn't get covered
128 int availableHeight = paneSize.height - UNUSED_HEIGHT;
129 // int availableHeight = paneSize.height;
130 int mainHeight = availableHeight/rows;
131 int smallerHeight = availableHeight/(rows + 1);
132 int rowHeight = mainHeight;
133 int x = 0;
134 int y = 0;
135 int thisRow = rows;
136 int normalColumns = columns - spares;
137 for (int i = comps.length - 1; i >= 0; i--)
138 {
139 comp = comps[i];
140 if (comp instanceof JInternalFrame && comp.isVisible())
141 {
142 manager.setBoundsForFrame((JComponent)comp, x, y, columnWidth, rowHeight);
143 y += rowHeight;
144 if (--thisRow == 0)
145 {
146 // Filled the row
147 y = 0;
148 x += columnWidth;
149 // Switch to smaller rows if necessary
150 if (--normalColumns <= 0)
151 {
152 thisRow = rows + 1;
153 rowHeight = smallerHeight;
154 }
155 else
156 thisRow = rows;
157 }
158 }
159 }
160 }
161 }
162
163 /**
164 Place a component so that it is cascaded
165 relative to the previous one
166 */
167 protected void cascade(Component comp)
168 {
169 Dimension paneSize = getSize();
170 int targetWidth = 3 * paneSize.width/4;
171 int targetHeight = 3 * paneSize.height/4;
172 DesktopManager manager = getDesktopManager();
173 if (manager == null)
174 {
175 comp.setBounds(0, 0, targetWidth, targetHeight);
176 return;
177 }
178 if (nextX + targetWidth > paneSize.width ||
179 nextY + targetHeight > paneSize.height)
180 {
181 nextX = 0;
182 nextY = 0;
183 }
184
185 manager.setBoundsForFrame((JComponent)comp, nextX, nextY, targetWidth, targetHeight);
186 nextX += offsetX;
187 nextY += offsetY;
188 }
189
190 private void tileOrCascadeAll()
191 {
192 if ( _cascaded )
193 cascadeAll() ;
194 else
195 tileAll() ;
196 revalidate() ;
197 }
198
199 /*
200 add internal Frame in a thread safe way since this component
201 is not guaranteed to be invoked from the Swing Event thread
202 ( this is the case when an FTP document is requested through
203 the FTP data thread )
204 */
205 class _SWING_THREAD_SAFE_ADD_INTERNALFRAME_
206 extends Thread
207 {
208 private String _title ;
209 private Component _comp ;
210
211 public _SWING_THREAD_SAFE_ADD_INTERNALFRAME_( String title ,
212 Component comp
213 )
214 {
215 _title = title ;
216 _comp = comp ;
217 }
218
219 public void addComponent()
220 {
221 if ( _comp == null )
222 return ; // Os dependent editors send null Java component to this method
223 JInternalFrame frame = new JInternalFrame( _title , true , true , true , true ) ;
224
225 // this hardcoded preffered size is candidate for later improvements
226 int preferredWidth = _comp.getPreferredSize().width ;
227 int preferredHeight = _comp.getPreferredSize().height ;
228
229 frame.setPreferredSize( new Dimension( preferredWidth,preferredHeight) );
230 frame.getContentPane().setLayout( new GridLayout(1,1) ) ;
231 frame.getContentPane().add( _comp ) ;
232 frame.setVisible(true) ;
233
234 ExtendedDesktopPane.this.add( frame ) ;
235
236 Dimension currentSize = getSize() ;
237
238 if ( ( currentSize.width == 0 ) ||
239 ( currentSize.height == 0 )
240 )
241 {
242 //ExtendedDesktopPane.this.addNotify() ;
243 if ( _parent != null )
244 {
245 _parent.pack() ;
246 tileOrCascadeAll() ;
247 }
248 else
249 frame.setBounds( 0, 0 , preferredWidth , preferredHeight );
250 }
251 else
252 tileOrCascadeAll() ;
253 }
254
255 public void run()
256 {
257 if ( _debug )
258 System.out.println("thread safe add") ;
259 addComponent() ;
260 }
261
262 }
263
264 /**
265 build a new JInternalFrame with given panel
266 and add it to the current list
267 This is done in a Swing THREAD SAFE way
268
269 */
270 public void addComponent( String title ,
271 Component comp
272 )
273 {
274 _SWING_THREAD_SAFE_ADD_INTERNALFRAME_ t = new _SWING_THREAD_SAFE_ADD_INTERNALFRAME_(title,comp) ;
275 SwingUtilities.invokeLater( t ) ;
276 // t.addComponent() ;
277 }
278
279
280 class _TILE_FRAME_
281 implements ActionListener {
282 public void actionPerformed( ActionEvent e )
283 {
284 _cascaded = false ;
285 tileOrCascadeAll() ;
286 }
287 }
288
289 class _CASCADE_FRAME_
290 implements ActionListener {
291
292 public void actionPerformed( ActionEvent e )
293 {
294 _cascaded = true ;
295 tileOrCascadeAll() ;
296 }
297 }
298
299 class _TEST_DOCUMENT_
300 extends SwingEditorPanePanel
301 {
302 public _TEST_DOCUMENT_()
303 throws UtilsError
304 {
305 setEditorKit( SwingEditorPanePanel.HTML );
306 load("<H1>Hello world</H1>") ;
307 }
308 }
309
310 class _ADD_FRAME_ implements ActionListener {
311
312 public void actionPerformed( ActionEvent e )
313 {
314 try {
315 addComponent( "test panell" , new _TEST_DOCUMENT_() ) ;
316 } catch ( UtilsError f )
317 { System.out.println("document load failed : " + f.getMessage() ) ; }
318 }
319 }
320
321 /**
322 debug mode method
323 */
324 public SwingEditorPanePanel newTestDocument()
325 {
326 try {
327 return new _TEST_DOCUMENT_() ;
328 } catch ( UtilsError f )
329 { System.out.println("document load failed : " + f.getMessage() ) ; }
330 return null ;
331 }
332
333 public ExtendedDesktopPane()
334 {
335 super() ;
336 // this.addComponentListener( listener );
337 SwingComponentPopup panePopup = new SwingComponentPopup(this) ;
338 // adding some specific menuItems to the _parent provided windowMenu
339 panePopup.addMenuItem( "tile internal frames" ,
340 new _TILE_FRAME_() ,
341 _TILE_ICON_
342 ) ;
343 panePopup.addMenuItem( "cascade internal frames" ,
344 new _CASCADE_FRAME_() ,
345 _CASCADE_ICON_
346 ) ;
347
348 if ( _debug )
349 {
350 panePopup.addMenuItem( "add new test frame" ,
351 new _ADD_FRAME_()
352 ) ;
353 }
354 }
355
356 public static void main ( String args[] )
357 {
358
359 JFrame f = new JFrame("Testing ExtendedDesktopPane") ;
360 f.setForeground(Color.black) ;
361 f.setBackground(Color.lightGray) ;
362 f.getContentPane().setLayout(new BorderLayout() ) ;
363 f.addWindowListener
364 (
365 // Exit the debug window frame
366 new WindowAdapter() {
367 public void windowClosing( WindowEvent e )
368 { System.exit(0) ; }
369 }
370
371 ) ;
372
373 JTabbedPane tabPanel = new JTabbedPane() ;
374
375 ExtendedDesktopPane intFrame = new ExtendedDesktopPane() ;
376 intFrame.setVisible(true) ;
377 intFrame.setPreferredSize(new Dimension(400,200)) ;
378 SwingMessageArea message = new SwingMessageArea() ;
379 message.headerFooter("test");
380 message.headerFooter("test");
381 JButton b = new JButton ("Add Frame") ;
382 // b.addActionListener( new _ADD_FRAME_(intFrame) ) ;
383 JPanel buttonPanel = new JPanel() ;
384 buttonPanel.setLayout( new FlowLayout() ) ;
385 buttonPanel.add(b) ;
386
387 // build the vsplit pane
388 JSplitPane vSplit = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT ,
389 buttonPanel ,
390 intFrame
391 ) ;
392 vSplit.setOneTouchExpandable(true);
393 vSplit.setContinuousLayout(true) ;
394
395 String ftpTitle = "test Panel" ;
396 JPanel testPanel = new JPanel() ;
397 testPanel.setLayout( new BorderLayout() ) ;
398 testPanel.add( BorderLayout.CENTER , new JButton("test panel") ) ;
399
400 tabPanel.addTab( ftpTitle ,
401 null ,
402 testPanel ,
403 "test panel"
404 ) ;
405
406 ftpTitle = "FTP connection" ;
407 tabPanel.addTab( ftpTitle ,
408 null ,
409 vSplit ,
410 "tab test Panel "
411 ) ;
412
413 f.getContentPane().add( "Center", tabPanel ) ;
414 intFrame.set_parent(f);
415 intFrame.addComponent( "test " , intFrame.newTestDocument() ) ;
416
417 f.pack() ;
418
419 f.setVisible(true) ;
420 }
421
422 }