1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * ident "%Z%%M% %I% %E% SMI" 24 * 25 * Copyright (c) 2000 by Sun Microsystems, Inc. 26 * All rights reserved. 27 */ 28 29 /* 30 * Copyright (C) 1996 Active Software, Inc. 31 * All rights reserved. 32 * 33 * @(#) TabbedFolder.java 1.20 - last change made 08/04/97 34 */ 35 36 package sunsoft.jws.visual.rt.awt; 37 38 import sunsoft.jws.visual.rt.base.Global; 39 40 import java.awt.*; 41 import java.util.*; 42 43 public class TabbedFolder extends CardPanel { 44 45 public static final int CONFIRM_SWITCH = 4862; 46 47 // 48 // Constants used for drawing the tabs 49 // 50 51 private static final int bd = 2; 52 private static final double BFACTOR = 0.8; 53 private static final double DFACTOR = 0.7; 54 55 private static final int tabipadx = 14; 56 private static final int tabipady = 14; 57 private static final int comppadx = 20; 58 private static final int comppady = 14; 59 private static final Insets folderInsets = new Insets(6, 6, 6, 6); 60 61 // 62 // Cached tab information 63 // 64 65 private Image buffer; 66 private int tabx[]; 67 private String tabtext[]; 68 private int tabW, tabH; 69 private boolean cancelSwitch = false; 70 71 TabbedFolder()72 public TabbedFolder() { 73 } 74 TabbedFolder(String tabs[])75 public TabbedFolder(String tabs[]) { 76 for (int i = 0; i < tabs.length; i++) { 77 super.addTab(tabs[i]); 78 } 79 } 80 newCardLabel()81 protected Label newCardLabel() { 82 return new Label(Global.getMsg( 83 "sunsoft.jws.visual.rt.awt.TabbedFolder.NewCardLabel")); 84 } 85 86 // 87 // Methods that comprise the public interface for TabbedFolder 88 // 89 addTab(String tab)90 public void addTab(String tab) { 91 super.addTab(tab); 92 flushCache(); 93 repaint(); 94 } 95 addTab(String tab, int index)96 public void addTab(String tab, int index) { 97 super.addTab(tab, index); 98 flushCache(); 99 repaint(); 100 } 101 renameTab(String oldName, String newName)102 public void renameTab(String oldName, String newName) { 103 super.renameTab(oldName, newName); 104 flushCache(); 105 repaint(); 106 } 107 removeTab(String tab)108 public void removeTab(String tab) { 109 super.removeTab(tab); 110 flushCache(); 111 repaint(); 112 } 113 removeAllTabs()114 public void removeAllTabs() { 115 super.removeAllTabs(); 116 flushCache(); 117 repaint(); 118 } 119 getCurrentFolder()120 public String getCurrentFolder() { 121 return getCurrentCard(); 122 } 123 show(String tab)124 public void show(String tab) { 125 super.show(tab); 126 repaint(); 127 } 128 129 // 130 // Overridden methods from Component 131 // 132 addNotify()133 public void addNotify() { 134 super.addNotify(); 135 flushCache(); 136 } 137 removeNotify()138 public void removeNotify() { 139 super.removeNotify(); 140 flushCache(); 141 } 142 setFont(Font font)143 public void setFont(Font font) { 144 super.setFont(font); 145 flushCache(); 146 } 147 minimumSize()148 public Dimension minimumSize() { 149 cacheTabInfo(); 150 151 Dimension d = super.minimumSize(); 152 int w = tabW + folderInsets.left + folderInsets.right; 153 if (w > d.width) 154 d = new Dimension(w, d.height); 155 156 return d; 157 } 158 preferredSize()159 public Dimension preferredSize() { 160 cacheTabInfo(); 161 162 Dimension d = super.preferredSize(); 163 int w = tabW + folderInsets.left + folderInsets.right; 164 if (w > d.width) 165 d = new Dimension(w, d.height); 166 167 return d; 168 } 169 insets()170 public Insets insets() { 171 cacheTabInfo(); 172 173 Insets insets = new Insets(0, 0, 0, 0); 174 insets.left = folderInsets.left + bd + comppadx/2; 175 insets.right = folderInsets.right + bd + comppadx/2; 176 insets.top = folderInsets.top + tabH + comppady/2; 177 insets.bottom = folderInsets.bottom + bd + comppady/2; 178 179 return insets; 180 } 181 182 // 183 // Event Handling 184 // 185 mouseDown(Event evt, int x, int y)186 public boolean mouseDown(Event evt, int x, int y) { 187 int index = calcTabIndex(x, y); 188 if (index >= 0 && index < tabs.size()) { 189 String name = (String)tabs.elementAt(index); 190 191 cancelSwitch = false; 192 postEvent(new Event(this, CONFIRM_SWITCH, name)); 193 194 if (!cancelSwitch) { 195 show(name); 196 postEvent(new Event(this, Event.ACTION_EVENT, name)); 197 } else { 198 cancelSwitch = false; 199 } 200 } 201 202 return false; 203 } 204 cancelSwitch()205 public void cancelSwitch() { 206 cancelSwitch = true; 207 } 208 calcTabIndex(int x, int y)209 private synchronized int calcTabIndex(int x, int y) { 210 cacheTabInfo(); 211 212 if (x < (folderInsets.left+tabx[0]) || 213 x > (folderInsets.left+tabx[tabx.length-1])) { 214 return -1; 215 } 216 if (y < (folderInsets.top+bd) || y > (folderInsets.top+tabH)) { 217 return -1; 218 } 219 220 for (int i = 0; i < tabtext.length; i++) { 221 if (x >= (folderInsets.left+tabx[i]) && 222 x <= (folderInsets.left + tabx[i+1])) { 223 return i; 224 } 225 } 226 227 return -1; 228 } 229 230 // 231 // Cache all the information and the image needed for the tabs. 232 // 233 cacheTabInfo()234 private synchronized void cacheTabInfo() { 235 if (tabx == null) { 236 if (getPeer() == null) 237 return; 238 239 FontMetrics fontMetrics = getFontMetrics(getFont()); 240 int len = tabs.size(); 241 242 if (len == 0) { 243 tabx = new int[2]; 244 tabtext = new String[1]; 245 tabtext[0] = Global.getMsg( 246 "sunsoft.jws.visual.rt.awt.TabbedFolder.Empty"); 247 tabx[0] = bd; 248 tabx[1] = tabx[0] + 249 fontMetrics.stringWidth(tabtext[0]) + tabipadx + 2*bd; 250 } else { 251 Enumeration e = tabs.elements(); 252 int i = 0; 253 int x = bd; 254 tabx = new int[tabs.size()+1]; 255 tabtext = new String[tabs.size()]; 256 257 while (e.hasMoreElements()) { 258 tabtext[i] = (String)e.nextElement(); 259 tabx[i] = x; 260 x += fontMetrics.stringWidth(tabtext[i]) + 261 tabipadx + 2*bd; 262 i++; 263 } 264 tabx[i] = x; 265 } 266 267 // Need 4 extra pixels: 2 on each end 268 tabW = tabx[tabx.length-1] - tabx[0] + 2*bd; 269 270 // Need 6 extra pixels: 4 on top, and 2 on the bottom 271 tabH = fontMetrics.getMaxAscent() + tabipady + 3*bd; 272 273 // Create the image buffer 274 buffer = createImage(tabW, tabH); 275 } 276 } 277 flushCache()278 private synchronized void flushCache() { 279 tabx = null; 280 tabtext = null; 281 tabW = 0; 282 tabH = 0; 283 buffer = null; 284 if (isValid()) 285 invalidate(); 286 } 287 288 // 289 // Drawing methods 290 // 291 update(Graphics g)292 public void update(Graphics g) { 293 if (Global.isWindows()) 294 g = getGraphics(); 295 296 cacheTabInfo(); 297 Dimension size = size(); 298 int x, y; 299 300 x = folderInsets.left + tabW; 301 y = folderInsets.top + tabH; 302 303 // Clear the background 304 g.setColor(getBackground()); 305 g.fillRect(0, 0, size.width, folderInsets.top); 306 g.fillRect(0, y, size.width, size.height-y); 307 g.fillRect(0, 0, folderInsets.left, size.height); 308 g.fillRect(x, 0, size.width-x, size.height); 309 310 draw(g); 311 } 312 paint(Graphics g)313 public void paint(Graphics g) { 314 if (Global.isWindows()) 315 g = getGraphics(); 316 draw(g); 317 } 318 draw(Graphics g)319 private synchronized void draw(Graphics g) { 320 cacheTabInfo(); 321 Dimension size = size(); 322 323 if (buffer != null) { 324 drawTabs(size); 325 g.drawImage(buffer, folderInsets.left, 326 folderInsets.top, null); 327 } 328 329 drawBox(g, size); 330 } 331 drawTabs(Dimension size)332 private synchronized void drawTabs(Dimension size) { 333 Graphics g = buffer.getGraphics(); 334 String card = getCurrentCard(); 335 int selIndex = -1; 336 if (card != null) 337 selIndex = tabs.indexOf(card); 338 339 g.setColor(getBackground()); 340 g.fillRect(0, 0, tabW, tabH); 341 342 for (int i = 0; i < tabtext.length; i++) { 343 if (i != selIndex) { 344 drawTab(g, i, false); 345 } 346 } 347 348 for (int i = 0; i < tabtext.length; i++) { 349 if (i == selIndex) { 350 drawTab(g, i, true); 351 break; 352 } 353 } 354 355 // Draw the left extra bit 356 g.setColor(brighter(getBackground())); 357 g.fillRect(0, tabH-bd, bd, bd); 358 359 // Draw the right extra bit 360 int rightEdge = tabx[tabx.length-1]; 361 if ((size.width - tabW) > (folderInsets.left + 362 folderInsets.right)) { 363 // The corner does not lie within the image. 364 // This can happen 365 // when the tabs do not completely fill 366 // the top of the folder. 367 g.setColor(brighter(getBackground())); 368 g.fillRect(tabW-bd, tabH-bd, bd, bd); 369 } else { 370 drawUpperRightCorner(g, tabW-bd, tabH-bd); 371 } 372 } 373 drawUpperRightCorner(Graphics g, int x, int y)374 private void drawUpperRightCorner(Graphics g, int x, int y) { 375 String card = getCurrentCard(); 376 int selIndex = -1; 377 if (card != null) 378 selIndex = tabs.indexOf(card); 379 380 g.setColor(darker(getBackground())); 381 fillRect(g, x, y, bd, bd); 382 383 int size = tabs.size(); 384 if (size == 0 || selIndex != size-1) { 385 g.setColor(brighter(getBackground())); 386 fillRect(g, x, y, 1, 1); 387 } 388 } 389 drawTab(Graphics g, int index, boolean selected)390 private void drawTab(Graphics g, int index, boolean selected) { 391 int x = tabx[index]; 392 int y = bd; 393 int w = tabx[index+1]-tabx[index]-1; 394 int h = tabH-bd-1; 395 396 if (selected) { 397 x -= bd; 398 y -= bd; 399 w += 2*bd; 400 h += 2*bd; 401 } 402 403 g.setColor(getBackground()); 404 draw3DOuterTab(g, x, y, w, h, selected); 405 draw3DInnerTab(g, x+1, y+1, w-2, h-2, selected); 406 407 x = tabx[index] + bd + (tabipadx/2); 408 y = tabH - bd - tabipady/2; 409 if (selected) 410 y -= bd; 411 412 g.setColor(getForeground()); 413 g.setFont(getFont()); 414 g.drawString(tabtext[index], x, y-1); 415 } 416 drawBox(Graphics g, Dimension size)417 private void drawBox(Graphics g, Dimension size) { 418 int x = folderInsets.left; 419 int y = folderInsets.top + tabH; 420 int w = size.width - (folderInsets.left + 421 folderInsets.right) - 1; 422 int h = size.height - (tabH + folderInsets.top + 423 folderInsets.bottom) - 1; 424 425 if (x >= size.width || y >= size.height || w <= 0 || h <= 0) 426 return; 427 428 g.setColor(getBackground()); 429 draw3DU(g, x, y, w, h, true); 430 431 // Draw the extra line on the top-right side if the tab image 432 // does not cover the area. The tab image is only as wide as 433 // the tabs, so we need to account for any possible extra space 434 // here. 435 if ((size.width - tabW) > (folderInsets.left + 436 folderInsets.right)) { 437 g.setColor(brighter(getBackground())); 438 fillRect(g, folderInsets.left + tabW, 439 folderInsets.top + tabH - bd, 440 size.width - (folderInsets.left + folderInsets.right + 441 tabW), 442 bd); 443 drawUpperRightCorner(g, 444 size.width - folderInsets.right - bd, 445 folderInsets.top + tabH - bd); 446 } 447 } 448 draw3DU(Graphics g, int x, int y, int width, int height, boolean raised)449 private void draw3DU(Graphics g, int x, int y, int width, 450 int height, boolean raised) { 451 Color c = g.getColor(); 452 Color brighter = brighter(c); 453 Color darker = darker(c); 454 455 g.setColor(raised ? brighter : darker); 456 g.drawLine(x, y, x, y + height); 457 g.drawLine(x+1, y, x+1, y + height); 458 459 g.setColor(raised ? darker : brighter); 460 g.drawLine(x + 1, y + height, x + width, y + height); 461 g.drawLine(x + 2, y + height - 1, x + width - 1, 462 y + height - 1); 463 464 g.drawLine(x + width, y, x + width, y + height - 1); 465 g.drawLine(x + width - 1, y, x + width - 1, y + height - 1); 466 g.setColor(c); 467 } 468 draw3DInnerTab(Graphics g, int x, int y, int width, int height, boolean selected)469 private void draw3DInnerTab(Graphics g, 470 int x, int y, int width, int height, 471 boolean selected) { 472 Color c = g.getColor(); 473 Color brighter = brighter(c); 474 Color darker = darker(c); 475 476 g.setColor(brighter); 477 g.drawLine(x, y, x, y + height); 478 g.drawLine(x + 1, y, x + width - 1, y); 479 if (!selected) 480 g.drawLine(x + 1, y + height, x + width + 1, y + height); 481 g.setColor(darker); 482 g.drawLine(x + width, y, x + width, y + height - 1); 483 g.setColor(c); 484 } 485 draw3DOuterTab(Graphics g, int x, int y, int width, int height, boolean selected)486 private void draw3DOuterTab(Graphics g, 487 int x, int y, int width, int height, 488 boolean selected) { 489 Color c = g.getColor(); 490 Color brighter = brighter(c); 491 Color darker = darker(c); 492 493 // Left, Top, Bottom, Right 494 495 g.setColor(brighter); 496 g.drawLine(x, y + 2, x, y + height); 497 g.drawLine(x + 2, y, x + width - 2, y); 498 if (!selected) 499 g.drawLine(x + 1, y + height, x + width, y + height); 500 g.setColor(darker); 501 g.drawLine(x + width, y + 2, x + width, y + height - 2); 502 g.setColor(c); 503 } 504 505 /** 506 * Returns a brighter version of this color. 507 */ brighter(Color c)508 private Color brighter(Color c) { 509 // fix for bug where the brighter color doesn't show up 510 // against a white background The Util.brighter will return 511 // new Color(<some light grey>) for whites. 512 return Global.util.brighter(c); 513 } 514 515 /** 516 * Returns a darker version of this color. 517 */ darker(Color c)518 private Color darker(Color c) { 519 return new Color(Math.max((int)(c.getRed() *DFACTOR), 0), 520 Math.max((int)(c.getGreen()*DFACTOR), 0), 521 Math.max((int)(c.getBlue() *DFACTOR), 0)); 522 } 523 524 // Workaround for Windows fillRect bug. 525 // The Windows fillRect sometimes 526 // fills the lower-right edges when it shouldn't. 527 // The bug appears to 528 // only happen is certain situations. It does 529 // not seem to happen when 530 // drawing inside an off-screen buffer. fillRect(Graphics g, int x, int y, int w, int h)531 private void fillRect(Graphics g, int x, int y, int w, int h) { 532 if (Global.isWindows()) { 533 w -= 1; 534 h -= 1; 535 g.drawRect(x, y, w, h); 536 } 537 g.fillRect(x, y, w, h); 538 } 539 } 540