package org.xmind.ui.internal.comments; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.eclipse.jface.resource.FontDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.widgets.Hyperlink; import org.xmind.core.Core; import org.xmind.core.IComment; import org.xmind.core.ICommentManager; import org.xmind.core.ISheet; import org.xmind.core.ITopic; import org.xmind.core.event.CoreEvent; import org.xmind.core.event.CoreEventRegister; import org.xmind.core.event.ICoreEventListener; import org.xmind.core.event.ICoreEventRegister; import org.xmind.core.util.TopicIterator; import org.xmind.gef.ui.editor.IGraphicalEditor; import org.xmind.ui.internal.MindMapMessages; import org.xmind.ui.internal.e4models.CommentsPart; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.resources.ColorUtils; import org.xmind.ui.resources.FontUtils; import org.xmind.ui.util.MindMapUtils; import org.xmind.ui.util.TextFormatter; public class SheetCommentsViewer implements ICoreEventListener, ISelectionChangedListener { private ResourceManager resources; private ISheet input; private ICommentsActionBarContributor contributor; private ISelectionProvider selectionProvider; private ICommentTextViewerContainer container; private IGraphicalEditor targetEditor; private TopicCommentsViewer topicViewer; private Label titleLabel; private ICoreEventRegister eventRegister; private List<CommentTextViewer> controls = new ArrayList<CommentTextViewer>(); private List<CommentTextViewer> implementations = new ArrayList<CommentTextViewer>(); private Map<ITopic, TopicCommentsViewer> topicViewers = new HashMap<ITopic, TopicCommentsViewer>(); private Composite sheetCommentsComposite; private Control newCommentControl; private Button insertButton; private Hyperlink insertHyperlink; private ITopic select; private String creatingTargetId; private Composite content; private Composite parent; public SheetCommentsViewer(ISheet input, ICommentsActionBarContributor contributor, ISelectionProvider selectionProvider, ICommentTextViewerContainer container, IGraphicalEditor targetEditor) { this.input = input; this.contributor = contributor; this.selectionProvider = selectionProvider; this.container = container; this.targetEditor = targetEditor; } public void create(Composite parent) { this.parent = parent; init(); createContent(parent, input); restoreEditing(); } private void init() { if (controls != null) { controls.clear(); } else { controls = new ArrayList<CommentTextViewer>(); } if (implementations != null) { implementations.clear(); } else { implementations = new ArrayList<CommentTextViewer>(); } if (topicViewers != null) { topicViewers.clear(); } else { topicViewers = new HashMap<ITopic, TopicCommentsViewer>(); } } private Composite createContent(Composite parent, ISheet sheet) { Composite composite = new Composite(parent, SWT.NONE); this.content = composite; resources = new LocalResourceManager(JFaceResources.getResources(), composite); composite.setBackground(composite.getParent().getBackground()); GridData layoutData = new GridData(GridData.FILL_BOTH); composite.setLayoutData(layoutData); GridLayout layout = new GridLayout(1, false); layout.marginWidth = 0; layout.marginHeight = 0; composite.setLayout(layout); if (sheet == null || !existComment(sheet)) { //If have no comment, create null comment content. container.getScrolledComposite().setExpandVertical(true); createNullContentArea(composite); } else { createAllComments(composite, sheet); } composite.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { handleControlDisposed(e); } }); return composite; } private void restoreEditing() { //restore last editing. final CommentsPart part = (CommentsPart) container; final String objectId = part.getInsertTarget(); if (objectId != null) { Display.getCurrent().asyncExec(new Runnable() { @Override public void run() { insertComment(objectId); container.setModified(false); part.setInsertTarget(null); } }); } } private boolean existComment(ISheet sheet) { if (sheet == null) { return false; } if (creatingTargetId != null) { return true; } ICommentManager commentManager = sheet.getOwnedWorkbook() .getCommentManager(); if (commentManager.isEmpty()) { return false; } if (commentManager.hasComments(sheet.getId())) { return true; } TopicIterator ite = new TopicIterator(sheet.getRootTopic()); while (ite.hasNext()) { ITopic topic = ite.next(); if (commentManager.hasComments(topic.getId())) { return true; } } return false; } private Control createAllComments(Composite parent, ISheet sheet) { container.getScrolledComposite().setExpandVertical(false); Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getBackground()); composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); GridLayout gridLayout = new GridLayout(1, false); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; gridLayout.marginTop = 9; gridLayout.marginBottom = 29; gridLayout.verticalSpacing = 18; gridLayout.horizontalSpacing = 0; composite.setLayout(gridLayout); boolean showTopicsComments = createTopicsComments(composite, sheet.getRootTopic()); if (showTopicsComments) { createSeparatorLine(composite); } createSheetComments(composite, sheet); boolean showSheetComments = sheet.getOwnedWorkbook().getCommentManager() .getComments(sheet.getId()).size() != 0; if (showSheetComments) { createSeparatorLine(composite); } createInsertCommentHyperlink(composite); return composite; } /** * @param parent * @param sheet * @return true if create not less than one comment, false otherwise. */ private boolean createTopicsComments(Composite parent, ITopic root) { boolean hasContent = false; Iterator<ITopic> topicIt = new TopicIterator(root); while (topicIt.hasNext()) { ITopic topic = topicIt.next(); if (topic.getOwnedWorkbook().getCommentManager().hasComments( topic.getId()) || topic.getId().equals(creatingTargetId)) { if (hasContent) { createSeparatorLine(parent); } createTopicLabelAndComments(parent, topic); hasContent = true; } } return hasContent; } private void createSeparatorLine(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getBackground()); composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); GridLayout layout = new GridLayout(1, false); layout.marginHeight = 0; layout.marginWidth = 10; composite.setLayout(layout); Label sep = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL); sep.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); sep.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_BLACK)); } private void createTopicLabelAndComments(Composite parent, ITopic topic) { topicViewer = new TopicCommentsViewer(topic, contributor, selectionProvider, container, true, targetEditor); topicViewer.create(parent); if (topicViewer.getControls() != null) { controls.addAll(topicViewer.getControls()); } if (topicViewer.getImplementations() != null) { implementations.addAll(topicViewer.getImplementations()); } topicViewers.put(topic, topicViewer); } private void createSheetComments(Composite parent, ISheet sheet) { Set<IComment> comments = new TreeSet<IComment>(sheet.getOwnedWorkbook() .getCommentManager().getComments(sheet.getId())); if (comments.isEmpty()) { return; } Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getBackground()); composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); GridLayout layout = new GridLayout(1, false); layout.marginHeight = 0; layout.marginWidth = 0; layout.verticalSpacing = 5; composite.setLayout(layout); this.sheetCommentsComposite = composite; createSheetLabel(composite, sheet); for (IComment comment : comments) { createCommentControl(composite, comment); } } private void createSheetLabel(Composite parent, final ISheet sheet) { Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getBackground()); composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); GridLayout layout = new GridLayout(1, false); layout.marginWidth = 10; layout.marginHeight = 0; layout.horizontalSpacing = 0; composite.setLayout(layout); titleLabel = new Label(composite, SWT.LEFT | SWT.HORIZONTAL); titleLabel.setBackground(parent.getBackground()); titleLabel.setForeground( (Color) resources.get(ColorUtils.toDescriptor("#353535"))); //$NON-NLS-1$ GridData data = new GridData(SWT.CENTER, SWT.CENTER, true, false); data.horizontalIndent = 2; titleLabel.setLayoutData(data); titleLabel.setFont((Font) resources .get(FontDescriptor.createFrom(FontUtils.relativeHeight( titleLabel.getFont().getFontData(), 1)))); titleLabel.setText(MindMapMessages.Comment_SHEET_text + TextFormatter.removeNewLineCharacter(sheet.getTitleText())); hookSheetTitle(); titleLabel.addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent e) { CommentsUtils.reveal(targetEditor, sheet); } }); } private void createCommentControl(Composite parent, IComment comment) { CommentTextViewer implementation = new CommentTextViewer(comment, input.getId(), input.getOwnedWorkbook(), contributor, selectionProvider, container, targetEditor); implementation.createControl(parent); registerControl(implementation); registerImplementation(implementation); } private void createNullContentArea(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(composite.getParent().getBackground()); GridData layoutData = new GridData(GridData.FILL_BOTH); composite.setLayoutData(layoutData); GridLayout layout = new GridLayout(1, false); layout.marginWidth = 0; layout.marginHeight = 0; layout.verticalSpacing = 0; composite.setLayout(layout); createNullContent(composite); } private void createNullContent(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(composite.getParent().getBackground()); composite.setLayoutData( new GridData(SWT.CENTER, SWT.CENTER, true, true)); GridLayout layout = new GridLayout(1, false); layout.marginWidth = 0; layout.marginHeight = 0; layout.verticalSpacing = 25; composite.setLayout(layout); Label label = new Label(composite, SWT.NONE); label.setBackground(label.getParent().getBackground()); label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); label.setImage((Image) resources .get(MindMapUI.getImages().get("comment-empty-bg.png", true))); //$NON-NLS-1$ Composite composite2 = new Composite(composite, SWT.NONE); composite2.setBackground(composite2.getParent().getBackground()); composite2.setLayoutData( new GridData(SWT.CENTER, SWT.CENTER, false, false)); GridLayout layout2 = new GridLayout(1, false); layout2.marginWidth = 0; layout2.marginHeight = 0; layout2.verticalSpacing = 0; composite2.setLayout(layout2); Label label2 = new Label(composite2, SWT.NONE); label2.setBackground(label2.getParent().getBackground()); label2.setForeground( (Color) resources.get(ColorUtils.toDescriptor("#aaaaaa"))); //$NON-NLS-1$ label2.setLayoutData( new GridData(SWT.CENTER, SWT.CENTER, false, false)); label2.setText(""); //$NON-NLS-1$ label2.setFont((Font) resources.get(FontDescriptor.createFrom( FontUtils.relativeHeight(label2.getFont().getFontData(), 2)))); Label label3 = new Label(composite2, SWT.NONE); label3.setBackground(label3.getParent().getBackground()); label3.setForeground( (Color) resources.get(ColorUtils.toDescriptor("#aaaaaa"))); //$NON-NLS-1$ label3.setLayoutData( new GridData(SWT.CENTER, SWT.CENTER, false, false)); label3.setText(MindMapMessages.Comment_FirstAdd_text); label3.setFont((Font) resources.get(FontDescriptor.createFrom( FontUtils.relativeHeight(label3.getFont().getFontData(), 2)))); createInsertButtonSection(composite); } private void createInsertButtonSection(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getBackground()); GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); composite.setLayoutData(gridData); GridLayout layout = new GridLayout(1, false); layout.marginWidth = 0; layout.marginHeight = 0; layout.marginTop = 30; layout.verticalSpacing = 0; layout.horizontalSpacing = 0; composite.setLayout(layout); insertButton = new Button(composite, SWT.PUSH); insertButton.setBackground(composite.getBackground()); GridData layoutData = new GridData(SWT.CENTER, SWT.CENTER, true, false); layoutData.widthHint = 90; insertButton.setLayoutData(layoutData); insertButton.setText(MindMapMessages.SheetCommentViewer_Insert_button); insertButton.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { insertComment(); } @Override public void widgetDefaultSelected(SelectionEvent e) { } }); //add selection listener. if (this.targetEditor != null) { this.targetEditor.getSite().getSelectionProvider() .addSelectionChangedListener(this); setSelection(targetEditor.getSite().getSelectionProvider() .getSelection()); } else { setSelection(null); } } private void createInsertCommentHyperlink(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getBackground()); GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); composite.setLayoutData(gridData); GridLayout layout = new GridLayout(1, false); layout.marginWidth = 0; layout.marginHeight = 0; layout.marginLeft = 15; layout.verticalSpacing = 0; layout.horizontalSpacing = 0; composite.setLayout(layout); insertHyperlink = new Hyperlink(composite, SWT.NONE); insertHyperlink.setBackground(composite.getBackground()); insertHyperlink.setForeground( (Color) resources.get(ColorUtils.toDescriptor("#0082F9"))); //$NON-NLS-1$ GridData layoutData = new GridData(SWT.LEFT, SWT.CENTER, false, false); insertHyperlink.setLayoutData(layoutData); insertHyperlink .setText(MindMapMessages.SheetCommentViewer_Insert_hyperlink); insertHyperlink.addListener(SWT.MouseDown, new Listener() { @Override public void handleEvent(Event event) { insertComment(); } }); //add selection listener. if (this.targetEditor != null) { this.targetEditor.getSite().getSelectionProvider() .addSelectionChangedListener(this); setSelection(targetEditor.getSite().getSelectionProvider() .getSelection()); } else { setSelection(null); } } private void insertComment() { if (select == null) { return; } String targetId = select.getId(); //store last insert state. if (container.isModified()) { container.setModified(false); ((CommentsPart) container).setInsertTarget(targetId); return; } insertComment(targetId); } private void insertComment(String targetId) { creatingTargetId = targetId; Composite contentComposite = container.getContentComposite(); contentComposite.setRedraw(false); content.dispose(); create(parent); createNewComment(targetId); contentComposite.pack(); contentComposite.setRedraw(true); creatingTargetId = null; } private void update() { Composite contentComposite = container.getContentComposite(); if (contentComposite == null || contentComposite.isDisposed()) { return; } contentComposite.setRedraw(false); content.dispose(); create(parent); contentComposite.pack(true); contentComposite.layout(true, true); contentComposite.setRedraw(true); } private void registerControl(CommentTextViewer control) { controls.add(control); } private void registerImplementation(CommentTextViewer implementation) { implementations.add(implementation); } private void hookSheetTitle() { if (eventRegister == null) { eventRegister = new CoreEventRegister(input, this); } eventRegister.register(Core.TitleText); } private void unhookSheetTitle() { if (eventRegister != null) { eventRegister.unregisterAll(); eventRegister = null; } } public void handleCoreEvent(final CoreEvent event) { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { public void run() { if (Core.TitleText.equals(event.getType())) { if (titleLabel != null && !titleLabel.isDisposed()) { titleLabel.setText(MindMapMessages.Comment_SHEET_text + TextFormatter.removeNewLineCharacter( input.getTitleText())); titleLabel.getParent().layout(true, true); } } } }); } private void handleControlDisposed(DisposeEvent e) { unhookSheetTitle(); if (controls != null) { controls.clear(); controls = null; } if (implementations != null) { implementations.clear(); implementations = null; } if (topicViewers != null) { topicViewers.clear(); topicViewers = null; } } public void setTargetEditor(IGraphicalEditor targetEditor) { if (targetEditor == this.targetEditor) { return; } if (this.targetEditor != null) { this.targetEditor.getSite().getSelectionProvider() .removeSelectionChangedListener(this); } this.targetEditor = targetEditor; if (this.targetEditor != null) { this.targetEditor.getSite().getSelectionProvider() .addSelectionChangedListener(this); setSelection(targetEditor.getSite().getSelectionProvider() .getSelection()); } else { setSelection(null); } if (topicViewer != null) { topicViewer.setTargetEditor(targetEditor); } if (implementations != null) { for (CommentTextViewer implementation : implementations) { implementation.setTargetEditor(targetEditor); } } } public List<CommentTextViewer> getControls() { return controls; } public List<CommentTextViewer> getImplementations() { return controls; } public void createNewComment(String objectId) { if (newCommentControl != null && !newCommentControl.isDisposed()) { newCommentControl.dispose(); } Object object = input.getOwnedWorkbook().getElementById(objectId); if (object instanceof ITopic) { newCommentControl = topicViewers.get((ITopic) object) .createNewComment(); } if (object instanceof ISheet) { CommentTextViewer implementation = new CommentTextViewer(null, input.getId(), input.getOwnedWorkbook(), contributor, selectionProvider, container, targetEditor); newCommentControl = implementation .createControl(sheetCommentsComposite); newCommentControl .moveAbove((sheetCommentsComposite.getChildren())[0]); container.getContentComposite().pack(); implementation.getTextViewer().getTextWidget().forceFocus(); } } public void cancelCreateNewComment() { if (newCommentControl != null && !newCommentControl.isDisposed()) { newCommentControl.dispose(); newCommentControl = null; update(); } } public void save() { Control contentComposite = container.getContentComposite(); if (contentComposite != null && !contentComposite.isDisposed()) { contentComposite.forceFocus(); } } @Override public void selectionChanged(SelectionChangedEvent event) { setSelection(event.getSelection()); } private void setSelection(ISelection selection) { boolean isSingleTopic = MindMapUtils.isSingleTopic(selection); if (isSingleTopic) { select = (ITopic) MindMapUtils .getAllSuchElements(selection, MindMapUI.CATEGORY_TOPIC) .get(0); } else { select = null; } if (insertButton != null && !insertButton.isDisposed()) { insertButton.setEnabled(isSingleTopic); } if (insertHyperlink != null && !insertHyperlink.isDisposed()) { insertHyperlink.setEnabled(isSingleTopic); } container.setModified(false); } }