1 /* 2 * $Id$ 3 * 4 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 package com.sun.javatest.exec; 28 29 import com.sun.javatest.tool.StringFitter; 30 import com.sun.javatest.tool.ToolAction; 31 import com.sun.javatest.tool.UIFactory; 32 import java.awt.Component; 33 import java.awt.Container; 34 import java.awt.GridBagConstraints; 35 import java.awt.GridBagLayout; 36 import java.awt.event.ActionEvent; 37 import java.awt.event.ItemEvent; 38 import java.awt.event.ItemListener; 39 import java.awt.Font; 40 import java.io.File; 41 import java.net.URL; 42 import java.util.Vector; 43 import javax.swing.Action; 44 import javax.swing.BorderFactory; 45 import javax.swing.DefaultComboBoxModel; 46 import javax.swing.DefaultListCellRenderer; 47 import javax.swing.JButton; 48 import javax.swing.JComboBox; 49 import javax.swing.JLabel; 50 import javax.swing.JList; 51 import javax.swing.JPanel; 52 import javax.swing.JScrollPane; 53 import javax.swing.JToolBar; 54 import javax.swing.ScrollPaneConstants; 55 import javax.swing.plaf.basic.BasicComboBoxUI; 56 import javax.swing.plaf.basic.BasicComboPopup; 57 import javax.swing.plaf.basic.ComboPopup; 58 59 public class NavigationPane extends JPanel { 60 61 public NavigationPane(UIFactory uif, MultiFormatPane mediaPane) 62 throws IllegalArgumentException { 63 64 if(mediaPane == null) { 65 throw new IllegalArgumentException("Corresponding media pane should exist"); 66 } 67 this.mediaPane = mediaPane; 68 69 this.uif = uif; 70 71 history = new History(); 72 73 initActions(); 74 75 initGUI(); 76 77 mediaPane.setNavigationPane(this); 78 } 79 80 public void setHomeURL(URL url) { 81 homeURL = url; 82 homeAction.setEnabled(true); 83 } 84 85 public URL getHomeURL() { 86 return homeURL; 87 } 88 89 public void setURLs(URL[] urls) { 90 if(model != null) { 91 model.removeAllElements(); 92 93 homeURL = urls[0]; 94 homeAction.setEnabled(homeURL != null); 95 96 for(URL url : urls) { 97 model.addElement(url); 98 } 99 model.setSelectedItem(homeURL); 100 } 101 } 102 // When click link on corresponding media pane 103 public void processURL(URL url) { 104 history.add(url); 105 backAction.setEnabled(history.hasPrev()); 106 forwardAction.setEnabled(history.hasNext()); 107 updateCombo(url); 108 } 109 110 public void clear() { 111 if (model != null) 112 model.removeAllElements(); 113 114 history.clear(); 115 backAction.setEnabled(false); 116 forwardAction.setEnabled(false); 117 homeAction.setEnabled(false); 118 119 homeURL = null; 120 } 121 122 private void initGUI() { 123 uif.initPanel(this, "np", false); 124 setLayout(new GridBagLayout()); 125 setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); 126 127 GridBagConstraints c = new GridBagConstraints(); 128 c.anchor = GridBagConstraints.EAST; 129 c.gridx = 0; 130 c.gridy = 0; 131 132 JLabel fileLbl = uif.createLabel("np.file", true); 133 fileLbl.setFont(new Font(Font.MONOSPACED, uif.getBaseFont().getStyle(), uif.getBaseFont().getSize())); 134 add(fileLbl, c); 135 136 selectBox = uif.createChoice("np.choice", fileLbl); 137 selectBox.setFont(new Font(Font.MONOSPACED, uif.getBaseFont().getStyle(), uif.getBaseFont().getSize())); 138 selectBox.setRenderer(new Renderer(selectBox)); 139 selectBox.setModel(createModel()); 140 selectBox.addItemListener(listener); 141 selectBox.setMaximumRowCount(MAX_ROWS_DISPLAY); 142 selectBox.setUI(new BasicComboBoxUI() { 143 // wrap the content with a scrolling interface 144 // would be nice if Swing did this for us 145 protected ComboPopup createPopup() { 146 BasicComboPopup popup = new BasicComboPopup(selectBox) { 147 protected JScrollPane createScroller() { 148 return new JScrollPane(list, 149 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 150 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); 151 } 152 }; 153 return popup; 154 } 155 } // class 156 ); 157 uif.setAccessibleName(selectBox, "np.choice"); // override default a11y name 158 159 c.gridx = 1; 160 c.weightx = 2.0; 161 c.fill = GridBagConstraints.HORIZONTAL; 162 163 add(selectBox, c); 164 165 Action[] actions = { backAction, forwardAction, null, homeAction }; 166 167 toolBar = uif.createToolBar("np.toolbar", actions ); 168 toolBar.setFloatable(false); 169 170 c.weightx = 0; 171 c.gridx = 2; 172 c.insets.left = 5; 173 174 add(toolBar, c); 175 176 } 177 178 private void initActions() { 179 homeAction = new ToolAction(uif, "np.home", true) { 180 public void actionPerformed(ActionEvent e) { 181 if (homeURL == null) { 182 mediaPane.setDefaultView(); 183 } 184 else{ 185 mediaPane.stopAudio(); 186 mediaPane.loadPage(homeURL); 187 } 188 } 189 }; 190 191 backAction = new ToolAction(uif, "np.back", true) { 192 public void actionPerformed(ActionEvent e) { 193 URL url = history.prev(); 194 if (url != null) { 195 mediaPane.stopAudio(); 196 mediaPane.loadPage(url); 197 } 198 } 199 }; 200 201 forwardAction = new ToolAction(uif, "np.forward", true) { 202 public void actionPerformed(ActionEvent e) { 203 URL url = history.next(); 204 if (url != null) { 205 mediaPane.stopAudio(); 206 mediaPane.loadPage(url); 207 } 208 } 209 }; 210 } 211 212 213 private DefaultComboBoxModel createModel() { 214 if (model == null) 215 model = new DefaultComboBoxModel(); 216 return model; 217 } 218 219 private void updateCombo(URL s) { 220 // check if the new element exists in the combo box... 221 if (model.getIndexOf(s) < 0) 222 model.addElement(s); 223 224 URL item = (URL) selectBox.getSelectedItem(); 225 // check if the new element is already selected. 226 // URL.equals can result in a big performance hit 227 if (s != null && !item.toString().equals(s.toString())) 228 selectBox.setSelectedItem(s); 229 } 230 231 private class Listener implements ItemListener { 232 public void itemStateChanged(ItemEvent e) { 233 if (e.getStateChange() == ItemEvent.SELECTED) { 234 mediaPane.stopAudio(); 235 URL url = (URL) e.getItem(); 236 mediaPane.loadPage(url); 237 } 238 } 239 } 240 241 242 // History 243 private static class History { 244 boolean hasPrev() { 245 return (index > 0); 246 } 247 248 URL prev() { 249 if (index == 0) 250 return null; 251 252 return (URL) (entries.elementAt(--index)); 253 } 254 255 boolean hasNext() { 256 return (index < entries.size() - 1); 257 } 258 259 URL next() { 260 if (index == entries.size() - 1) 261 return null; 262 263 return (URL) (entries.elementAt(++index)); 264 } 265 266 void add(URL u) { 267 if (u == null) 268 throw new NullPointerException(); 269 270 // if there is a current entry, and it matches the one to be added, we're done 271 if (index >= 0 && index < entries.size() && entries.elementAt(index).equals(u)) 272 return; 273 274 // if current entry not the last one, truncate to the current entry 275 if (index < entries.size() - 1) 276 entries.setSize(index + 1); 277 278 // finally, add new entry 279 entries.addElement(u); 280 index = entries.size() - 1; 281 } 282 283 void clear() { 284 entries.setSize(0); 285 index = -1; 286 } 287 288 private Vector entries = new Vector(); 289 private int index; 290 } 291 292 293 294 295 private class Renderer extends DefaultListCellRenderer { 296 297 public Renderer() { 298 setPreferredSize(new JLabel("MinSize").getPreferredSize()); 299 } 300 301 public Renderer(Container container) { 302 setPreferredSize(new JLabel("MinSize").getPreferredSize()); 303 this.container = container; 304 sf = new StringFitter(getFontMetrics(getFont())); 305 } 306 307 public Component getListCellRendererComponent(JList list, Object o, int index, boolean isSelected, boolean cellHasFocus) { 308 String name = null; 309 if (o instanceof URL) { 310 URL url = (URL) o; 311 312 // if not file URL 313 if (!url.getProtocol().equals("file")) { 314 name = url.toString(); 315 } 316 else { 317 // if file URL, remove the "file:" prefix 318 name = extractPrefix(url.toString(), "file:"); 319 String baseName = null; 320 name = new File(name).getAbsolutePath(); 321 322 File baseDir = mediaPane.getBaseDirectory(); 323 if (baseDir != null && baseDir.getParentFile() != null) { 324 baseName = baseDir.getParentFile().getAbsolutePath(); 325 } 326 // if contains base dir, only show file name 327 if (baseName != null && 328 name.startsWith(baseName) && 329 (name.length() > baseName.length())) { 330 name = name.substring(baseName.length() ); 331 // in case of Unix 332 if (name.startsWith(File.separator)) { 333 name = name.substring(1); 334 } 335 } 336 } 337 } 338 else 339 name = String.valueOf(o); 340 341 JLabel cell = (JLabel) super.getListCellRendererComponent(list, name, index, isSelected, cellHasFocus); 342 if(container != null) 343 cell.setText(sf.truncateBeginning(name, container.getWidth() - 17)); 344 cell.setToolTipText(name); 345 return cell; 346 } 347 348 private String extractPrefix(String origStr, String target) { 349 return (!origStr.startsWith(target)) ? origStr : origStr.substring(target.length()); 350 } 351 352 private Container container; 353 private StringFitter sf; 354 } 355 356 357 private UIFactory uif; 358 private String uiKey; 359 360 private History history; 361 362 private Action homeAction; 363 private Action backAction; 364 private Action forwardAction; 365 366 private JButton homeBtn; 367 private JButton backBtn; 368 private JButton forwardBtn; 369 370 private JComboBox selectBox; 371 372 private DefaultComboBoxModel model; 373 private Listener listener = new Listener(); 374 private JToolBar toolBar; 375 376 private static final int MAX_ROWS_DISPLAY = 20; 377 378 private MultiFormatPane mediaPane; 379 380 private URL homeURL; 381 382 383 }