001: package net.sourceforge.squirrel_sql.client.gui.mainframe;
002:
003: /*
004: * Copyright (C) 2001-2004 Colin Bell
005: * colbell@users.sourceforge.net
006: *
007: * Modifications Copyright (C) 2003-2004 Jason Height
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022: */
023: import java.awt.BorderLayout;
024: import java.awt.Container;
025: import java.awt.Dimension;
026: import java.awt.Event;
027: import java.awt.Font;
028: import java.awt.Point;
029: import java.awt.event.*;
030: import java.beans.PropertyChangeEvent;
031: import java.beans.PropertyChangeListener;
032: import java.beans.PropertyVetoException;
033: import java.util.prefs.Preferences;
034:
035: import javax.swing.AbstractAction;
036: import javax.swing.Action;
037: import javax.swing.BorderFactory;
038: import javax.swing.DefaultDesktopManager;
039: import javax.swing.ImageIcon;
040: import javax.swing.JComponent;
041: import javax.swing.JDesktopPane;
042: import javax.swing.JFrame;
043: import javax.swing.JInternalFrame;
044: import javax.swing.JMenu;
045: import javax.swing.JScrollPane;
046: import javax.swing.JSplitPane;
047: import javax.swing.KeyStroke;
048: import javax.swing.SwingUtilities;
049:
050: import net.sourceforge.squirrel_sql.fw.gui.CascadeInternalFramePositioner;
051: import net.sourceforge.squirrel_sql.fw.gui.Dialogs;
052: import net.sourceforge.squirrel_sql.fw.gui.GUIUtils;
053: import net.sourceforge.squirrel_sql.fw.gui.IInternalFramePositioner;
054: import net.sourceforge.squirrel_sql.fw.util.StringManager;
055: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
056: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
057: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
058: import net.sourceforge.squirrel_sql.fw.datasetviewer.IMainFrame;
059:
060: import net.sourceforge.squirrel_sql.client.IApplication;
061: import net.sourceforge.squirrel_sql.client.Version;
062: import net.sourceforge.squirrel_sql.client.gui.ScrollableDesktopPane;
063: import net.sourceforge.squirrel_sql.client.preferences.SquirrelPreferences;
064: import net.sourceforge.squirrel_sql.client.resources.SquirrelResources;
065: import net.sourceforge.squirrel_sql.client.session.MessagePanel;
066:
067: public class MainFrame extends JFrame implements IMainFrame //BaseMDIParentFrame
068: {
069:
070: public interface IMenuIDs extends MainFrameMenuBar.IMenuIDs {
071: // Empty body.
072: }
073:
074: /** Logger for this class. */
075: private final ILogger s_log = LoggerController
076: .createLogger(MainFrame.class);
077:
078: /** Internationalized strings for this class. */
079: private static final StringManager s_stringMgr = StringManagerFactory
080: .getStringManager(MainFrame.class);
081:
082: /** Application API. */
083: private final IApplication _app;
084:
085: // private AliasesListInternalFrame _aliasesListWindow;
086: // private DriversListInternalFrame _driversListWindow;
087:
088: /** Toolbar at top of window. */
089: private MainFrameToolBar _toolBar;
090:
091: /** Status bar at bottom of window. */
092: private MainFrameStatusBar _statusBar;
093:
094: /** Message panel at bottom of window. */
095: // JASON: Should be part of status bar?
096: private MessagePanel _msgPnl;
097:
098: /** If <TT>true</TT> then status bar is visible. */
099: private boolean _statusBarVisible = false;
100:
101: private JDesktopPane _desktop;
102:
103: private final IInternalFramePositioner _internalFramePositioner = new CascadeInternalFramePositioner();
104: // private Map _children = new HashMap();
105:
106: private static final String PREFS_KEY_MESSAGEPANEL_HEIGHT = "squirrelSql_msgPanel_height";
107:
108: private boolean m_hasBeenVisible;
109:
110: private JSplitPane _splitPn;
111:
112: /**
113: * Ctor.
114: *
115: * @param app Application API.
116: *
117: * @throws IllegalArgumentException
118: * Thrown if <TT>null</TT> <TT>IApplication</TT>
119: * passed.
120: */
121: public MainFrame(IApplication app) {
122: super (Version.getVersion());
123: if (app == null) {
124: throw new IllegalArgumentException(
125: "Null IApplication passed");
126: }
127: _app = app;
128: _desktop = new ScrollableDesktopPane();
129: createUserInterface();
130: preferencesHaveChanged(null); // Initial load of prefs.
131: _app.getSquirrelPreferences().addPropertyChangeListener(
132: new PropertyChangeListener() {
133: public void propertyChange(PropertyChangeEvent evt) {
134: synchronized (MainFrame.this ) {
135: preferencesHaveChanged(evt);
136: }
137: }
138: });
139:
140: SwingUtilities.invokeLater(new Runnable() {
141: public void run() {
142: ScrollableDesktopPane comp = (ScrollableDesktopPane) getDesktopPane();
143: comp.setPreferredSize(comp.getRequiredSize());
144: comp.revalidate();
145: }
146: });
147: }
148:
149: public void dispose() {
150: boolean shouldDispose = true;
151: if (!_app.shutdown()) {
152: String msg = s_stringMgr
153: .getString("MainFrame.errorOnClose");
154: shouldDispose = Dialogs.showYesNo(_app.getMainFrame(), msg);
155: }
156: if (shouldDispose) {
157: closeAllToolWindows();
158: super .dispose();
159: System.exit(0);
160: }
161: }
162:
163: public void pack() {
164: // Don't call super. Packing this frame causes problems.
165: }
166:
167: public IApplication getApplication() {
168: return _app;
169: }
170:
171: public JDesktopPane getDesktopPane() {
172: return _desktop;
173: }
174:
175: /**
176: * Add the passed internal frame to this MDI frame.
177: * Calls <TT>addInternalFrame(child, createMenuItem, null)</TT>.
178: *
179: * @param child The internal frame to be added.
180: * @param createMenuItem If <TT>true</TT> add an item to the MDI
181: * Window menu to select the passed internal frame.
182: *
183: * @throws IllegalArgumentException if null <TT>JInternalFrame</TT> passed.
184: */
185: public void addInternalFrame(JInternalFrame child,
186: boolean createMenuItem) {
187: addInternalFrame(child, createMenuItem, null);
188: }
189:
190: public void addInternalFrame(JInternalFrame child,
191: boolean addToWindowMenu, Action action) {
192: addInternalFrame(child, addToWindowMenu, action, null);
193: }
194:
195: public void addInternalFrame(JInternalFrame child,
196: boolean addToWindowMenu, Action action, Integer layer) {
197: if (!GUIUtils.isToolWindow(child)) {
198: Dimension cs = getDesktopPane().getSize();
199: // Cast to int required as Dimension::setSize(double,double)
200: // doesn't appear to do anything in JDK1.2.2.
201: cs.setSize((int) (cs.width * 0.8d),
202: (int) (cs.height * 0.8d));
203: child.setSize(cs);
204: }
205:
206: if (child == null) {
207: throw new IllegalArgumentException(
208: "Null JInternalFrame added");
209: }
210:
211: if (null != layer) {
212: _desktop.add(child, layer);
213: } else {
214: _desktop.add(child);
215: }
216:
217: if (!GUIUtils.isToolWindow(child)) {
218: positionNewInternalFrame(child);
219: }
220: // JInternalFrame[] frames = GUIUtils.getOpenNonToolWindows(getDesktopPane().getAllFrames());
221: // _app.getActionCollection().internalFrameOpenedOrClosed(frames.length);
222:
223: // Size non-tool child window.
224: if (!GUIUtils.isToolWindow(child)) {
225: if (child.isMaximizable()
226: && _app.getSquirrelPreferences()
227: .getMaximizeSessionSheetOnOpen()) {
228: try {
229: child.setMaximum(true);
230: } catch (PropertyVetoException ex) {
231: s_log.error("Unable to maximize window", ex);
232: }
233: }
234: }
235: }
236:
237: public JMenu getSessionMenu() {
238: return ((MainFrameMenuBar) getJMenuBar()).getSessionMenu();
239: }
240:
241: public void addToMenu(int menuId, JMenu menu) {
242: if (menu == null) {
243: throw new IllegalArgumentException("Null JMenu passed");
244: }
245: ((MainFrameMenuBar) getJMenuBar()).addToMenu(menuId, menu);
246: }
247:
248: public void addToMenu(int menuId, Action action) {
249: if (action == null) {
250: throw new IllegalArgumentException("Null BaseAction passed");
251: }
252: ((MainFrameMenuBar) getJMenuBar()).addToMenu(menuId, action);
253: }
254:
255: /**
256: * Add component to the status bar.
257: *
258: * @param comp Component to add.
259: *
260: * @throws IllegalArgumentException
261: * Thrown if <TT>null</TT> <TT>JComponent</TT> passed.
262: */
263: public void addToStatusBar(JComponent comp) {
264: if (comp == null) {
265: throw new IllegalArgumentException("JComponent == null");
266: }
267: _statusBar.addJComponent(comp);
268: }
269:
270: /**
271: * Remove component to the main frames status bar.
272: *
273: * @param comp Component to remove.
274: */
275: public void removeFromStatusBar(JComponent comp) {
276: if (comp == null) {
277: throw new IllegalArgumentException("JComponent == null");
278: }
279: _statusBar.remove(comp);
280: }
281:
282: public MessagePanel getMessagePanel() {
283: return _msgPnl;
284: }
285:
286: private void preferencesHaveChanged(PropertyChangeEvent evt) {
287: String propName = evt != null ? evt.getPropertyName() : null;
288:
289: final SquirrelPreferences prefs = _app.getSquirrelPreferences();
290:
291: if (propName == null
292: || propName
293: .equals(SquirrelPreferences.IPropertyNames.SHOW_CONTENTS_WHEN_DRAGGING)) {
294: if (prefs.getShowContentsWhenDragging()) {
295: getDesktopPane().putClientProperty(
296: "JDesktopPane.dragMode", null);
297: } else {
298: getDesktopPane().putClientProperty(
299: "JDesktopPane.dragMode", "outline");
300: }
301: }
302:
303: if (propName == null
304: || propName
305: .equals(SquirrelPreferences.IPropertyNames.SHOW_MAIN_STATUS_BAR)) {
306: final boolean show = prefs.getShowMainStatusBar();
307: if (!show && _statusBarVisible) {
308: getContentPane().remove(_statusBar);
309: _statusBarVisible = false;
310: } else if (show && !_statusBarVisible) {
311: getContentPane().add(_statusBar, BorderLayout.SOUTH);
312: _statusBarVisible = true;
313: }
314: }
315: if (propName == null
316: || propName
317: .equals(SquirrelPreferences.IPropertyNames.SHOW_MAIN_TOOL_BAR)) {
318: final boolean show = prefs.getShowMainToolBar();
319: if (!show && _toolBar != null) {
320: getContentPane().remove(_toolBar);
321: _toolBar = null;
322: } else if (show && _toolBar == null) {
323: _toolBar = new MainFrameToolBar(_app);
324: getContentPane().add(_toolBar, BorderLayout.NORTH);
325: }
326: }
327:
328: }
329:
330: private void closeAllToolWindows() {
331: JInternalFrame[] frames = GUIUtils
332: .getOpenToolWindows(getDesktopPane().getAllFrames());
333: for (int i = 0; i < frames.length; ++i) {
334: frames[i].dispose();
335: }
336: }
337:
338: private void createUserInterface() {
339: setVisible(false);
340: setDefaultCloseOperation(MainFrame.DO_NOTHING_ON_CLOSE);
341:
342: final SquirrelResources rsrc = _app.getResources();
343:
344: getDesktopPane().setDesktopManager(new MyDesktopManager());
345:
346: final Container content = getContentPane();
347:
348: // _aliasesToolWindow = new AliasesListInternalFrame(_app);
349: // _driversToolWindow = new DriversListInternalFrame(_app);
350:
351: // preLoadActions();
352: content.setLayout(new BorderLayout());
353: final JScrollPane sp = new JScrollPane(getDesktopPane());
354: sp.setBorder(BorderFactory.createEmptyBorder());
355:
356: _msgPnl = new MessagePanel() {
357: public void setSize(int width, int height) {
358: super .setSize(width, height);
359: if (0 < width && 0 < height) {
360: // The call here is the result of a desperate fight
361: // to find a place where the components in the split
362: // had not height = 0. If someone knows a better way
363: // please tell me I'll apreciate any advice.
364: // gerdwagner@users.sourceforge.net
365: resizeSplitOnStartup();
366: }
367: }
368: };
369:
370: _msgPnl.setEditable(false);
371:
372: _splitPn = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
373: _splitPn.add(sp);
374: _splitPn.add(new JScrollPane(_msgPnl));
375:
376: _splitPn.setResizeWeight(1);
377:
378: //i18n[MainFrame.saveSize=Save size]
379: String key = s_stringMgr.getString("MainFrame.saveSize");
380: Action splitDividerLocAction = new AbstractAction(key) {
381: public void actionPerformed(ActionEvent e) {
382: int msgPanelHeight = _splitPn.getBottomComponent()
383: .getSize().height;
384: Preferences.userRoot().putInt(
385: PREFS_KEY_MESSAGEPANEL_HEIGHT, msgPanelHeight);
386: }
387: };
388: _msgPnl.addToMessagePanelPopup(splitDividerLocAction);
389:
390: //i18n[MainFrame.restoreSize=Restore saved size]
391: key = s_stringMgr.getString("MainFrame.restoreSize");
392:
393: Action setSplitDividerLocAction = new AbstractAction(key) {
394: public void actionPerformed(ActionEvent e) {
395: int prefMsgPanelHeight = Preferences.userRoot().getInt(
396: PREFS_KEY_MESSAGEPANEL_HEIGHT, -1);
397: if (-1 != prefMsgPanelHeight) {
398: int divLoc = getDividerLocation(prefMsgPanelHeight,
399: _splitPn);
400: _splitPn.setDividerLocation(divLoc);
401: }
402: }
403: };
404: _msgPnl.addToMessagePanelPopup(setSplitDividerLocAction);
405:
406: content.add(_splitPn, BorderLayout.CENTER);
407:
408: _statusBar = new MainFrameStatusBar(_app);
409: final Font fn = _app.getFontInfoStore().getStatusBarFontInfo()
410: .createFont();
411: _statusBar.setFont(fn);
412:
413: setJMenuBar(new MainFrameMenuBar(_app, getDesktopPane(), _app
414: .getActionCollection()));
415:
416: setupFromPreferences();
417:
418: final ImageIcon icon = rsrc
419: .getIcon(SquirrelResources.IImageNames.APPLICATION_ICON);
420: if (icon != null) {
421: setIconImage(icon.getImage());
422: } else {
423: s_log.error("Missing icon for mainframe");
424: }
425:
426: // On Win 2000 & XP mnemonics are normally hidden. To make them
427: // visible you press the alt key. Under the Windows L&F pressing
428: // alt may not work. This code is a workaround. See bug report
429: // 4736093 for more information.
430: getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
431: .put(
432: KeyStroke.getKeyStroke(KeyEvent.VK_ALT,
433: Event.ALT_MASK, false), "repaint");
434:
435: validate();
436:
437: addWindowListener(new WindowAdapter() {
438: public void windowClosing(WindowEvent evt) {
439: dispose();
440: }
441: });
442: }
443:
444: public void resizeSplitOnStartup() {
445:
446: if (false == m_hasBeenVisible) {
447: m_hasBeenVisible = true;
448: final int prefMsgPanelHeight = Preferences.userRoot()
449: .getInt(PREFS_KEY_MESSAGEPANEL_HEIGHT, -1);
450:
451: SwingUtilities.invokeLater(new Runnable() {
452: public void run() {
453: if (-1 == prefMsgPanelHeight) {
454: int divLoc = getDividerLocation(50, _splitPn);
455: _splitPn.setDividerLocation(divLoc);
456: } else {
457: int divLoc = getDividerLocation(
458: prefMsgPanelHeight, _splitPn);
459: _splitPn.setDividerLocation(divLoc);
460:
461: }
462: }
463: });
464:
465: }
466: }
467:
468: private int getDividerLocation(int wantedBottomComponentHeight,
469: JSplitPane splitPn) {
470: int splitBarSize = splitPn.getSize().height
471: - splitPn.getBottomComponent().getSize().height
472: - splitPn.getTopComponent().getSize().height - 1;
473:
474: int divLoc = splitPn.getSize().height
475: - wantedBottomComponentHeight - splitBarSize;
476: return divLoc;
477: }
478:
479: private void setupFromPreferences() {
480: final SquirrelPreferences prefs = _app.getSquirrelPreferences();
481: MainFrameWindowState ws = prefs.getMainFrameWindowState();
482:
483: // Position window to where it was when last closed. If this is not
484: // on the screen, move it back on to the screen.
485: setBounds(ws.getBounds().createRectangle());
486: if (!GUIUtils.isWithinParent(this )) {
487: setLocation(new Point(10, 10));
488: }
489: setExtendedState(ws.getFrameExtendedState());
490: }
491:
492: private void positionNewInternalFrame(JInternalFrame child) {
493: _internalFramePositioner.positionInternalFrame(child);
494: }
495:
496: public JMenu getWindowsMenu() {
497: return ((MainFrameMenuBar) getJMenuBar()).getWindowsMenu();
498: }
499:
500: public void setEnabledAliasesMenu(boolean b) {
501: MainFrameMenuBar mainFrameMenuBar = (MainFrameMenuBar) getJMenuBar();
502: mainFrameMenuBar.setEnabledAliasesMenu(b);
503: }
504:
505: public void setEnabledDriversMenu(boolean b) {
506: MainFrameMenuBar mainFrameMenuBar = (MainFrameMenuBar) getJMenuBar();
507: mainFrameMenuBar.setEnabledDriversMenu(b);
508: }
509:
510: public void addToToolBar(Action act) {
511: _toolBar.add(act);
512: }
513:
514: private class MyDesktopManager extends DefaultDesktopManager {
515: public void activateFrame(JInternalFrame f) {
516: super .activateFrame(f);
517: _app.getActionCollection().activationChanged(f);
518: }
519:
520: public void deactivateFrame(JInternalFrame f) {
521: super.deactivateFrame(f);
522: _app.getActionCollection().deactivationChanged(f);
523: }
524: }
525: }
|