/******************************************************************************* * Copyright (c) 2004, 2008 Tasktop Technologies and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.tasks.ui.editors; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ToolBarManager; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor; import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPart; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.forms.widgets.ExpandableComposite; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.internal.EditorAreaHelper; import org.eclipse.ui.internal.WorkbenchPage; /** * @author Steffen Pingel */ public class TaskEditorRichTextPart extends AbstractTaskEditorPart { private RichTextAttributeEditor editor; private TaskAttribute attribute; private Composite composite; private int sectionStyle; private ToggleToMaximizePartAction toggleToMaximizePartAction; private Action togglePreviewAction; private Action toggleBrowserAction; public TaskEditorRichTextPart() { setSectionStyle(ExpandableComposite.TITLE_BAR | ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED); } public void appendText(String text) { if (editor == null) { return; } StringBuilder strBuilder = new StringBuilder(); String oldText = editor.getViewer().getDocument().get(); if (strBuilder.length() != 0) { strBuilder.append("\n"); //$NON-NLS-1$ } strBuilder.append(oldText); strBuilder.append(text); editor.getViewer().getDocument().set(strBuilder.toString()); TaskAttribute attribute = getTaskData().getRoot().getMappedAttribute(TaskAttribute.COMMENT_NEW); if (attribute != null) { attribute.setValue(strBuilder.toString()); getTaskEditorPage().getModel().attributeChanged(attribute); } editor.getViewer().getTextWidget().setCaretOffset(strBuilder.length()); } public int getSectionStyle() { return sectionStyle; } public void setSectionStyle(int sectionStyle) { this.sectionStyle = sectionStyle; } @Override public void createControl(Composite parent, FormToolkit toolkit) { if (attribute == null) { return; } AbstractAttributeEditor attributEditor = createAttributeEditor(attribute); if (!(attributEditor instanceof RichTextAttributeEditor)) { String clazz; if (attributEditor != null) { clazz = attributEditor.getClass().getName(); } else { clazz = ""; //$NON-NLS-1$ } StatusHandler.log(new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, "Expected an instance of RichTextAttributeEditor, got \"" + clazz + "\"")); //$NON-NLS-1$ //$NON-NLS-2$ return; } Section section = createSection(parent, toolkit, sectionStyle); composite = toolkit.createComposite(section); GridLayout layout = new GridLayout(); layout.numColumns = 1; composite.setLayout(layout); editor = (RichTextAttributeEditor) attributEditor; editor.createControl(composite, toolkit); if (editor.isReadOnly()) { composite.setLayout(new FillWidthLayout(EditorUtil.getLayoutAdvisor(getTaskEditorPage()), 0, 0, 0, 3)); } else { final GridData gd = new GridData(); // wrap text at this margin, see comment below int width = getEditorWidth(); // the goal is to make the text viewer as big as the text so it does not require scrolling when first drawn // on screen Point size = editor.getViewer().getTextWidget().computeSize(width, SWT.DEFAULT, true); gd.widthHint = EditorUtil.MAXIMUM_WIDTH; gd.minimumWidth = EditorUtil.MAXIMUM_WIDTH; gd.horizontalAlignment = SWT.FILL; gd.grabExcessHorizontalSpace = true; // limit height to be avoid dynamic resizing of the text widget: // MAXIMUM_HEIGHT < height < MAXIMUM_HEIGHT * 3 //gd.minimumHeight = AbstractAttributeEditor.MAXIMUM_HEIGHT; gd.heightHint = Math.min(Math.max(EditorUtil.MAXIMUM_HEIGHT, size.y), EditorUtil.MAXIMUM_HEIGHT * 3); if (getExpandVertically()) { gd.verticalAlignment = SWT.FILL; gd.grabExcessVerticalSpace = true; } editor.getControl().setLayoutData(gd); editor.getControl().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); // shrink the text control if the editor width is reduced, otherwise the text field will always keep it's original // width and will cause the editor to have a horizonal scroll bar // composite.addControlListener(new ControlAdapter() { // @Override // public void controlResized(ControlEvent e) { // int width = sectionComposite.getSize().x; // Point size = descriptionTextViewer.getTextWidget().computeSize(width, SWT.DEFAULT, true); // // limit width to parent widget // gd.widthHint = width; // // limit height to avoid dynamic resizing of the text widget // gd.heightHint = Math.min(Math.max(DESCRIPTION_HEIGHT, size.y), DESCRIPTION_HEIGHT * 4); // sectionComposite.layout(); // } // }); } getEditor().getControl().setData(EditorUtil.KEY_TOGGLE_TO_MAXIMIZE_ACTION, getMaximizePartAction()); if (getEditor().getControl() instanceof Composite) { for (Control control : ((Composite) getEditor().getControl()).getChildren()) { control.setData(EditorUtil.KEY_TOGGLE_TO_MAXIMIZE_ACTION, getMaximizePartAction()); } } getTaskEditorPage().getAttributeEditorToolkit().adapt(editor); toolkit.paintBordersFor(composite); section.setClient(composite); setSection(toolkit, section); } private int getEditorWidth() { int widthHint = 0; if (getManagedForm() != null && getManagedForm().getForm() != null) { widthHint = getManagedForm().getForm().getClientArea().width - 90; } if (widthHint <= 0 && getTaskEditorPage().getEditor().getEditorSite() != null && getTaskEditorPage().getEditor().getEditorSite().getPage() != null) { EditorAreaHelper editorManager = ((WorkbenchPage) getTaskEditorPage().getEditor().getEditorSite().getPage()).getEditorPresentation(); if (editorManager != null && editorManager.getLayoutPart() != null) { widthHint = editorManager.getLayoutPart().getControl().getBounds().width - 90; } } if (widthHint <= 0) { widthHint = EditorUtil.MAXIMUM_WIDTH; } return widthHint; } public TaskAttribute getAttribute() { return attribute; } protected Composite getComposite() { return composite; } protected RichTextAttributeEditor getEditor() { return editor; } public void setAttribute(TaskAttribute attribute) { this.attribute = attribute; } @Override public void setFocus() { if (editor != null) { editor.getControl().setFocus(); } } // TODO 3.1 move to AbstractTaskEditorPart? protected Action getMaximizePartAction() { if (toggleToMaximizePartAction == null) { toggleToMaximizePartAction = new ToggleToMaximizePartAction(); } return toggleToMaximizePartAction; } private class ToggleToMaximizePartAction extends Action { private static final String COMMAND_ID = "org.eclipse.mylyn.tasks.ui.command.maximizePart"; //$NON-NLS-1$ private/*static*/final String MAXIMIZE = Messages.TaskEditorRichTextPart_Maximize; private static final int SECTION_HEADER_HEIGHT = 50; private int originalHeight = -1; public ToggleToMaximizePartAction() { super("", SWT.TOGGLE); //$NON-NLS-1$ setImageDescriptor(CommonImages.PART_MAXIMIZE); setToolTipText(MAXIMIZE); setActionDefinitionId(COMMAND_ID); setChecked(false); } @Override public void run() { if (!(getEditor().getControl().getLayoutData() instanceof GridData)) { return; } GridData gd = (GridData) getEditor().getControl().getLayoutData(); if (originalHeight == -1) { originalHeight = gd.heightHint; } try { getTaskEditorPage().setReflow(false); int heightHint; if (isChecked()) { heightHint = getManagedForm().getForm().getClientArea().height - SECTION_HEADER_HEIGHT; } else { heightHint = originalHeight; } // ignore when not necessary if (gd.heightHint == heightHint) { return; } gd.heightHint = heightHint; gd.minimumHeight = heightHint; } finally { getTaskEditorPage().setReflow(true); } getTaskEditorPage().reflow(); EditorUtil.ensureVisible(getEditor().getControl()); } } @Override protected void fillToolBar(ToolBarManager manager) { if (getEditor().hasPreview()) { togglePreviewAction = new Action("", SWT.TOGGLE) { //$NON-NLS-1$ @Override public void run() { if (isChecked()) { editor.showPreview(); } else { editor.showEditor(); } if (toggleBrowserAction != null) { toggleBrowserAction.setChecked(false); } } }; togglePreviewAction.setImageDescriptor(CommonImages.PREVIEW_WEB); togglePreviewAction.setToolTipText(Messages.TaskEditorRichTextPart_Preview); togglePreviewAction.setChecked(false); manager.add(togglePreviewAction); } if (togglePreviewAction == null && getEditor().hasBrowser()) { toggleBrowserAction = new Action("", SWT.TOGGLE) { //$NON-NLS-1$ @Override public void run() { if (isChecked()) { editor.showBrowser(); } else { editor.showEditor(); } if (togglePreviewAction != null) { togglePreviewAction.setChecked(false); } } }; toggleBrowserAction.setImageDescriptor(CommonImages.PREVIEW_WEB); toggleBrowserAction.setToolTipText(Messages.TaskEditorRichTextPart_Browser_Preview); toggleBrowserAction.setChecked(false); manager.add(toggleBrowserAction); } manager.add(getMaximizePartAction()); super.fillToolBar(manager); } }