package org.nightlabs.jfire.prop.html.ui; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; 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.swt.widgets.Display; import org.eclipse.ui.IPropertyListener; import org.nightlabs.base.ui.language.LanguageChangeEvent; import org.nightlabs.base.ui.language.LanguageChangeListener; import org.nightlabs.base.ui.language.LanguageChooserCombo; import org.nightlabs.eclipse.ui.fckeditor.FCKEditorComposite; import org.nightlabs.eclipse.ui.fckeditor.FCKEditorInput; import org.nightlabs.eclipse.ui.fckeditor.IFCKEditor; import org.nightlabs.eclipse.ui.fckeditor.IFCKEditorInput; import org.nightlabs.htmlcontent.IFCKEditorContent; import org.nightlabs.jfire.base.ui.edit.IEntryEditor; import org.nightlabs.jfire.base.ui.prop.edit.AbstractDataFieldEditor; import org.nightlabs.jfire.base.ui.prop.edit.DataFieldEditorLayoutData; import org.nightlabs.jfire.prop.IStruct; import org.nightlabs.jfire.prop.html.HTMLDataField; import org.nightlabs.language.LanguageCf; /** * @author Marc Klinger - marc[at]nightlabs[dot]de * @author Tobias Langner <!-- tobias[dot]langner[at]nightlabs[dot]de --> */ public class HTMLDataFieldEditor extends AbstractDataFieldEditor<HTMLDataField> implements IEntryEditor { private Composite control; private LanguageChooserCombo languageChooser; private Map<String, FCKEditorComposite> editorComposites; private Composite editorWrapper; private StackLayout editorWrapperLayout; public HTMLDataFieldEditor(IStruct struct, HTMLDataField data) { super(struct, data); } @Override public Control createControl(Composite parent) { control = new Composite(parent, SWT.NONE); GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.horizontalSpan = 2; control.setLayoutData(gd); GridLayout gl = new GridLayout(); gl.marginWidth = 0; gl.marginHeight = 0; control.setLayout(gl); languageChooser = new LanguageChooserCombo(control); languageChooser.addLanguageChangeListener(new LanguageChangeListener() { @Override public void languageChanged(LanguageChangeEvent event) { switchLanguage(event.getNewLanguage().getLanguageID()); } }); editorWrapper = new Composite(control, SWT.NONE); gd = new GridData(SWT.FILL, SWT.FILL, true, true); editorWrapper.setLayoutData(gd); editorWrapperLayout = new StackLayout(); editorWrapper.setLayout(editorWrapperLayout); List<LanguageCf> languages = languageChooser.getLanguages(); editorComposites = new HashMap<String, FCKEditorComposite>(languages.size()); for(LanguageCf language : languages) { IFCKEditorContent contentWrapper = getDataField().getContent(language.getLanguageID()); System.out.println("CONTENT: "+contentWrapper.getHtml()); IFCKEditorInput editorInput = new FCKEditorInput(contentWrapper, getDataField().getStructFieldID()); FCKEditorComposite editorComposite = new FCKEditorComposite(editorWrapper, SWT.BORDER, editorInput); editorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); editorComposite.getEditor().addPropertyListener(new IPropertyListener() { @Override public void propertyChanged(Object src, int propertyId) { if(propertyId == IFCKEditor.PROP_DIRTY) notifyChangeListeners(); } }); editorComposites.put(language.getLanguageID(), editorComposite); } switchLanguage(languageChooser.getLanguage().getLanguageID()); doRefresh(); return control; } private void switchLanguage(String languageId) { FCKEditorComposite editorComposite = editorComposites.get(languageId); if(editorComposite == null) throw new IllegalStateException("Editor for language "+languageId+" is unknown"); editorWrapperLayout.topControl = editorComposite; editorWrapper.layout(); } @Override public DataFieldEditorLayoutData getLayoutData() { DataFieldEditorLayoutData ld = new DataFieldEditorLayoutData(DataFieldEditorLayoutData.FILL_BOTH); ld.minimumHeight = 450; return ld; } @Override public void doRefresh() { // TODO: handle input change // if(!getDataField().isEmpty()) // contentLabel.setText(getDataField().getHtml()); // else // contentLabel.setText("No content."); // // int count = getDataField().getFiles() == null ? 0 : getDataField().getFiles().size(); // fileLabel.setText(String.format("%d files", count)); // // contentLabel.getParent().layout(true, true); } @Override public Control getControl() { return control; } private class MyWaitListener implements IPropertyListener { boolean committed = false; @Override public void propertyChanged(Object source, int propertyId) { if(propertyId == IFCKEditor.PROP_DIRTY && source instanceof IFCKEditor && !((IFCKEditor)source).isDirty()) { committed = true; } } } @Override public void updatePropertySet() { long timeoutMillis = 5000; for(Map.Entry<String, FCKEditorComposite> entry : editorComposites.entrySet()) { String languageId = entry.getKey(); FCKEditorComposite editorComposite = entry.getValue(); IFCKEditor editor = editorComposite.getEditor(); MyWaitListener propertyListener = new MyWaitListener(); if(editor.isDirty()) { editor.addPropertyListener(propertyListener); try { editor.commit(); // wait on the ui thread until the server commit round-trip // is back and the editor is not dirty anymore: long startTimeMillis = System.currentTimeMillis(); Display display = control.getDisplay(); while(!display.isDisposed() && !propertyListener.committed) { if(System.currentTimeMillis() - startTimeMillis > timeoutMillis) throw new RuntimeException("Editor commit timeout"); if(!display.readAndDispatch()) display.sleep(); } } finally { editor.removePropertyListener(propertyListener); } // waiting done. Commit into the property set: IFCKEditorContent editorContent = editor.getEditorInput().getEditorContent(); HTMLDataField dataField = getDataField(); dataField.setText(languageId, editorContent.getHtml()); dataField.setFiles(editorContent.getFiles()); // commit done. } } } @Override protected IEntryEditor getEntryViewer() { return this; } @Override public void setEnabledState(boolean enabled, String tooltip) { for (Control child : editorWrapper.getChildren()) { child.setEnabled(enabled); } if (!enabled) { editorWrapper.setToolTipText(tooltip); } else { editorWrapper.setToolTipText(null); } } @Override public void setTitle(String title) { // TODO Dunno where to set a title here. } }