001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.gwt.client.ui.contextmenu;
029
030import org.opencms.gwt.client.CmsCoreProvider;
031import org.opencms.gwt.client.property.CmsActiveFieldData;
032import org.opencms.gwt.client.property.CmsPropertySubmitHandler;
033import org.opencms.gwt.client.property.CmsSimplePropertyEditorHandler;
034import org.opencms.gwt.client.property.CmsVfsModePropertyEditor;
035import org.opencms.gwt.client.property.I_CmsPropertySaver;
036import org.opencms.gwt.client.property.definition.CmsPropertyDefinitionButton;
037import org.opencms.gwt.client.rpc.CmsRpcAction;
038import org.opencms.gwt.client.ui.CmsPushButton;
039import org.opencms.gwt.client.ui.I_CmsButton.ButtonColor;
040import org.opencms.gwt.client.ui.I_CmsButton.ButtonStyle;
041import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
042import org.opencms.gwt.client.ui.input.form.CmsDialogFormHandler;
043import org.opencms.gwt.client.ui.input.form.CmsForm;
044import org.opencms.gwt.client.ui.input.form.CmsFormDialog;
045import org.opencms.gwt.client.ui.input.form.I_CmsFormHandler;
046import org.opencms.gwt.client.ui.input.form.I_CmsFormSubmitHandler;
047import org.opencms.gwt.client.util.CmsDebugLog;
048import org.opencms.gwt.shared.CmsContextMenuEntryBean;
049import org.opencms.gwt.shared.property.CmsPropertiesBean;
050import org.opencms.util.CmsUUID;
051
052import java.util.List;
053
054import com.google.common.collect.Lists;
055import com.google.gwt.core.client.Scheduler;
056import com.google.gwt.core.client.Scheduler.RepeatingCommand;
057import com.google.gwt.dom.client.Style.Float;
058import com.google.gwt.event.dom.client.ClickEvent;
059import com.google.gwt.event.dom.client.ClickHandler;
060import com.google.gwt.event.logical.shared.CloseEvent;
061import com.google.gwt.event.logical.shared.CloseHandler;
062import com.google.gwt.user.client.rpc.AsyncCallback;
063import com.google.gwt.user.client.ui.FlowPanel;
064import com.google.gwt.user.client.ui.PopupPanel;
065import com.google.gwt.user.client.ui.Widget;
066
067/**
068 * The class for the "edit properties" context menu entries.<p>
069 *
070 * @since 8.0.0
071 */
072public final class CmsEditProperties implements I_CmsHasContextMenuCommand {
073
074    /**
075     * Interface used to access the next/previous file for which to edit properties.
076     */
077    public static interface I_MultiFileNavigation {
078
079        /**
080         * Requests the next / previous file id.<p>
081         *
082         * @param offset should be 1 for the next file, or -1 for the previous file
083         * @param callback the callback to call with the id
084         */
085        void requestNextFile(int offset, AsyncCallback<CmsUUID> callback);
086    }
087
088    /**
089     * Helper class which encapsulates the differences between the contexts where the property edit dialog is opened.<p>
090     */
091    public static class PropertyEditingContext {
092
093        /** The cancel handler. */
094        protected Runnable m_cancelHandler;
095
096        /** The dialog instance. */
097        protected CmsFormDialog m_formDialog;
098
099        /** The form handler. */
100        protected I_CmsFormHandler m_formHandler;
101
102        /** Enable/disable property definition button. */
103        private boolean m_allowCreateProperties = true;
104
105        /** Flag to control whether the file name field should be focused after opening the property dialog. */
106        private boolean m_focusNameField;
107
108        /** The file navigation. */
109        private I_MultiFileNavigation m_multiFileNavigation;
110
111        /** The property saver. */
112        private I_CmsPropertySaver m_propertySaver;
113
114        /** The restart command (used to open the property dialog again after closing e.g. the property definition dialog). */
115        private Runnable m_restart;
116
117        /**
118         * Returns true if the property definition button should be enabled.<p>
119         *
120         * @return true if the user should be able to define new properties
121         */
122        public boolean allowCreateProperties() {
123
124            return m_allowCreateProperties;
125        }
126
127        /**
128         * Creates the property definition button.<p>
129         *
130         * @return the property definition button
131         */
132        public CmsPropertyDefinitionButton createPropertyDefinitionButton() {
133
134            return new CmsPropertyDefinitionButton() {
135
136                /**
137                 * @see org.opencms.gwt.client.property.definition.CmsPropertyDefinitionButton#onBeforeEditPropertyDefinition()
138                 */
139                @Override
140                public void onBeforeEditPropertyDefinition() {
141
142                    m_formDialog.hide();
143                }
144
145                /**
146                 * @see org.opencms.gwt.client.property.definition.CmsPropertyDefinitionButton#onClosePropertyDefinitionDialog()
147                 */
148                @SuppressWarnings("synthetic-access")
149                @Override
150                public void onClosePropertyDefinitionDialog() {
151
152                    if (m_restart != null) {
153                        m_restart.run();
154                    }
155                }
156            };
157
158        }
159
160        /**
161         * Gets the form dialog.<p>
162         *
163         * @return the form dialog
164         */
165        public CmsFormDialog getDialog() {
166
167            return m_formDialog;
168        }
169
170        /**
171         * Gets the property saver.<p>
172         *
173         * @return the property saver
174         */
175        public I_CmsPropertySaver getPropertySaver() {
176
177            return m_propertySaver;
178        }
179
180        /**
181         * Initializes the close handler of the dialog.<p>
182         */
183        public void initCloseHandler() {
184
185            if (m_cancelHandler != null) {
186                m_formDialog.addCloseHandler(new CloseHandler<PopupPanel>() {
187
188                    public void onClose(CloseEvent<PopupPanel> event) {
189
190                        if (!m_formHandler.isSubmitting()) {
191                            m_cancelHandler.run();
192                        }
193                    }
194                });
195            }
196        }
197
198        /**
199         * Return true if  the file name field should be focused after opening the dialog.<p>
200         *
201         * @return true if the file name field should be focused
202         */
203        public boolean isFocusNameField() {
204
205            return m_focusNameField;
206        }
207
208        /**
209         * Enables / disables the 'define property' functionality.<p>
210         *
211         * @param allowCreateProperties true if the user should be able to create new properties
212         */
213        public void setAllowCreateProperties(boolean allowCreateProperties) {
214
215            m_allowCreateProperties = allowCreateProperties;
216        }
217
218        /**
219         * Sets the cancel handler.<p>
220         *
221         * @param cancelHandler the cancel handler
222         */
223        public void setCancelHandler(Runnable cancelHandler) {
224
225            m_cancelHandler = cancelHandler;
226        }
227
228        /**
229         * Sets the form dialog.<p>
230         *
231         * @param formDialog the form dialog
232         */
233        public void setDialog(CmsFormDialog formDialog) {
234
235            m_formDialog = formDialog;
236        }
237
238        /**
239         * Enables / disables focusing on the name field.
240         *
241         * @param focusNameField true if the file name field should be focused after opening the dialog
242         *
243         * */
244        public void setFocusNameField(boolean focusNameField) {
245
246            m_focusNameField = focusNameField;
247        }
248
249        /**
250         * Sets the form handler.<p>
251         *
252         * @param formHandler the form handler
253         */
254        public void setFormHandler(I_CmsFormHandler formHandler) {
255
256            m_formHandler = formHandler;
257        }
258
259        /**
260         * Sets the file navigation object.<p>
261         *
262         * @param nav the file navigation object
263         */
264        public void setMultiFileNavigation(I_MultiFileNavigation nav) {
265
266            m_multiFileNavigation = nav;
267        }
268
269        /**
270         * Sets the property saver.<p>
271         *
272         * @param saver the property saver
273         */
274        public void setPropertySaver(I_CmsPropertySaver saver) {
275
276            m_propertySaver = saver;
277        }
278
279        /**
280         * Sets the restart command (used to open the property dialog again after a secondary dialog).
281         *
282         * @param command the restart command
283         */
284        public void setRestart(Runnable command) {
285
286            m_restart = command;
287        }
288
289        /**
290         * Gets the file navigation object.<p>
291         *
292         * @return the file navigation object
293         */
294        private I_MultiFileNavigation getMultiFileNavigation() {
295
296            return m_multiFileNavigation;
297
298        }
299
300    }
301
302    /**
303     * Helper class for editing properties in the workplace.<p>
304     */
305    public static class WorkplacePropertyEditorContext implements I_CmsFormHandler {
306
307        /** The cancel handler. */
308        private Runnable m_cancelHandler;
309
310        /** The context menu handler. */
311        private I_CmsContextMenuHandler m_contextMenuHandler;
312
313        /** The dialog. */
314        private PropertiesFormDialog m_dialog;
315
316        /** The edit context. */
317        private PropertyEditingContext m_editContext;
318
319        /** True if name should be edited. */
320        private boolean m_editName;
321
322        /** The property editor. */
323        private CmsVfsModePropertyEditor m_editor;
324
325        /** True if ADE template selection should be enabled. */
326        private boolean m_enableAdeTemplateSelect;
327
328        /** The editor handler. */
329        private PropertyEditorHandler m_handler;
330
331        /** True if last button was prev/next. */
332        private boolean m_isPrevNext;
333
334        /** The active field data. */
335        private CmsActiveFieldData m_prevFieldData;
336
337        /** Structure id of the current resource. */
338        private CmsUUID m_structureId;
339
340        /** The submit handler.*/
341        private I_CmsFormSubmitHandler m_submitHandler;
342
343        /** True if form is currently being submitted. */
344        private boolean m_submitting;
345
346        /**
347         * Creates a new instance.<p>
348         *
349         * @param structureId the structure id of the resource
350         * @param contextMenuHandler the context menu handler
351         * @param editName true if name should be editable
352         * @param cancelHandler the cancel handler
353         * @param enableAdeTemplateSelect true if ADE template selection should be enabled
354         * @param editContext the edit context
355         * @param prevFieldData the previous field data
356         */
357        public WorkplacePropertyEditorContext(
358            CmsUUID structureId,
359            I_CmsContextMenuHandler contextMenuHandler,
360            boolean editName,
361            Runnable cancelHandler,
362            boolean enableAdeTemplateSelect,
363            PropertyEditingContext editContext,
364            CmsActiveFieldData prevFieldData) {
365
366            m_structureId = structureId;
367            m_contextMenuHandler = contextMenuHandler;
368            m_editName = editName;
369            m_cancelHandler = cancelHandler;
370            m_enableAdeTemplateSelect = enableAdeTemplateSelect;
371            m_editContext = editContext;
372            m_prevFieldData = prevFieldData;
373
374            m_dialog = new PropertiesFormDialog("XXX", null);
375
376            m_editContext.setDialog(m_dialog);
377            m_dialog.catchNotifications();
378            @SuppressWarnings("synthetic-access")
379            final I_MultiFileNavigation fileNavigation = m_editContext.getMultiFileNavigation();
380            List<CmsPushButton> additionalLeftButtons = Lists.newArrayList();
381            if (fileNavigation != null) {
382                CmsPushButton prevButton = new CmsPushButton();
383                prevButton.setText("<<");
384                String prevText = org.opencms.gwt.client.Messages.get().key(
385                    org.opencms.gwt.client.Messages.GUI_BUTTON_PREV_RESOURCE_0);
386                prevButton.setTitle(prevText);
387                String nextText = org.opencms.gwt.client.Messages.get().key(
388                    org.opencms.gwt.client.Messages.GUI_BUTTON_NEXT_RESOURCE_0);
389                CmsPushButton nextButton = new CmsPushButton();
390                nextButton.setText(">>");
391                nextButton.setTitle(nextText);
392                for (CmsPushButton button : new CmsPushButton[] {prevButton, nextButton}) {
393                    button.setButtonStyle(ButtonStyle.TEXT, ButtonColor.BLUE);
394                    // button.getElement().getStyle().setFloat(Float.LEFT);
395                }
396
397                final AsyncCallback<CmsUUID> loadHandler = new AsyncCallback<CmsUUID>() {
398
399                    public void onFailure(Throwable caught) {
400
401                        CmsDebugLog.consoleLog("" + caught);
402                    }
403
404                    @SuppressWarnings("synthetic-access")
405                    public void onSuccess(CmsUUID nextId) {
406
407                        CmsActiveFieldData fieldData = getActiveFieldData();
408                        m_prevFieldData = fieldData;
409                        m_structureId = nextId;
410                        editProperties();
411                    }
412                };
413                prevButton.addClickHandler(new ClickHandler() {
414
415                    @SuppressWarnings("synthetic-access")
416                    public void onClick(ClickEvent event) {
417
418                        m_isPrevNext = true;
419                        m_dialog.getForm().validateAndSubmit();
420                        m_handler.setNextAction(new Runnable() {
421
422                            public void run() {
423
424                                fileNavigation.requestNextFile(-1, loadHandler);
425                            }
426                        });
427                    }
428                });
429                nextButton.addClickHandler(new ClickHandler() {
430
431                    @SuppressWarnings("synthetic-access")
432                    public void onClick(ClickEvent event) {
433
434                        m_isPrevNext = true;
435                        m_dialog.getForm().validateAndSubmit();
436                        m_handler.setNextAction(new Runnable() {
437
438                            public void run() {
439
440                                fileNavigation.requestNextFile(1, loadHandler);
441                            }
442                        });
443
444                    }
445                });
446                additionalLeftButtons.add(prevButton);
447                additionalLeftButtons.add(nextButton);
448            }
449
450            m_editContext.setRestart(() -> {
451                WorkplacePropertyEditorContext context = new WorkplacePropertyEditorContext(
452                    m_structureId,
453                    contextMenuHandler,
454                    editName,
455                    cancelHandler,
456                    enableAdeTemplateSelect,
457                    new PropertyEditingContext(),
458                    prevFieldData);
459                context.editProperties();
460
461            });
462            CmsPropertyDefinitionButton defButton = m_editContext.createPropertyDefinitionButton();
463
464            FlowPanel leftButtonBox = new FlowPanel();
465            String boxStyle = org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE.dialogCss().leftButtonBox();
466            leftButtonBox.addStyleName(boxStyle);
467            leftButtonBox.getElement().getStyle().setFloat(Float.LEFT);
468            for (CmsPushButton additionalButton : additionalLeftButtons) {
469                leftButtonBox.add(additionalButton);
470            }
471            if (CmsCoreProvider.get().getUserInfo().isDeveloper()) {
472                defButton.setDialog(m_dialog);
473                leftButtonBox.add(defButton);
474            }
475            m_dialog.addButton(leftButtonBox);
476
477            m_dialog.addCloseHandler(new CloseHandler<PopupPanel>() {
478
479                /**
480                 * @see com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt.event.logical.shared.CloseEvent)
481                 */
482                @SuppressWarnings("synthetic-access")
483                public void onClose(CloseEvent<PopupPanel> event) {}
484            });
485
486        }
487
488        /**
489         * Edits properties for current resource.<p>
490         */
491        public void editProperties() {
492
493            CmsRpcAction<CmsPropertiesBean> action = new CmsRpcAction<CmsPropertiesBean>() {
494
495                @SuppressWarnings("synthetic-access")
496                @Override
497                public void execute() {
498
499                    start(0, true);
500                    CmsCoreProvider.getVfsService().loadPropertyData(m_structureId, this);
501                }
502
503                @SuppressWarnings("synthetic-access")
504                @Override
505                protected void onResponse(CmsPropertiesBean result) {
506
507                    stop(false);
508                    updateData(result);
509                }
510
511            };
512            action.execute();
513
514        }
515
516        /**
517         * Gets the structure id.
518         *
519         * @return the structure id
520         */
521        public CmsUUID getStructureId() {
522
523            return m_structureId;
524        }
525
526        /**
527         * @see org.opencms.gwt.client.ui.input.form.I_CmsFormHandler#isSubmitting()
528         */
529        public boolean isSubmitting() {
530
531            return m_submitting;
532        }
533
534        /**
535         * @see org.opencms.gwt.client.ui.input.form.I_CmsFormHandler#onSubmitValidationResult(org.opencms.gwt.client.ui.input.form.CmsForm, boolean)
536         */
537        public void onSubmitValidationResult(CmsForm form, boolean ok) {
538
539            if (ok) {
540                m_submitting = true;
541                if (!m_isPrevNext) {
542                    m_contextMenuHandler.refreshResource(CmsUUID.getNullUUID());
543                    m_dialog.hide();
544                }
545                m_isPrevNext = false;
546                form.handleSubmit(m_submitHandler);
547            } else {
548                m_dialog.setOkButtonEnabled(form.noFieldsInvalid());
549            }
550        }
551
552        /**
553         * @see org.opencms.gwt.client.ui.input.form.I_CmsFormHandler#onValidationResult(org.opencms.gwt.client.ui.input.form.CmsForm, boolean)
554         */
555        public void onValidationResult(CmsForm form, boolean ok) {
556
557            m_dialog.setOkButtonEnabled(ok);
558        }
559
560        /**
561         * Gets the active field data.<p>
562         *
563         * @return the active field data
564         */
565        CmsActiveFieldData getActiveFieldData() {
566
567            if (m_editor != null) {
568                return m_editor.getActiveFieldData();
569            } else {
570                return null;
571            }
572        }
573
574        /**
575         * Updates the property dialog with the next resource.<p>
576         *
577         * @param result the data for the next resource
578         */
579        private void updateData(CmsPropertiesBean result) {
580
581            final PropertyEditorHandler handler = new PropertyEditorHandler(null);
582            m_handler = handler;
583            handler.setEnableAdeTemplateSelect(m_enableAdeTemplateSelect);
584            m_editContext.setCancelHandler(m_cancelHandler);
585
586            handler.setPropertiesBean(result);
587            handler.setEditableName(m_editName);
588            final CmsVfsModePropertyEditor editor = new CmsVfsModePropertyEditor(
589                result.getPropertyDefinitions(),
590                handler);
591            m_editor = editor;
592            editor.setShowResourceProperties(!handler.isFolder());
593            editor.setReadOnly(result.isReadOnly());
594
595            m_editContext.setFormHandler(this);
596
597            m_submitHandler = new CmsPropertySubmitHandler(handler);
598            editor.getForm().setFormHandler(this);
599            try {
600                CmsVfsModePropertyEditor.disableResize(true);
601                editor.restoreActiveFieldData(m_prevFieldData);
602                editor.initializeWidgets(m_dialog);
603                m_dialog.setForm(editor.getForm());
604                m_dialog.centerHorizontally(50);
605            } finally {
606                CmsVfsModePropertyEditor.disableResize(false);
607            }
608
609        }
610
611    }
612
613    /**
614     * Property editor handler which uses a text box for the template selection.<p>
615     */
616    protected static class PropertyEditorHandler extends CmsSimplePropertyEditorHandler {
617
618        /** Enables the ADE template select box for pages. */
619        private boolean m_enableAdeTemplateSelect;
620
621        /** The stored callback. */
622        private Runnable m_nextAction;
623
624        /**
625         * Creates a new instance.<p>
626         *
627         * @param handler the handler
628         */
629        public PropertyEditorHandler(I_CmsContextMenuHandler handler) {
630
631            super(handler);
632        }
633
634        /**
635         * Executes and clears the stored callback.<p>
636         */
637        public void runAction() {
638
639            if (m_nextAction != null) {
640                m_nextAction.run();
641                m_nextAction = null;
642            }
643        }
644
645        /**
646         * Enables or disables the ADE template select box for pages.<p>
647         *
648         * @param enableAdeTemplateSelect true if ADE template select box for pages should be enabled
649         */
650        public void setEnableAdeTemplateSelect(boolean enableAdeTemplateSelect) {
651
652            m_enableAdeTemplateSelect = enableAdeTemplateSelect;
653        }
654
655        /**
656         * Stores an action to execute after successful submits.<p>
657         *
658         * @param runnable the callback
659         */
660        public void setNextAction(Runnable runnable) {
661
662            m_nextAction = runnable;
663
664        }
665
666        /**
667         * @see org.opencms.gwt.client.property.CmsSimplePropertyEditorHandler#useAdeTemplates()
668         */
669        @Override
670        public boolean useAdeTemplates() {
671
672            return m_enableAdeTemplateSelect;
673        }
674
675        /**
676         * @see org.opencms.gwt.client.property.CmsSimplePropertyEditorHandler#onSubmitSuccess()
677         */
678        @Override
679        protected void onSubmitSuccess() {
680
681            super.onSubmitSuccess();
682            runAction();
683        }
684
685    }
686
687    /**
688     * Property dialog subclass which keeps track of which way the dialog is exited.<p>
689     */
690    static class PropertiesFormDialog extends CmsFormDialog {
691
692        /** The content panel. */
693        private FlowPanel m_content = new FlowPanel();
694
695        /** True if the dialog should be truly exited. */
696        private boolean m_maybeExit;
697
698        /**
699         * Creates a new instance.<p>
700         *
701         * @param title the title
702         * @param form the form
703         */
704        public PropertiesFormDialog(String title, CmsForm form) {
705
706            super(title, form);
707            setMainContent(m_content);
708        }
709
710        /**
711         * Return true if OK or Cancel was clicked previously.<p>
712         *
713         * @return true if OK or Cancel was clicked previously
714         */
715        public boolean maybeExit() {
716
717            return m_maybeExit;
718        }
719
720        /**
721         * @see org.opencms.gwt.client.ui.input.form.CmsFormDialog#onClickCancel()
722         */
723        @Override
724        public void onClickCancel() {
725
726            m_maybeExit = true;
727            super.onClickCancel();
728        }
729
730        /**
731         * Sets the form.<p>
732         *
733         * @param form the form
734         */
735        public void setForm(CmsForm form) {
736
737            m_form = form;
738        }
739
740        /**
741         * @see org.opencms.gwt.client.ui.input.form.CmsFormDialog#initContent()
742         */
743        @Override
744        protected void initContent() {
745
746            int prevHeight = m_content.getOffsetHeight();
747            if (m_content.getWidgetCount() > 0) {
748                int childPrevHeight = m_content.getWidget(0).getOffsetHeight();
749                if (childPrevHeight > 0) {
750                    prevHeight = childPrevHeight;
751                }
752            }
753            final String parentStyle = I_CmsLayoutBundle.INSTANCE.propertiesCss().propertyParentLoading();
754            if (prevHeight > 0) {
755                m_content.getElement().getStyle().setProperty("minHeight", "" + prevHeight + "px");
756            }
757            m_content.addStyleName(parentStyle);
758            m_content.clear();
759            final Widget formWidget = m_form.getWidget();
760            m_content.add(formWidget);
761
762            Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
763
764                @SuppressWarnings("synthetic-access")
765                public boolean execute() {
766
767                    if (!formWidget.isAttached()) {
768                        m_content.removeStyleName(parentStyle);
769                        return false;
770                    }
771                    if (formWidget.getOffsetHeight() > 100) {
772                        m_content.getElement().getStyle().clearProperty("minHeight");
773                        m_content.removeStyleName(parentStyle);
774                        return false;
775                    }
776                    return true;
777                }
778            }, 100);
779        }
780
781        /**
782         * @see org.opencms.gwt.client.ui.input.form.CmsFormDialog#onClickOk()
783         */
784        @Override
785        protected void onClickOk() {
786
787            m_maybeExit = true;
788            super.onClickOk();
789        }
790    }
791
792    /**
793     * Hidden utility class constructor.<p>
794     */
795    private CmsEditProperties() {
796
797        // nothing to do
798    }
799
800    /**
801     * Starts the property editor for the resource with the given structure id.<p>
802     *
803     * @param structureId the structure id of a resource
804     * @param contextMenuHandler the context menu handler
805     * @param editName if true, provides a field for changing the file name
806     * @param cancelHandler callback which is executed if the user cancels the property dialog
807     * @param enableAdeTemplateSelect enables/disables special template selector
808     * @param editContext the editing context
809     */
810    public static void editProperties(
811        final CmsUUID structureId,
812        final I_CmsContextMenuHandler contextMenuHandler,
813        final boolean editName,
814        final Runnable cancelHandler,
815        final boolean enableAdeTemplateSelect,
816        final PropertyEditingContext editContext) {
817
818        CmsRpcAction<CmsPropertiesBean> action = new CmsRpcAction<CmsPropertiesBean>() {
819
820            @Override
821            public void execute() {
822
823                start(0, true);
824                CmsCoreProvider.getVfsService().loadPropertyData(structureId, this);
825            }
826
827            @Override
828            protected void onResponse(CmsPropertiesBean result) {
829
830                stop(false);
831                openPropertyDialog(
832                    result,
833                    contextMenuHandler,
834                    editName,
835                    cancelHandler,
836                    enableAdeTemplateSelect,
837                    editContext);
838            }
839
840        };
841        action.execute();
842    }
843
844    /**
845     * Starts the property editor for the resource with the given structure id.<p>
846     *
847     * @param structureId the structure id of a resource
848     * @param contextMenuHandler the context menu handler
849     * @param editName if true, provides a field for changing the file name
850     * @param cancelHandler callback which is executed if the user cancels the property dialog
851     * @param enableAdeTemplateSelect enables/disables special template selector
852     * @param editContext the editing context
853     * @param prevFieldData the previous active field data (may be null)
854     */
855    public static void editPropertiesWithFileNavigation(
856        final CmsUUID structureId,
857        final I_CmsContextMenuHandler contextMenuHandler,
858        final boolean editName,
859        final Runnable cancelHandler,
860        final boolean enableAdeTemplateSelect,
861        final PropertyEditingContext editContext,
862        final CmsActiveFieldData prevFieldData) {
863
864        new WorkplacePropertyEditorContext(
865            structureId,
866            contextMenuHandler,
867            editName,
868            cancelHandler,
869            enableAdeTemplateSelect,
870            editContext,
871            prevFieldData).editProperties();
872
873    }
874
875    /**
876     * Returns the context menu command according to
877     * {@link org.opencms.gwt.client.ui.contextmenu.I_CmsHasContextMenuCommand}.<p>
878     *
879     * @return the context menu command
880     */
881    public static I_CmsContextMenuCommand getContextMenuCommand() {
882
883        return new I_CmsContextMenuCommand() {
884
885            public void execute(CmsUUID structureId, I_CmsContextMenuHandler handler, CmsContextMenuEntryBean bean) {
886
887                editProperties(structureId, handler, false, null, true, new PropertyEditingContext());
888            }
889
890            public A_CmsContextMenuItem getItemWidget(
891                CmsUUID structureId,
892                I_CmsContextMenuHandler handler,
893                CmsContextMenuEntryBean bean) {
894
895                return null;
896            }
897
898            public boolean hasItemWidget() {
899
900                return false;
901            }
902        };
903    }
904
905    /**
906     * Opens the property dialog and populates it with the data from a given CmsPropertiesBean.<p>
907     *
908     * @param result the property data
909     * @param contextMenuHandler the context menu handler
910     * @param editName true if the name should be editable
911     * @param cancelHandler the cancel handler
912     * @param enableAdeTemplateSelect true if template selection should be enabled
913     * @param editContext the edit context
914     */
915    public static void openPropertyDialog(
916        CmsPropertiesBean result,
917        final I_CmsContextMenuHandler contextMenuHandler,
918        final boolean editName,
919        final Runnable cancelHandler,
920        final boolean enableAdeTemplateSelect,
921        final PropertyEditingContext editContext) {
922
923        final PropertyEditorHandler handler = new PropertyEditorHandler(contextMenuHandler);
924        handler.setPropertySaver(editContext.getPropertySaver());
925        handler.setEnableAdeTemplateSelect(enableAdeTemplateSelect);
926        editContext.setCancelHandler(cancelHandler);
927
928        handler.setPropertiesBean(result);
929        handler.setEditableName(editName);
930        final CmsVfsModePropertyEditor editor = new CmsVfsModePropertyEditor(result.getPropertyDefinitions(), handler);
931
932        editor.setShowResourceProperties(!handler.isFolder());
933        editor.setReadOnly(result.isReadOnly());
934
935        final CmsFormDialog dialog = new PropertiesFormDialog(handler.getDialogTitle(), editor.getForm());
936        editContext.setDialog(dialog);
937
938        if (editContext.allowCreateProperties()) {
939            CmsPropertyDefinitionButton defButton = editContext.createPropertyDefinitionButton();
940            defButton.installOnDialog(dialog);
941            defButton.getElement().getStyle().setFloat(Float.LEFT);
942        }
943        final CmsDialogFormHandler formHandler = new CmsDialogFormHandler();
944        editContext.setFormHandler(formHandler);
945        editContext.initCloseHandler();
946        formHandler.setDialog(dialog);
947        I_CmsFormSubmitHandler submitHandler = new CmsPropertySubmitHandler(handler);
948        formHandler.setSubmitHandler(submitHandler);
949        editor.getForm().setFormHandler(formHandler);
950        editor.initializeWidgets(dialog);
951
952        dialog.centerHorizontally(50);
953        if (editContext.isFocusNameField()) {
954            editor.focusNameField();
955        }
956
957        dialog.catchNotifications();
958    }
959
960}