package com.limegroup.gnutella.gui; import java.awt.Component; import java.awt.Dimension; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import javax.swing.plaf.TabbedPaneUI; import com.limegroup.gnutella.gui.connection.ConnectionMediator; import com.limegroup.gnutella.gui.download.DownloadMediator; import com.limegroup.gnutella.gui.library.LibraryMediator; import com.limegroup.gnutella.gui.menu.MenuMediator; import com.limegroup.gnutella.gui.options.OptionsMediator; import com.limegroup.gnutella.gui.playlist.PlaylistMediator; import com.limegroup.gnutella.gui.search.MagnetClipboardListener; import com.limegroup.gnutella.gui.search.SearchMediator; import com.limegroup.gnutella.gui.statistics.StatisticsMediator; import com.limegroup.gnutella.gui.tabs.ConnectionsTab; import com.limegroup.gnutella.gui.tabs.ConsoleTab; import com.limegroup.gnutella.gui.tabs.LibraryPlayListTab; import com.limegroup.gnutella.gui.tabs.MonitorUploadTab; import com.limegroup.gnutella.gui.tabs.SearchDownloadTab; import com.limegroup.gnutella.gui.tabs.Tab; import com.limegroup.gnutella.gui.themes.ThemeMediator; import com.limegroup.gnutella.gui.themes.ThemeObserver; import com.limegroup.gnutella.gui.upload.UploadMediator; import com.limegroup.gnutella.settings.ApplicationSettings; import com.limegroup.gnutella.settings.PlayerSettings; import com.limegroup.gnutella.settings.SettingsHandler; import com.limegroup.gnutella.util.CommonUtils; /** * This class constructs the main <tt>JFrame</tt> for the program as well as * all of the other GUI classes. */ //2345678|012345678|012345678|012345678|012345678|012345678|012345678|012345678| final class MainFrame implements ComponentListener, RefreshListener, ThemeObserver { /** * Handle to the <tt>JTabbedPane</tt> instance. */ private final JTabbedPane TABBED_PANE = new JTabbedPane(); /** * Constant handle to the <tt>SearchMediator</tt> class that is * responsible for displaying search results to the user. */ private final SearchMediator SEARCH_MEDIATOR = new SearchMediator(); /** * Constant handle to the <tt>DownloadMediator</tt> class that is * responsible for displaying active downloads to the user. */ private final DownloadMediator DOWNLOAD_MEDIATOR = DownloadMediator.instance(); /** * Constant handle to the <tt>MonitorView</tt> class that is * responsible for displaying incoming search queries to the user. */ private final MonitorView MONITOR_VIEW = new MonitorView(); /** * Constant handle to the <tt>UploadMediator</tt> class that is * responsible for displaying active uploads to the user. */ private final UploadMediator UPLOAD_MEDIATOR = UploadMediator.instance(); /** * Constant handle to the <tt>ConnectionView</tt> class that is * responsible for displaying current connections to the user. */ private final ConnectionMediator CONNECTION_MEDIATOR = ConnectionMediator.instance(); /** * Constant handle to the <tt>LibraryView</tt> class that is * responsible for displaying files in the user's repository. */ private final LibraryMediator LIBRARY_MEDIATOR = LibraryMediator.instance(); /** * Constant handle to the <tt>StatisticsMediator</tt> class that is * responsible for displaying statistics to the user. */ private final StatisticsMediator STATISTICS_MEDIATOR = StatisticsMediator.instance(); /** * Constant handle to the <tt>OptionsMediator</tt> class that is * responsible for displaying customizable options to the user. */ private final OptionsMediator OPTIONS_MEDIATOR = OptionsMediator.instance(); /** * Constant handle to the <tt>StatusLine</tt> class that is * responsible for displaying the status of the network and * connectivity to the user. */ private final StatusLine STATUS_LINE = new StatusLine(); /** * Handle the <tt>MenuMediator</tt> for use in changing the menu * depending on the selected tab. */ private final MenuMediator MENU_MEDIATOR = MenuMediator.instance(); /** * The main <tt>JFrame</tt> for the application. */ private final JFrame FRAME; /** * Is the download view currently being shown? */ private boolean isDownloadViewVisible = false; /** * Constant for the <tt>LogoPanel</tt> used for displaying the * lime/spinning lime search status indicator and the logo. */ private final LogoPanel LOGO_PANEL = new LogoPanel(); /** * The array of tabs in the main application window. */ private Tab[] TABS = null; private int height; private boolean isSearching = false; /** * Initializes the primary components of the main application window, * including the <tt>JFrame</tt> and the <tt>JTabbedPane</tt> * contained in that window. */ MainFrame(JFrame frame) { FRAME = frame; // Setup the Tabs structure based on advertising mode and Windows buildTabs(); TABBED_PANE.setPreferredSize(new Dimension(10000, 10000)); ImageIcon limeIcon = GUIMediator.getThemeImage(GUIConstants.LIMEWIRE_ICON); FRAME.setIconImage(limeIcon.getImage()); FRAME.addWindowListener(new WindowAdapter() { public void windowDeiconified(WindowEvent e) { // Handle reactivation on systems which do not support // the system tray. Windows systems call the // WindowsNotifyUser.restoreApplication() // method to restore applications from minimize and // auto-shutdown modes. Non-windows systems restore // the application using the following code. if(!CommonUtils.supportsTray()) { GUIMediator.restoreView(); } } public void windowClosing(WindowEvent e) { // save the screen size and location Dimension dim = GUIMediator.getAppSize(); Point loc = GUIMediator.getAppLocation(); ApplicationSettings.APP_WIDTH.setValue(dim.width); ApplicationSettings.APP_HEIGHT.setValue(dim.height); ApplicationSettings.WINDOW_X.setValue(loc.x); ApplicationSettings.WINDOW_Y.setValue(loc.y); SettingsHandler.save(); GUIMediator.close(true); } }); FRAME.addComponentListener(this); FRAME.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); this.setFrameDimensions(); // add all tabs initially.... for (int i = 0; i < TABS.length; i++) { this.addTab(TABS[i]); } TABBED_PANE.setRequestFocusEnabled(false); TABBED_PANE.addMouseListener(new MouseListener() { public void mouseClicked(MouseEvent e) { TabbedPaneUI ui = TABBED_PANE.getUI(); int idx = ui.tabForCoordinate(TABBED_PANE, e.getX(), e.getY()); if(idx != -1) idx = getTabIndex(idx); // get the real index. if(idx != -1) TABS[idx].mouseClicked(); } public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} }); // remove tabs according to Settings Manager... if (!ApplicationSettings.MONITOR_VIEW_ENABLED.getValue()) this.setTabVisible(GUIMediator.MONITOR_INDEX, false); if (!ApplicationSettings.CONNECTION_VIEW_ENABLED.getValue()) this.setTabVisible(GUIMediator.CONNECTIONS_INDEX, false); if (!ApplicationSettings.LIBRARY_VIEW_ENABLED.getValue()) this.setTabVisible(GUIMediator.LIBRARY_INDEX, false); if (!ApplicationSettings.CONSOLE_VIEW_ENABLED.getValue()) this.setTabVisible(GUIMediator.CONSOLE_INDEX, false); FRAME.setJMenuBar(MENU_MEDIATOR.getMenuBar()); JPanel contentPane = new JPanel(); FRAME.setContentPane(contentPane); contentPane.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.weightx = 1; gbc.weighty = 1; gbc.fill = GridBagConstraints.BOTH; gbc.gridx = 0; contentPane.add(TABBED_PANE, gbc); gbc.weighty = 0; gbc.gridy = 1; gbc.fill = GridBagConstraints.HORIZONTAL; contentPane.add(STATUS_LINE.getComponent(), gbc); JLayeredPane layeredPane = JLayeredPane.getLayeredPaneAbove(TABBED_PANE); layeredPane.add(LOGO_PANEL, JLayeredPane.PALETTE_LAYER, 0); ThemeMediator.addThemeObserver(this); GUIMediator.addRefreshListener(this); updateLogoHeight(); if (ApplicationSettings.MAGNET_CLIPBOARD_LISTENER.getValue()) { FRAME.addWindowListener(MagnetClipboardListener.getInstance()); } PowerManager pm = new PowerManager(); FRAME.addWindowListener(pm); GUIMediator.addRefreshListener(pm); } // inherit doc comment public void updateTheme() { FRAME.setJMenuBar(MENU_MEDIATOR.getMenuBar()); LOGO_PANEL.updateTheme(); setSearchIconLocation(); updateLogoHeight(); } private void updateLogoHeight() { // necessary so that the logo does not intrude on the content below Rectangle rect = TABBED_PANE.getUI().getTabBounds(TABBED_PANE, 0); Dimension ld = LOGO_PANEL.getPreferredSize(); int height = ld.height + 4; this.height = Math.max(rect.height, height); if (rect.height < height) TABBED_PANE.setBorder(BorderFactory.createEmptyBorder( height - rect.height, 0, 0, 0)); else TABBED_PANE.setBorder(null); } /** * Build the Tab Structure based on advertising mode and Windows */ private void buildTabs() { ArrayList tabs = new ArrayList(); tabs.add(new SearchDownloadTab(SEARCH_MEDIATOR, DOWNLOAD_MEDIATOR)); tabs.add(new MonitorUploadTab(MONITOR_VIEW, UPLOAD_MEDIATOR)); tabs.add(new ConnectionsTab(CONNECTION_MEDIATOR)); tabs.add(new LibraryPlayListTab(LIBRARY_MEDIATOR)); if (CommonUtils.isLog4JAvailable()) { Console console = new Console(); tabs.add(new ConsoleTab(console)); } TABS = (Tab[])tabs.toArray(new Tab[0]); } /** * Adds a tab to the <tt>JTabbedPane</tt> based on the data supplied * in the <tt>Tab</tt> instance. * * @param tab the <tt>Tab</tt> instance containing data for the tab to * add */ private void addTab(Tab tab) { TABBED_PANE.addTab(tab.getTitle(), tab.getIcon(), tab.getComponent(), tab.getToolTip()); } /** * Inserts a tab in the <tt>JTabbedPane</tt> at the specified index, * based on the data supplied in the <tt>Tab</tt> instance. * * @param tab the <tt>Tab</tt> instance containing data for the tab to * add */ private void insertTab(Tab tab, int index) { TABBED_PANE.insertTab(tab.getTitle(), tab.getIcon(), tab.getComponent(), tab.getToolTip(), index); // the component tree must be updated so that the new tab // fits the current theme (if the theme was changed at runtime) SwingUtilities.updateComponentTreeUI(TABBED_PANE); ThemeMediator.updateThemeObservers(); } /** * Sets the selected index in the wrapped <tt>JTabbedPane</tt>. * * @param index the tab index to select */ final void setSelectedIndex(int index) { int i = getTabIndex(index); if (i == -1) return; TABBED_PANE.setSelectedIndex(i); } void updateTabIcon(int index) { int i = getTabIndex(index); if (i == -1) return; TABBED_PANE.setIconAt(i, TABS[index].getIcon()); } /** * Sets the x,y location as well as the height and width of the main * application <tt>Frame</tt>. */ private final void setFrameDimensions() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gd = ge.getDefaultScreenDevice(); GraphicsConfiguration gc = gd.getDefaultConfiguration(); Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int locX = 0; int locY = 0; int appWidth = Math.min(screenSize.width-insets.left-insets.right, ApplicationSettings.APP_WIDTH.getValue()); int appHeight = Math.min(screenSize.height-insets.top-insets.bottom, ApplicationSettings.APP_HEIGHT.getValue()); // Set the location of our window based on whether or not // the user has run the program before, and therefore may have // modified the location of the main window. if(ApplicationSettings.RUN_ONCE.getValue()) { locX = Math.max(insets.left, ApplicationSettings.WINDOW_X.getValue()); locY = Math.max(insets.top, ApplicationSettings.WINDOW_Y.getValue()); } else { locX = (screenSize.width - appWidth) / 2; locY = (screenSize.height - appHeight) / 2; } // Make sure the Window is visible and not for example // somewhere in the very bottom right corner. if (locX+appWidth > screenSize.width) { locX = Math.max(insets.left, screenSize.width - insets.left - insets.right - appWidth); } if (locY+appHeight > screenSize.height) { locY = Math.max(insets.top, screenSize.height - insets.top - insets.bottom - appHeight); } FRAME.setLocation(locX, locY); FRAME.setSize(new Dimension(appWidth, appHeight)); FRAME.getContentPane().setSize(new Dimension(appWidth, appHeight)); ((JComponent)FRAME.getContentPane()).setPreferredSize(new Dimension(appWidth, appHeight)); } /** * Sets the visible/invisible state of the tab associated with the * specified index. The indeces correspond to the order of the * tabs whether or not they are visible, as specified in * <tt>GUIMediator</tt>. * * @param TAB_INDEX the index of the tab to make visible or * invisible * @param VISIBLE the visible/invisible state to set the tab to */ void setTabVisible(final int TAB_INDEX, final boolean VISIBLE) { if ((TAB_INDEX == 0) || (TAB_INDEX > (TABS.length - 1))) throw new IllegalArgumentException( "Invalid tab index: " + TAB_INDEX); Tab tab = TABS[TAB_INDEX]; Component comp = tab.getComponent(); int tabCount = TABBED_PANE.getTabCount(); if (!VISIBLE) { // remove the tab from the tabbed pane for (int i = 0; i < tabCount; i++) { if (comp.equals(TABBED_PANE.getComponentAt(i))) { TABBED_PANE.remove(i); break; } } } else { // make sure the current one is invisible. JComponent selComp = (JComponent)TABBED_PANE.getSelectedComponent(); selComp.setVisible(false); // add the tab to the tabbed pane for (int i = 0; i < tabCount; i++) { Component comp1 = TABBED_PANE.getComponentAt(i); int index = getIndex(comp1); if (index == -1) { selComp.setVisible(true); return; } if (index > TAB_INDEX) { insertTab(TABS[TAB_INDEX], i); break; } else if (i == tabCount - 1) { insertTab(TABS[TAB_INDEX], i + 1); } } JComponent jcomp = (JComponent)comp; jcomp.invalidate(); jcomp.revalidate(); jcomp.repaint(); } MENU_MEDIATOR.setNavMenuItemEnabled(TAB_INDEX, VISIBLE); tab.storeState(VISIBLE); } /** * This method gets the fixed index for the specified <tt>Component</tt> * instance, or the index as specified by the constants in * <tt>GUIMediator</tt>. The component passed in must be the component * for one of the tabs in the main applicaiton window. * * @param comp a <tt>Component</tt> instance for one of the tabs * @return the fixed index for the tab that contains the component * argument, or -1 if the component is not contained in any of the tabs */ private int getIndex(Component comp) { for (int i = 0; i < TABS.length; i++) { if (comp.equals(TABS[i].getComponent())) return TABS[i].getIndex(); } return -1; } /** * Returns the index in the tabbed pane of the specified "real" index * argument. The values for this argument are listed in * <tt>GUIMediator</tt>. * * @param index the "real" index of the tab, meaning that this index * is independent of what is currently visible in the tab * @return the index in the tabbed pane of the specified real index, * or -1 if the specified index is not found */ private int getTabIndex(int index) { int tabCount = TABBED_PANE.getTabCount(); Component comp = TABS[index].getComponent(); for (int i = 0; i < tabCount; i++) { Component tabComp = TABBED_PANE.getComponentAt(i); if (tabComp.equals(comp)) return i; } return -1; } /** * Should be called whenever state may have changed, so MainFrame can then * re-layout window (if necessary). */ public void refresh() { if (isSearching) { // if we're searching make sure the search result panel // is visible SearchDownloadTab tab = (SearchDownloadTab)TABS[GUIMediator.SEARCH_INDEX]; if (tab.getDividerLocation() == 0) { tab.setDividerLocation(0.5); isDownloadViewVisible = true; } } // first handle the download view if (DOWNLOAD_MEDIATOR.getActiveDownloads() == 0 && isDownloadViewVisible) { ((SearchDownloadTab)TABS[GUIMediator.SEARCH_INDEX]). setDividerLocation(1000); isDownloadViewVisible = false; } else if (DOWNLOAD_MEDIATOR.getActiveDownloads() > 0 && !isDownloadViewVisible) { // need to turn it on.... final int count = DOWNLOAD_MEDIATOR.getActiveDownloads(); // make sure stuff didn't change on me.... if (count > 0) { final double prop = (count > 6) ? 0.60 : 0.70; ((SearchDownloadTab)TABS[GUIMediator.SEARCH_INDEX]). setDividerLocation(prop); ((SearchDownloadTab)TABS[GUIMediator.SEARCH_INDEX]). getComponent().revalidate(); TABBED_PANE.revalidate(); isDownloadViewVisible = true; } } } /** * Returns a reference to the <tt>SearchMediator</tt> instance. * * @return a reference to the <tt>SearchMediator</tt> instance */ final SearchMediator getSearchMediator() { return SEARCH_MEDIATOR; } /** * Returns a reference to the <tt>DownloadMediator</tt> instance. * * @return a reference to the <tt>DownloadMediator</tt> instance */ final DownloadMediator getDownloadMediator() { return DOWNLOAD_MEDIATOR; } /** * Returns a reference to the <tt>MonitorView</tt> instance. * * @return a reference to the <tt>MonitorView</tt> instance */ final MonitorView getMonitorView() { return MONITOR_VIEW; } /** * Returns a reference to the <tt>UploadMediator</tt> instance. * * @return a reference to the <tt>UploadMediator</tt> instance */ final UploadMediator getUploadMediator() { return UPLOAD_MEDIATOR; } /** * Returns a reference to the <tt>ConnectionMediator</tt> instance. * * @return a reference to the <tt>ConnectionMediator</tt> instance */ final ConnectionMediator getConnectionMediator() { return CONNECTION_MEDIATOR; } /** * Returns a reference to the <tt>LibraryMediator</tt> instance. * * @return a reference to the <tt>LibraryMediator</tt> instance */ final LibraryMediator getLibraryMediator() { return LIBRARY_MEDIATOR; } /** * Returns a reference to the <tt>PlaylistMediator</tt> instance. * * @return a reference to the <tt>PlaylistMediator</tt> instance or * <code>null</code> if the playlist is not enabled */ static final PlaylistMediator getPlaylistMediator() { return PlayerSettings.PLAYER_ENABLED.getValue() ? PlaylistMediator.instance() : null; } /** * Returns a reference to the <tt>StatusLine</tt> instance. * * @return a reference to the <tt>StatusLine</tt> instance */ final StatusLine getStatusLine() { return STATUS_LINE; } /** * Returns a reference to the <tt>MenuMediator</tt> instance. * * @return a reference to the <tt>MenuMediator</tt> instance */ final MenuMediator getMenuMediator() { return MENU_MEDIATOR; } /** * Returns a reference to the <tt>OptionsMediator</tt> instance. * * @return a reference to the <tt>OptionsMediator</tt> instance */ final OptionsMediator getOptionsMediator() { return OPTIONS_MEDIATOR; } /** * Returns a reference to the <tt>StatisticsMediator</tt> instance. * * @return a reference to the <tt>StatisticsMediator</tt> instance */ final StatisticsMediator getStatisticsMediator() { return STATISTICS_MEDIATOR; } /** * Returns a reference to the <tt>StatisticsView</tt> instance. * * @return a reference to the <tt>StatisticsView</tt> instance */ //final StatisticsView getStatisticsView() { //return STATISTICS_VIEW; //} /** * Sets the searching or not searching status of the application. * * @param searching the searching status of the application */ final void setSearching(boolean searching) { LOGO_PANEL.setSearching(searching); isSearching = searching; refresh(); } // implements the ComponentListener interface public void componentHidden(ComponentEvent e) { } // implements the ComponentListener interface public void componentMoved(ComponentEvent e) { } // implements the ComponentListener interface public void componentResized(ComponentEvent e) { this.setSearchIconLocation(); } // implements the ComponentListener interface public void componentShown(ComponentEvent e) { this.setSearchIconLocation(); } /** * Sets the location of the search status icon. */ private void setSearchIconLocation() { int y = MENU_MEDIATOR.getMenuBarHeight() + (height - LOGO_PANEL.getPreferredSize().height) / 2; LOGO_PANEL.setLocation( FRAME.getSize().width - LOGO_PANEL.getSize().width - 12, y); } }