1 /******************************************************************************* 2 * Copyright (c) 2000, 2016 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Ralf M Petter <ralf.petter@gmail.com> - Bug 509719 14 *******************************************************************************/ 15 package org.eclipse.ui.internal.forms.widgets; 16 17 import java.util.Hashtable; 18 19 import org.eclipse.core.runtime.Assert; 20 import org.eclipse.core.runtime.ListenerList; 21 import org.eclipse.jface.action.IMenuManager; 22 import org.eclipse.jface.action.IToolBarManager; 23 import org.eclipse.jface.action.ToolBarManager; 24 import org.eclipse.jface.dialogs.Dialog; 25 import org.eclipse.jface.dialogs.IMessageProvider; 26 import org.eclipse.jface.resource.JFaceResources; 27 import org.eclipse.swt.SWT; 28 import org.eclipse.swt.custom.CLabel; 29 import org.eclipse.swt.dnd.DragSourceListener; 30 import org.eclipse.swt.dnd.DropTargetListener; 31 import org.eclipse.swt.dnd.Transfer; 32 import org.eclipse.swt.events.MouseEvent; 33 import org.eclipse.swt.events.MouseTrackListener; 34 import org.eclipse.swt.graphics.Color; 35 import org.eclipse.swt.graphics.Font; 36 import org.eclipse.swt.graphics.FontMetrics; 37 import org.eclipse.swt.graphics.GC; 38 import org.eclipse.swt.graphics.Image; 39 import org.eclipse.swt.graphics.Point; 40 import org.eclipse.swt.graphics.Rectangle; 41 import org.eclipse.swt.widgets.Canvas; 42 import org.eclipse.swt.widgets.Composite; 43 import org.eclipse.swt.widgets.Control; 44 import org.eclipse.swt.widgets.Layout; 45 import org.eclipse.swt.widgets.ToolBar; 46 import org.eclipse.ui.forms.IFormColors; 47 import org.eclipse.ui.forms.IMessage; 48 import org.eclipse.ui.forms.events.IHyperlinkListener; 49 import org.eclipse.ui.forms.widgets.Hyperlink; 50 import org.eclipse.ui.forms.widgets.ILayoutExtension; 51 import org.eclipse.ui.forms.widgets.SizeCache; 52 import org.eclipse.ui.internal.forms.IMessageToolTipManager; 53 import org.eclipse.ui.internal.forms.MessageManager; 54 55 /** 56 * Form header moved out of the form class. 57 */ 58 public class FormHeading extends Canvas { 59 private static final int TITLE_HMARGIN = 1; 60 private static final int SPACING = 5; 61 private static final int VSPACING = 5; 62 private static final int HMARGIN = 6; 63 private static final int VMARGIN = 1; 64 private static final int CLIENT_MARGIN = 1; 65 66 private static final int SEPARATOR = 1 << 1; 67 private static final int BOTTOM_TOOLBAR = 1 << 2; 68 private static final int BACKGROUND_IMAGE_TILED = 1 << 3; 69 private static final int SEPARATOR_HEIGHT = 2; 70 private static final int MESSAGE_AREA_LIMIT = 50; 71 static IMessage[] NULL_MESSAGE_ARRAY = new IMessage[] {}; 72 73 public static final String COLOR_BASE_BG = "baseBg"; //$NON-NLS-1$ 74 75 private Image backgroundImage; 76 77 private Image gradientImage; 78 79 Hashtable<String, Color> colors = new Hashtable<>(); 80 81 private int flags; 82 83 private GradientInfo gradientInfo; 84 85 private ToolBarManager toolBarManager; 86 87 private SizeCache toolbarCache = new SizeCache(); 88 89 private SizeCache clientCache = new SizeCache(); 90 91 private SizeCache messageCache = new SizeCache(); 92 93 private SizeCache titleRegionCache = new SizeCache(); 94 95 private TitleRegion titleRegion; 96 97 private MessageRegion messageRegion; 98 99 private IMessageToolTipManager messageToolTipManager = new DefaultMessageToolTipManager(); 100 101 private Control headClient; 102 103 private class DefaultMessageToolTipManager implements 104 IMessageToolTipManager { 105 @Override createToolTip(Control control, boolean imageLabel)106 public void createToolTip(Control control, boolean imageLabel) { 107 } 108 109 @Override update()110 public void update() { 111 String details = getMessageType() == 0 ? null : MessageManager 112 .createDetails(getChildrenMessages()); 113 if (messageRegion != null) 114 messageRegion.updateToolTip(details); 115 if (getMessageType() > 0 116 && (details == null || details.length() == 0)) 117 details = getMessage(); 118 titleRegion.updateToolTip(details); 119 } 120 } 121 122 private static class GradientInfo { 123 Color[] gradientColors; 124 125 int[] percents; 126 127 boolean vertical; 128 } 129 130 private class FormHeadingLayout extends Layout implements ILayoutExtension { 131 private static final int MIN_WIDTH = -2; 132 133 @Override computeMinimumWidth(Composite composite, boolean flushCache)134 public int computeMinimumWidth(Composite composite, boolean flushCache) { 135 return layout(composite, false, 0, 0, MIN_WIDTH, SWT.DEFAULT, flushCache).x; 136 } 137 138 @Override computeMaximumWidth(Composite composite, boolean flushCache)139 public int computeMaximumWidth(Composite composite, boolean flushCache) { 140 return computeSize(composite, SWT.DEFAULT, SWT.DEFAULT, flushCache).x; 141 } 142 143 @Override computeSize(Composite composite, int wHint, int hHint, boolean flushCache)144 public Point computeSize(Composite composite, int wHint, int hHint, 145 boolean flushCache) { 146 return layout(composite, false, 0, 0, wHint, hHint, flushCache); 147 } 148 149 @Override layout(Composite composite, boolean flushCache)150 protected void layout(Composite composite, boolean flushCache) { 151 Rectangle rect = composite.getClientArea(); 152 layout(composite, true, rect.x, rect.y, rect.width, rect.height, 153 flushCache); 154 } 155 layout(Composite composite, boolean move, int x, int y, int width, int height, boolean flushCache)156 private Point layout(Composite composite, boolean move, int x, int y, 157 int width, int height, boolean flushCache) { 158 titleRegionCache.setControl(titleRegion); 159 160 Point tsize = null; 161 Point msize = null; 162 Point tbsize = null; 163 Point clsize = null; 164 165 if (flushCache) { 166 clientCache.flush(); 167 messageCache.flush(); 168 toolbarCache.flush(); 169 titleRegionCache.flush(); 170 } 171 if (hasToolBar()) { 172 ToolBar tb = toolBarManager.getControl(); 173 toolbarCache.setControl(tb); 174 tbsize = toolbarCache.computeSize(SWT.DEFAULT, SWT.DEFAULT); 175 } 176 if (headClient != null) { 177 clientCache.setControl(headClient); 178 int clientWidthHint = width; 179 if (clientWidthHint != SWT.DEFAULT && clientWidthHint != MIN_WIDTH) { 180 clientWidthHint -= HMARGIN * 2; 181 if (tbsize != null && getToolBarAlignment() == SWT.BOTTOM) 182 clientWidthHint -= tbsize.x + SPACING; 183 } 184 clsize = computeSize(clientCache, clientWidthHint); 185 } 186 int totalFlexWidth = width; 187 int flexWidth = totalFlexWidth; 188 if (totalFlexWidth != SWT.DEFAULT && totalFlexWidth != MIN_WIDTH) { 189 totalFlexWidth -= TITLE_HMARGIN * 2; 190 // complete right margin 191 if (hasToolBar() && getToolBarAlignment() == SWT.TOP 192 || hasMessageRegion()) 193 totalFlexWidth -= SPACING; 194 // subtract tool bar 195 if (hasToolBar() && getToolBarAlignment() == SWT.TOP) 196 totalFlexWidth -= tbsize.x + SPACING; 197 flexWidth = totalFlexWidth; 198 if (hasMessageRegion()) { 199 // remove message region spacing and divide by 2 200 flexWidth -= SPACING; 201 // flexWidth /= 2; 202 } 203 } 204 /* 205 * // compute text and message sizes tsize = 206 * titleRegion.computeSize(flexWidth, SWT.DEFAULT); if (flexWidth != 207 * SWT.DEFAULT && tsize.x < flexWidth) flexWidth += flexWidth - 208 * tsize.x; 209 * 210 * if (hasMessageRegion()) { 211 * messageCache.setControl(messageRegion.getMessageControl()); msize = 212 * messageCache.computeSize(flexWidth, SWT.DEFAULT); int maxWidth = 213 * messageCache.computeSize(SWT.DEFAULT, SWT.DEFAULT).x; if 214 * (maxWidth < msize.x) { msize.x = maxWidth; // recompute title 215 * with the reclaimed width int tflexWidth = totalFlexWidth - 216 * SPACING - msize.x; tsize = titleRegion.computeSize(tflexWidth, 217 * SWT.DEFAULT); } } 218 */ 219 if (!hasMessageRegion()) { 220 tsize = computeSize(titleRegionCache, flexWidth); 221 } else { 222 // Total flexible area in the first row is flexWidth. 223 // Try natural widths of title and 224 Point tsizeNatural = titleRegionCache.computeSize(SWT.DEFAULT, 225 SWT.DEFAULT); 226 messageCache.setControl(messageRegion.getMessageControl()); 227 Point msizeNatural = messageCache.computeSize(SWT.DEFAULT, 228 SWT.DEFAULT); 229 // try to fit all 230 tsize = tsizeNatural; 231 msize = msizeNatural; 232 if (flexWidth != SWT.DEFAULT && flexWidth != MIN_WIDTH) { 233 int needed = tsizeNatural.x + msizeNatural.x; 234 if (needed > flexWidth) { 235 // too big - try to limit the message 236 int mwidth = flexWidth - tsizeNatural.x; 237 if (mwidth >= MESSAGE_AREA_LIMIT) { 238 msize.x = mwidth; 239 } else { 240 // message is squeezed to the limit 241 int flex = flexWidth - MESSAGE_AREA_LIMIT; 242 tsize = titleRegion.computeSize(flex, SWT.DEFAULT); 243 msize.x = MESSAGE_AREA_LIMIT; 244 } 245 } 246 } 247 } 248 249 Point size = new Point(width, height); 250 if (!move) { 251 // compute sizes 252 int width1 = 2 * TITLE_HMARGIN; 253 width1 += tsize.x; 254 if (msize != null) 255 width1 += SPACING + msize.x; 256 if (tbsize != null && getToolBarAlignment() == SWT.TOP) 257 width1 += SPACING + tbsize.x; 258 if (msize != null 259 || (tbsize != null && getToolBarAlignment() == SWT.TOP)) 260 width1 += SPACING; 261 size.x = width1; 262 if (clsize != null) { 263 int width2 = clsize.x; 264 if (tbsize != null && getToolBarAlignment() == SWT.BOTTOM) 265 width2 += SPACING + tbsize.x; 266 width2 += 2 * HMARGIN; 267 size.x = Math.max(width1, width2); 268 } 269 // height, first row 270 size.y = tsize.y; 271 if (msize != null) 272 size.y = Math.max(msize.y, size.y); 273 if (tbsize != null && getToolBarAlignment() == SWT.TOP) 274 size.y = Math.max(tbsize.y, size.y); 275 if (size.y > 0) 276 size.y += VMARGIN * 2; 277 // add second row 278 int height2 = 0; 279 if (tbsize != null && getToolBarAlignment() == SWT.BOTTOM) 280 height2 = tbsize.y; 281 if (clsize != null) 282 height2 = Math.max(height2, clsize.y); 283 if (height2 > 0) 284 size.y += VSPACING + height2 + CLIENT_MARGIN; 285 // add separator 286 if (size.y > 0 && isSeparatorVisible()) 287 size.y += SEPARATOR_HEIGHT; 288 } else { 289 // position controls 290 int xloc = x; 291 int yloc = y + VMARGIN; 292 int row1Height = tsize.y; 293 if (hasMessageRegion()) 294 row1Height = Math.max(row1Height, msize.y); 295 if (hasToolBar() && getToolBarAlignment() == SWT.TOP) 296 row1Height = Math.max(row1Height, tbsize.y); 297 titleRegion.setBounds(xloc, 298 // yloc + row1Height / 2 - tsize.y / 2, 299 yloc, tsize.x, tsize.y); 300 xloc += tsize.x; 301 302 if (hasMessageRegion()) { 303 xloc += SPACING; 304 int messageOffset = 0; 305 if (tsize.y > 0) { 306 // space between title area and title text 307 int titleLeadingSpace = (tsize.y - titleRegion.getFontHeight()) / 2; 308 // space between message control and message text 309 int messageLeadingSpace = (msize.y - messageRegion.getFontHeight()) / 2; 310 // how much to offset the message so baselines align 311 messageOffset = (titleLeadingSpace + titleRegion.getFontBaselineHeight()) 312 - (messageLeadingSpace + messageRegion.getFontBaselineHeight()); 313 } 314 315 messageRegion 316 .getMessageControl() 317 .setBounds( 318 xloc, 319 tsize.y > 0 ? (yloc + messageOffset) 320 : (yloc + row1Height / 2 - msize.y / 2), 321 msize.x, msize.y); 322 xloc += msize.x; 323 } 324 if (toolBarManager != null) 325 toolBarManager.getControl().setVisible( 326 !toolBarManager.isEmpty()); 327 if (tbsize != null && getToolBarAlignment() == SWT.TOP) { 328 ToolBar tbar = toolBarManager.getControl(); 329 tbar.setBounds(x + width - 1 - tbsize.x - HMARGIN, yloc 330 + row1Height - 1 - tbsize.y, tbsize.x, tbsize.y); 331 } 332 // second row 333 xloc = HMARGIN; 334 yloc += row1Height + VSPACING; 335 int tw = 0; 336 337 if (tbsize != null && getToolBarAlignment() == SWT.BOTTOM) { 338 ToolBar tbar = toolBarManager.getControl(); 339 tbar.setBounds(x + width - 1 - tbsize.x - HMARGIN, yloc, 340 tbsize.x, tbsize.y); 341 tw = tbsize.x + SPACING; 342 } 343 if (headClient != null) { 344 int carea = width - HMARGIN * 2 - tw; 345 headClient.setBounds(xloc, yloc, carea, clsize.y); 346 } 347 } 348 return size; 349 } 350 351 /** 352 * Computes the preferred or minimum size of the given client cache. 353 * 354 * @param clientCache 355 * size cache for the control whose size is being computed 356 * @param wHint 357 * the width of the control, in pixels, or SWT.DEFAULT if the 358 * preferred size is being computed, or MIN_WIDTH if the minimum size 359 * is being computed 360 */ computeSize(SizeCache clientCache, int wHint)361 private Point computeSize(SizeCache clientCache, int wHint) { 362 if (wHint == MIN_WIDTH) { 363 int minWidth = clientCache.computeMinimumWidth(); 364 return clientCache.computeSize(minWidth, SWT.DEFAULT); 365 } 366 return clientCache.computeSize(wHint, SWT.DEFAULT); 367 } 368 } 369 370 @Override forceFocus()371 public boolean forceFocus() { 372 return false; 373 } 374 hasToolBar()375 private boolean hasToolBar() { 376 return toolBarManager != null && !toolBarManager.isEmpty(); 377 } 378 hasMessageRegion()379 private boolean hasMessageRegion() { 380 return messageRegion != null && !messageRegion.isEmpty(); 381 } 382 383 private class MessageRegion { 384 private String message; 385 private int messageType; 386 private CLabel messageLabel; 387 private IMessage[] messages; 388 private Hyperlink messageHyperlink; 389 private ListenerList<IHyperlinkListener> listeners; 390 private Color fg; 391 private int fontHeight = -1; 392 private int fontBaselineHeight = -1; 393 MessageRegion()394 public MessageRegion() { 395 } 396 isDisposed()397 public boolean isDisposed() { 398 Control c = getMessageControl(); 399 return c != null && c.isDisposed(); 400 } 401 isEmpty()402 public boolean isEmpty() { 403 Control c = getMessageControl(); 404 if (c == null) 405 return true; 406 return !c.getVisible(); 407 } 408 getFontHeight()409 public int getFontHeight() { 410 if (fontHeight == -1) { 411 Control c = getMessageControl(); 412 if (c == null) 413 return 0; 414 GC gc = new GC(c.getDisplay()); 415 gc.setFont(c.getFont()); 416 fontHeight = gc.getFontMetrics().getHeight(); 417 gc.dispose(); 418 } 419 return fontHeight; 420 } 421 getFontBaselineHeight()422 public int getFontBaselineHeight() { 423 if (fontBaselineHeight == -1) { 424 Control c = getMessageControl(); 425 if (c == null) 426 return 0; 427 GC gc = new GC(c.getDisplay()); 428 gc.setFont(c.getFont()); 429 FontMetrics fm = gc.getFontMetrics(); 430 fontBaselineHeight = fm.getHeight() - fm.getDescent(); 431 gc.dispose(); 432 } 433 return fontBaselineHeight; 434 } 435 showMessage(String newMessage, int newType, IMessage[] messages)436 public void showMessage(String newMessage, int newType, 437 IMessage[] messages) { 438 Control oldControl = getMessageControl(); 439 int oldType = messageType; 440 this.message = newMessage; 441 this.messageType = newType; 442 this.messages = messages; 443 if (newMessage == null) { 444 // clearing of the message 445 if (oldControl != null && oldControl.getVisible()) 446 oldControl.setVisible(false); 447 if (oldType != newType) 448 updateForeground(); 449 return; 450 } 451 ensureControlExists(); 452 if (needHyperlink()) { 453 messageHyperlink.setText(newMessage); 454 messageHyperlink.setHref(messages); 455 } else { 456 messageLabel.setText(newMessage); 457 } 458 if (oldType != newType) 459 updateForeground(); 460 } 461 updateToolTip(String toolTip)462 public void updateToolTip(String toolTip) { 463 Control control = getMessageControl(); 464 if (control != null) 465 control.setToolTipText(toolTip); 466 } 467 getMessage()468 public String getMessage() { 469 return message; 470 } 471 getMessageType()472 public int getMessageType() { 473 return messageType; 474 } 475 getChildrenMessages()476 public IMessage[] getChildrenMessages() { 477 return messages; 478 } 479 getMessageControl()480 public Control getMessageControl() { 481 if (needHyperlink() && messageHyperlink != null) 482 return messageHyperlink; 483 return messageLabel; 484 } 485 getMessageImage()486 public Image getMessageImage() { 487 switch (messageType) { 488 case IMessageProvider.INFORMATION: 489 return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_INFO); 490 case IMessageProvider.WARNING: 491 return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_WARNING); 492 case IMessageProvider.ERROR: 493 return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR); 494 default: 495 return null; 496 } 497 } 498 addMessageHyperlinkListener(IHyperlinkListener listener)499 public void addMessageHyperlinkListener(IHyperlinkListener listener) { 500 if (listeners == null) 501 listeners = new ListenerList<>(); 502 listeners.add(listener); 503 ensureControlExists(); 504 if (messageHyperlink != null) 505 messageHyperlink.addHyperlinkListener(listener); 506 if (listeners.size() == 1) 507 updateForeground(); 508 } 509 removeMessageHyperlinkListener(IHyperlinkListener listener)510 private void removeMessageHyperlinkListener(IHyperlinkListener listener) { 511 if (listeners != null) { 512 listeners.remove(listener); 513 if (messageHyperlink != null) 514 messageHyperlink.removeHyperlinkListener(listener); 515 if (listeners.isEmpty()) 516 listeners = null; 517 ensureControlExists(); 518 if (listeners == null && !isDisposed()) 519 updateForeground(); 520 } 521 } 522 ensureControlExists()523 private void ensureControlExists() { 524 if (needHyperlink()) { 525 if (messageLabel != null) 526 messageLabel.setVisible(false); 527 if (messageHyperlink == null) { 528 messageHyperlink = new Hyperlink(FormHeading.this, SWT.NULL); 529 messageHyperlink.setUnderlined(true); 530 messageHyperlink.setBackground(getBackground()); 531 messageHyperlink.setText(message); 532 messageHyperlink.setHref(messages); 533 for (IHyperlinkListener element : listeners) 534 messageHyperlink 535 .addHyperlinkListener(element); 536 if (messageToolTipManager != null) 537 messageToolTipManager.createToolTip(messageHyperlink, false); 538 } else if (!messageHyperlink.getVisible()) { 539 messageHyperlink.setText(message); 540 messageHyperlink.setHref(messages); 541 messageHyperlink.setVisible(true); 542 } 543 } else { 544 // need a label 545 if (messageHyperlink != null) 546 messageHyperlink.setVisible(false); 547 if (messageLabel == null) { 548 messageLabel = new CLabel(FormHeading.this, SWT.NULL); 549 messageLabel.setBackground(getBackground()); 550 messageLabel.setText(message); 551 if (messageToolTipManager != null) 552 messageToolTipManager.createToolTip(messageLabel, false); 553 } else if (!messageLabel.getVisible()) { 554 messageLabel.setText(message); 555 messageLabel.setVisible(true); 556 } 557 } 558 updateForeground(); 559 layout(true); 560 } 561 needHyperlink()562 private boolean needHyperlink() { 563 return messageType > 0 && listeners != null; 564 } 565 setBackground(Color bg)566 public void setBackground(Color bg) { 567 if (messageHyperlink != null) 568 messageHyperlink.setBackground(bg); 569 if (messageLabel != null) 570 messageLabel.setBackground(bg); 571 } 572 setForeground(Color fg)573 public void setForeground(Color fg) { 574 this.fg = fg; 575 updateForeground(); 576 } 577 updateForeground()578 private void updateForeground() { 579 Color theFg; 580 581 switch (messageType) { 582 case IMessageProvider.ERROR: 583 theFg = getDisplay().getSystemColor(SWT.COLOR_RED); 584 break; 585 case IMessageProvider.WARNING: 586 theFg = getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW); 587 break; 588 default: 589 theFg = fg; 590 } 591 getMessageControl().setForeground(theFg); 592 } 593 } 594 595 /** 596 * Creates the form content control as a child of the provided parent. 597 * 598 * @param parent 599 * the parent widget 600 */ FormHeading(Composite parent, int style)601 public FormHeading(Composite parent, int style) { 602 super(parent, style); 603 setBackgroundMode(SWT.INHERIT_DEFAULT); 604 addListener(SWT.Paint, e -> onPaint(e.gc)); 605 addListener(SWT.Dispose, e -> { 606 if (gradientImage != null) { 607 FormImages.getInstance().markFinished(gradientImage, getDisplay()); 608 gradientImage = null; 609 } 610 }); 611 addListener(SWT.Resize, e -> { 612 if (gradientInfo != null || (backgroundImage != null && !isBackgroundImageTiled())) 613 updateGradientImage(); 614 }); 615 addMouseMoveListener(e -> updateTitleRegionHoverState(e)); 616 addMouseTrackListener(new MouseTrackListener() { 617 @Override 618 public void mouseEnter(MouseEvent e) { 619 updateTitleRegionHoverState(e); 620 } 621 622 @Override 623 public void mouseExit(MouseEvent e) { 624 titleRegion.setHoverState(TitleRegion.STATE_NORMAL); 625 } 626 627 @Override 628 public void mouseHover(MouseEvent e) { 629 } 630 }); 631 super.setLayout(new FormHeadingLayout()); 632 titleRegion = new TitleRegion(this); 633 } 634 635 /** 636 * Fully delegates the size computation to the internal layout manager. 637 */ 638 @Override computeSize(int wHint, int hHint, boolean changed)639 public final Point computeSize(int wHint, int hHint, boolean changed) { 640 return ((FormHeadingLayout) getLayout()).computeSize(this, wHint, 641 hHint, changed); 642 } 643 644 /** 645 * Prevents from changing the custom control layout. 646 */ 647 @Override setLayout(Layout layout)648 public final void setLayout(Layout layout) { 649 } 650 651 /** 652 * Returns the title text that will be rendered at the top of the form. 653 * 654 * @return the title text 655 */ getText()656 public String getText() { 657 return titleRegion.getText(); 658 } 659 660 /** 661 * Returns the title image that will be rendered to the left of the title. 662 * 663 * @return the title image 664 * @since 3.2 665 */ getImage()666 public Image getImage() { 667 return titleRegion.getImage(); 668 } 669 670 /** 671 * Sets the background color of the header. 672 */ 673 @Override setBackground(Color bg)674 public void setBackground(Color bg) { 675 super.setBackground(bg); 676 internalSetBackground(bg); 677 } 678 internalSetBackground(Color bg)679 private void internalSetBackground(Color bg) { 680 titleRegion.setBackground(bg); 681 if (messageRegion != null) 682 messageRegion.setBackground(bg); 683 if (toolBarManager != null) 684 toolBarManager.getControl().setBackground(bg); 685 putColor(COLOR_BASE_BG, bg); 686 } 687 688 /** 689 * Sets the foreground color of the header. 690 */ 691 @Override setForeground(Color fg)692 public void setForeground(Color fg) { 693 super.setForeground(fg); 694 titleRegion.setForeground(fg); 695 if (messageRegion != null) 696 messageRegion.setForeground(fg); 697 } 698 699 /** 700 * Sets the text to be rendered at the top of the form above the body as a 701 * title. 702 * 703 * @param text 704 * the title text 705 */ setText(String text)706 public void setText(String text) { 707 titleRegion.setText(text); 708 } 709 710 /** 711 * Sets whether ther text in the title region should be selectable. 712 * <p> 713 * Note: If {@link #addDragSupport(int, Transfer[], DragSourceListener) drag 714 * support} is also enabled, text selection has priority. Dragging still works 715 * in the non-text parts of the title area. 716 * 717 * @param selectable whether the title text should be selectable 718 */ setTextSelectable(boolean selectable)719 public void setTextSelectable(boolean selectable) { 720 titleRegion.setTextSelectable(selectable); 721 } 722 723 @Override setFont(Font font)724 public void setFont(Font font) { 725 super.setFont(font); 726 titleRegion.setFont(font); 727 } 728 729 /** 730 * Sets the image to be rendered to the left of the title. 731 * 732 * @param image 733 * the title image or <code>null</code> to show no image. 734 * @since 3.2 735 */ setImage(Image image)736 public void setImage(Image image) { 737 titleRegion.setImage(image); 738 if (messageRegion != null) 739 titleRegion.updateImage(messageRegion.getMessageImage(), true); 740 else 741 titleRegion.updateImage(null, true); 742 } 743 setTextBackground(Color[] gradientColors, int[] percents, boolean vertical)744 public void setTextBackground(Color[] gradientColors, int[] percents, 745 boolean vertical) { 746 if (gradientColors != null) { 747 gradientInfo = new GradientInfo(); 748 gradientInfo.gradientColors = gradientColors; 749 gradientInfo.percents = percents; 750 gradientInfo.vertical = vertical; 751 setBackground(null); 752 updateGradientImage(); 753 } else { 754 // reset 755 gradientInfo = null; 756 if (gradientImage != null) { 757 FormImages.getInstance().markFinished(gradientImage, getDisplay()); 758 gradientImage = null; 759 setBackgroundImage(null); 760 } 761 } 762 } 763 setHeadingBackgroundImage(Image image)764 public void setHeadingBackgroundImage(Image image) { 765 this.backgroundImage = image; 766 if (image != null) 767 setBackground(null); 768 if (isBackgroundImageTiled()) { 769 setBackgroundImage(image); 770 } else 771 updateGradientImage(); 772 } 773 getHeadingBackgroundImage()774 public Image getHeadingBackgroundImage() { 775 return backgroundImage; 776 } 777 setBackgroundImageTiled(boolean tiled)778 public void setBackgroundImageTiled(boolean tiled) { 779 if (tiled) 780 flags |= BACKGROUND_IMAGE_TILED; 781 else 782 flags &= ~BACKGROUND_IMAGE_TILED; 783 setHeadingBackgroundImage(this.backgroundImage); 784 } 785 isBackgroundImageTiled()786 public boolean isBackgroundImageTiled() { 787 return (flags & BACKGROUND_IMAGE_TILED) != 0; 788 } 789 790 @Override setBackgroundImage(Image image)791 public void setBackgroundImage(Image image) { 792 super.setBackgroundImage(image); 793 if (image != null) { 794 internalSetBackground(null); 795 } 796 } 797 798 /** 799 * Returns the tool bar manager that is used to manage tool items in the 800 * form's title area. 801 * 802 * @return form tool bar manager 803 */ getToolBarManager()804 public IToolBarManager getToolBarManager() { 805 if (toolBarManager == null) { 806 toolBarManager = new ToolBarManager(SWT.FLAT); 807 ToolBar toolbar = toolBarManager.createControl(this); 808 toolbar.setBackground(getBackground()); 809 toolbar.setForeground(getForeground()); 810 toolbar.setCursor(FormsResources.getHandCursor()); 811 addDisposeListener(e -> { 812 if (toolBarManager != null) { 813 toolBarManager.dispose(); 814 toolBarManager.removeAll(); 815 toolBarManager = null; 816 } 817 }); 818 } 819 return toolBarManager; 820 } 821 822 /** 823 * Returns the menu manager that is used to manage tool items in the form's 824 * title area. 825 * 826 * @return form drop-down menu manager 827 * @since 3.3 828 */ getMenuManager()829 public IMenuManager getMenuManager() { 830 return titleRegion.getMenuManager(); 831 } 832 833 /** 834 * Updates the local tool bar manager if used. Does nothing if local tool 835 * bar manager has not been created yet. 836 */ updateToolBar()837 public void updateToolBar() { 838 if (toolBarManager != null) 839 toolBarManager.update(false); 840 } 841 onPaint(GC gc)842 private void onPaint(GC gc) { 843 if (!isSeparatorVisible() && getBackgroundImage() == null) 844 return; 845 Rectangle carea = getClientArea(); 846 if (carea.width == 0 || carea.height == 0) { 847 return; 848 } 849 Image buffer = new Image(getDisplay(), carea.width, carea.height); 850 buffer.setBackground(getBackground()); 851 GC igc = new GC(buffer); 852 igc.setBackground(getBackground()); 853 igc.fillRectangle(0, 0, carea.width, carea.height); 854 if (getBackgroundImage() != null) { 855 if (gradientInfo != null) 856 drawBackground(igc, carea.x, carea.y, carea.width, carea.height); 857 else { 858 Image bgImage = getBackgroundImage(); 859 Rectangle ibounds = bgImage.getBounds(); 860 drawBackground(igc, carea.x, carea.y, ibounds.width, 861 ibounds.height); 862 } 863 } 864 865 if (isSeparatorVisible()) { 866 // bg separator 867 if (hasColor(IFormColors.H_BOTTOM_KEYLINE1)) 868 igc.setForeground(getColor(IFormColors.H_BOTTOM_KEYLINE1)); 869 else 870 igc.setForeground(getBackground()); 871 igc.drawLine(carea.x, carea.height - 2, carea.x + carea.width - 1, 872 carea.height - 2); 873 if (hasColor(IFormColors.H_BOTTOM_KEYLINE2)) 874 igc.setForeground(getColor(IFormColors.H_BOTTOM_KEYLINE2)); 875 else 876 igc.setForeground(getForeground()); 877 igc.drawLine(carea.x, carea.height - 1, carea.x + carea.width - 1, 878 carea.height - 1); 879 } 880 igc.dispose(); 881 gc.drawImage(buffer, carea.x, carea.y); 882 buffer.dispose(); 883 } 884 updateTitleRegionHoverState(MouseEvent e)885 private void updateTitleRegionHoverState(MouseEvent e) { 886 Rectangle titleRect = titleRegion.getBounds(); 887 titleRect.width += titleRect.x + 15; 888 titleRect.height += titleRect.y + 15; 889 titleRect.x = 0; 890 titleRect.y = 0; 891 if (titleRect.contains(e.x, e.y)) 892 titleRegion.setHoverState(TitleRegion.STATE_HOVER_LIGHT); 893 else 894 titleRegion.setHoverState(TitleRegion.STATE_NORMAL); 895 } 896 updateGradientImage()897 private void updateGradientImage() { 898 Rectangle rect = getBounds(); 899 Image oldGradientImage = gradientImage; 900 gradientImage = null; 901 if (gradientInfo != null) { 902 gradientImage = FormImages.getInstance().getGradient(gradientInfo.gradientColors, gradientInfo.percents, 903 gradientInfo.vertical ? rect.height : rect.width, gradientInfo.vertical, getColor(COLOR_BASE_BG), getDisplay()); 904 } else if (backgroundImage != null && !isBackgroundImageTiled()) { 905 gradientImage = new Image(getDisplay(), Math.max(rect.width, 1), 906 Math.max(rect.height, 1)); 907 gradientImage.setBackground(getBackground()); 908 GC gc = new GC(gradientImage); 909 gc.drawImage(backgroundImage, 0, 0); 910 gc.dispose(); 911 } 912 if (oldGradientImage != null) { 913 FormImages.getInstance().markFinished(oldGradientImage, getDisplay()); 914 } 915 setBackgroundImage(gradientImage); 916 } 917 isSeparatorVisible()918 public boolean isSeparatorVisible() { 919 return (flags & SEPARATOR) != 0; 920 } 921 setSeparatorVisible(boolean addSeparator)922 public void setSeparatorVisible(boolean addSeparator) { 923 if (addSeparator) 924 flags |= SEPARATOR; 925 else 926 flags &= ~SEPARATOR; 927 } 928 setToolBarAlignment(int alignment)929 public void setToolBarAlignment(int alignment) { 930 if (alignment == SWT.BOTTOM) 931 flags |= BOTTOM_TOOLBAR; 932 else 933 flags &= ~BOTTOM_TOOLBAR; 934 } 935 getToolBarAlignment()936 public int getToolBarAlignment() { 937 return (flags & BOTTOM_TOOLBAR) != 0 ? SWT.BOTTOM : SWT.TOP; 938 } 939 addMessageHyperlinkListener(IHyperlinkListener listener)940 public void addMessageHyperlinkListener(IHyperlinkListener listener) { 941 ensureMessageRegionExists(); 942 messageRegion.addMessageHyperlinkListener(listener); 943 } 944 removeMessageHyperlinkListener(IHyperlinkListener listener)945 public void removeMessageHyperlinkListener(IHyperlinkListener listener) { 946 if (messageRegion != null) 947 messageRegion.removeMessageHyperlinkListener(listener); 948 } 949 getMessage()950 public String getMessage() { 951 return messageRegion != null ? messageRegion.getMessage() : null; 952 } 953 getMessageType()954 public int getMessageType() { 955 return messageRegion != null ? messageRegion.getMessageType() : 0; 956 } 957 getChildrenMessages()958 public IMessage[] getChildrenMessages() { 959 return messageRegion != null ? messageRegion.getChildrenMessages() 960 : NULL_MESSAGE_ARRAY; 961 } 962 ensureMessageRegionExists()963 private void ensureMessageRegionExists() { 964 // ensure message region exists 965 if (messageRegion == null) 966 messageRegion = new MessageRegion(); 967 } 968 showMessage(String newMessage, int type, IMessage[] messages)969 public void showMessage(String newMessage, int type, IMessage[] messages) { 970 if (messageRegion == null) { 971 // check the trivial case 972 if (newMessage == null) 973 return; 974 } else if (messageRegion.isDisposed()) 975 return; 976 ensureMessageRegionExists(); 977 messageRegion.showMessage(newMessage, type, messages); 978 titleRegion.updateImage(messageRegion.getMessageImage(), false); 979 if (messageToolTipManager != null) 980 messageToolTipManager.update(); 981 layout(); 982 redraw(); 983 } 984 985 /** 986 * Tests if the form is in the 'busy' state. 987 * 988 * @return <code>true</code> if busy, <code>false</code> otherwise. 989 */ 990 isBusy()991 public boolean isBusy() { 992 return titleRegion.isBusy(); 993 } 994 995 /** 996 * Sets the form's busy state. Busy form will display 'busy' animation in 997 * the area of the title image. 998 * 999 * @param busy 1000 * the form's busy state 1001 */ 1002 setBusy(boolean busy)1003 public void setBusy(boolean busy) { 1004 if (titleRegion.setBusy(busy)) 1005 layout(); 1006 } 1007 getHeadClient()1008 public Control getHeadClient() { 1009 return headClient; 1010 } 1011 setHeadClient(Control headClient)1012 public void setHeadClient(Control headClient) { 1013 if (headClient != null) 1014 Assert.isTrue(headClient.getParent() == this); 1015 this.headClient = headClient; 1016 layout(); 1017 } 1018 putColor(String key, Color color)1019 public void putColor(String key, Color color) { 1020 if (color == null) 1021 colors.remove(key); 1022 else 1023 colors.put(key, color); 1024 } 1025 getColor(String key)1026 public Color getColor(String key) { 1027 return colors.get(key); 1028 } 1029 hasColor(String key)1030 public boolean hasColor(String key) { 1031 return colors.containsKey(key); 1032 } 1033 addDragSupport(int operations, Transfer[] transferTypes, DragSourceListener listener)1034 public void addDragSupport(int operations, Transfer[] transferTypes, 1035 DragSourceListener listener) { 1036 titleRegion.addDragSupport(operations, transferTypes, listener); 1037 } 1038 addDropSupport(int operations, Transfer[] transferTypes, DropTargetListener listener)1039 public void addDropSupport(int operations, Transfer[] transferTypes, 1040 DropTargetListener listener) { 1041 titleRegion.addDropSupport(operations, transferTypes, listener); 1042 } 1043 getMessageToolTipManager()1044 public IMessageToolTipManager getMessageToolTipManager() { 1045 return messageToolTipManager; 1046 } 1047 setMessageToolTipManager( IMessageToolTipManager messageToolTipManager)1048 public void setMessageToolTipManager( 1049 IMessageToolTipManager messageToolTipManager) { 1050 this.messageToolTipManager = messageToolTipManager; 1051 } 1052 } 1053