Ticket #2413: sync-template-subelements-impl.patch

File sync-template-subelements-impl.patch, 19.2 KB (added by deni, 15 years ago)
  • modules/org.sophie2.main.app.commons/src/main/java/org/sophie2/main/app/commons/util/TemplateUtil.java

    ### Eclipse Workspace Patch 1.0
    #P sophie
     
    109109                final ResourceRefList newTemplates =  
    110110                        templates.contains(templateRef) ? templates : templates.add(templateRef); 
    111111                 
    112                 //auto-action which changes the keys of the root element/its sub-elements 
    113                 String changeKeysDescription = "Change the template's elements' keys"; 
    114                 new AutoAction(changeKeysDescription, false) { 
     112                 
     113                ImmList<ResourceRefR4> rootsToDelete = ImmTreeList.<ResourceRefR4>create(); 
     114                /* 
     115                 * Adds the references to be removed. We're looking for references who should be deleted, 
     116                 * but their parent shouldn't be (so when we remove them, we'll remove all their sub-elements as well,  
     117                 * which is what we need). Note that iterRef.getParentRef() will never equal the ref of the element we're templating, 
     118                 * because we pass the root as an absolute reference and the sub-elements as relative ones.  
     119                 */ 
     120                for (ResourceRefR4 iterRef : toDelete) { 
     121                        if (!toDelete.contains(iterRef.getParentRef()) && !iterRef.equals(ref) ) { 
     122                                rootsToDelete = rootsToDelete.add(iterRef); 
     123                        } 
     124                }                
     125                final ImmList<ResourceRefR4> finalRootsToDelete = rootsToDelete; 
     126                 
     127                /* 
     128                 * Copies the template as a child of the book, changes its keys and deletes 
     129                 * the unneeded sub-elements (also removes their activation channels from the  
     130                 * corresponding parent's KEY_SUB_ELEMENTS key). 
     131                 */ 
     132                new AutoAction(description, true) { 
    115133                        @Override 
    116134                        public void performAuto() { 
    117135                                getChanger().copyResource(relativeRef, templateRef); 
     
    136154                                if(createDefaultTemplate) { 
    137155                                        getChanger().setRaw(defaultTemplateKey, templateRef); 
    138156                                } 
    139                         } 
    140  
    141                 }.register(bookAccess); 
    142                  
    143                 ImmList<ResourceRefR4> rootsToDelete = ImmTreeList.<ResourceRefR4>create(); 
    144                  
    145                 /* 
    146                  * Adds the references to be removed. We're looking for references who should be deleted, 
    147                  * but their parent shouldn't be (so when we remove them, we'll remove all their sub-elements as well,  
    148                  * which is what we need). Note that iterRef.getParentRef() will never equal the ref of the element we're templating, 
    149                  * because we pass the root as an absolute reference and the sub-elements as relative ones.  
    150                  */ 
    151                 for (ResourceRefR4 iterRef : toDelete) { 
    152                         if (!toDelete.contains(iterRef.getParentRef()) && !iterRef.equals(ref) ) { 
    153                                 rootsToDelete = rootsToDelete.add(iterRef); 
    154                         } 
    155                 } 
    156                  
    157                 final ImmList<ResourceRefR4> finalRootsToDelete = rootsToDelete; 
    158                  
    159                 /* 
    160                  * Auto-action which deletes the unneeded sub-elements (also removes their activation channels from the  
    161                  * corresponding parent's KEY_SUB_ELEMENTS key). 
    162                  */ 
    163                 new AutoAction (description, isSign) { 
    164                         @Override 
    165                         public void performAuto () { 
    166                                 ResourceChanger subCh = getChanger().getSub(templateRef); 
    167157                                                                 
    168158                                for (ResourceRefR4 iterRef : finalRootsToDelete) { 
    169159                                        ResourceRefR4 parent = iterRef.getParentRef(), parentToIterRef = ResourceRefR4.getRelativeRef(parent, iterRef); 
     
    184174                                        subCh.removeResource(iterRef);   
    185175                                } 
    186176                        } 
     177 
    187178                }.register(bookAccess); 
    188179        } 
    189180 
     
    328319         * @param pageTemplateRef 
    329320         *              An absolute reference to the template to apply. 
    330321         * @param existingMap 
    331          *              A map from frames in the given page template to existing frames in the page 
    332          *              to which the template will be applied. The frames from the template will be used 
    333          *              as templates for the frames in the page. 
     322         *              A map from elements in the given page template to existing frames in the page 
     323         *              to which the template will be applied. The elements from the template will be used 
     324         *              as templates for the elements in the page. 
    334325         * @param list 
    335          *              A list containing frames in the given page templates that should be instantiated 
     326         *              A list containing elements in the given page template that should be instantiated 
    336327         *              as templates. 
    337328         */ 
    338329        public static void applyPageTemplate(PageH page, ResourceRefR4 pageTemplateRef, 
     
    369360                } 
    370361        } 
    371362         
    372         private static void templatePageElements(ElementH templateH, ElementH parent,  
     363        /** 
     364         * Templates a page element.  
     365         *  
     366         * @param templateH 
     367         *              The template that should be applied. 
     368         * @param parent 
     369         *              The parent of the element to which the template should be applied. 
     370         * @param newElements 
     371         *              A list containing elements from the template that should be instantiated. 
     372         * @param existing 
     373         *              A map from elements in the template to existing elements to which they should be applied. 
     374         */ 
     375        public static void templatePageElements(ElementH templateH, ElementH parent,  
    373376                        List<ResourceRefR4> newElements, Map<ResourceRefR4, ResourceRefR4> existing) { 
    374  
     377                 
    375378                if (!newElements.contains(templateH.getRef()) && !existing.containsKey(templateH.getRef())) { 
    376379                        return; 
    377380                } 
     
    382385                        if (newElements.contains(templateH.getRef())) { 
    383386                                assert !existing.containsKey(templateH.getRef()); 
    384387                                nextParentRef = createNewEmptyGroup((ElementGroupH)templateH, parent); 
    385                         } else { 
     388                        } else {                                 
    386389                                nextParentRef = existing.get(templateH.getRef()); 
     390                                ResourceAccess groupAccess = parent.getAccess().open(nextParentRef, null); 
     391                                ElementGroupH groupH = ResourceH.getHelper(groupAccess, ElementGroupH.class); 
     392                                final NaiveImmList<TemplatedKey<?>> keys = groupH.getApplicableTemplatedKeys(); 
     393                                 
     394                                final ResourceRefR4 groupToTemplateRef =  
     395                                        ResourceRefR4.getRelativeRef(groupAccess.getRef(), templateH.getRef()); 
     396                                 
     397                                new AutoAction("Template group", false) { 
     398 
     399                                        @Override 
     400                                        public void performAuto() { 
     401                                                ResourceChanger ch = getChanger(); 
     402                                                ch.setRaw(ResourceR4.KEY_TEMPLATE, groupToTemplateRef); 
     403                                                for (Key<?> key : keys) { 
     404                                                        ch.setRaw(key, null); 
     405                                                } 
     406                                        } 
     407                                         
     408                                }.register(groupAccess); 
    387409                        } 
    388410                         
    389411                        ResourceAccess groupAccess = parent.getAccess().open(nextParentRef, null); 
     
    410432                final String groupTitle = templateH.getTitle(); 
    411433                final ImmList<ActivationChannel> parentElements =  
    412434                        CompositeElement.KEY_SUB_ELEMENTS.get(parent.getAccess()); 
    413  
     435                final ResourceRefR4 groupToTemplateRef = ResourceRefR4.PARENT_REF.append( 
     436                                ResourceRefR4.getRelativeRef(parent.getRef(), templateH.getRef())); 
     437                final NaiveImmList<TemplatedKey<?>> keys = templateH.getApplicableTemplatedKeys(); 
     438                 
    414439                new AutoAction("Create group for template", false) { 
    415440 
    416441                        @Override 
     
    423448                                ResourceChanger groupCh = ch.getSub(groupRef); 
    424449                                groupCh.setRaw(ResourceR4.KEY_KIND, ElementGroupR4.KIND); 
    425450                                groupCh.setRaw(ResourceR4.KEY_TITLE, groupTitle); 
     451                                 
     452                                groupCh.setRaw(ResourceR4.KEY_TEMPLATE, groupToTemplateRef); 
     453                                for (Key<?> key : keys) { 
     454                                        groupCh.setRaw(key, null); 
     455                                } 
    426456                        } 
    427457 
    428458                }.register(parent.getAccess()); 
     
    435465                final String frameKind = templateH.getKind(); 
    436466                final NaiveImmList<TemplatedKey<?>> immKeys = templateH.getApplicableTemplatedKeys(); 
    437467 
    438                 final ResourceRefR4 frameRef = ResourceRefR4.generateRandomSub(FrameH.NAME_PREFIX); 
     468                final ResourceRefR4 frameRef = templateH.getRef().getThisChildRef(); 
    439469                final String frameTitle = templateH.getTitle(); 
    440470 
    441471                final ResourceRefR4 parentRef = parent.getRef(); 
  • modules/org.sophie2.base.model.book/src/main/java/org/sophie2/base/model/book/FrameH.java

     
    1212import org.sophie2.base.model.book.interfaces.CompositeElement; 
    1313import org.sophie2.base.model.book.interfaces.MemberElement; 
    1414import org.sophie2.base.model.book.interfaces.ResizableElement; 
     15import org.sophie2.base.model.book.interfaces.ResourceFrame; 
    1516import org.sophie2.base.model.book.timelines.ActivationChannel; 
    1617import org.sophie2.base.model.book.timelines.LocationChannel; 
    1718import org.sophie2.base.model.resources.r4.ResourceRefR4; 
    1819import org.sophie2.base.model.resources.r4.access.ResourceAccess; 
     20import org.sophie2.base.model.resources.r4.changes.AutoAction; 
    1921import org.sophie2.base.model.resources.r4.changes.ResourceChanger; 
    2022import org.sophie2.base.model.resources.r4.resources.ResourceR4; 
    2123import org.sophie2.core.prolib.impl.AutoProperty; 
     
    206208                }  
    207209                return super.getBoundArea(boundMode, elementTime, wrapMode); 
    208210        } 
     211         
     212        /** 
     213         * Property synchronizing the kind of this frame with the kind of its template.  
     214         *  
     215         * @return 
     216         *              The property. 
     217         */ 
     218        @SuppressWarnings("unused") 
     219        private Prop<String> templateKind() { 
     220                class templateKind extends AutoProperty<String> { 
     221 
     222                        private String prevTemplateKind = ResourceR4.KIND; 
     223                        private ResourceRefR4 prevTemplate = ResourceRefR4.NONE_REF; 
     224                         
     225                        @Override 
     226                        protected String compute() { 
     227                                ResourceRefR4 templateRef = getTemplate(); 
     228                                ResourceAccess templateAccess = getAccess().open(templateRef, null); 
     229                                final String templateKind = ResourceR4.KEY_KIND.get(templateAccess); 
     230                                 
     231                                if (!templateKind.equals(this.prevTemplateKind)) { 
     232                                         
     233                                        if (templateRef.equals(this.prevTemplate) 
     234                                                        && ResourceFrame.KEY_MAIN_RESOURCE.getApplyKey().get(templateAccess)) { 
     235                                                 
     236                                                new AutoAction("Change kind", true) { 
     237 
     238                                                        @Override 
     239                                                        public void performAuto() { 
     240                                                                getChanger().setRaw(ResourceR4.KEY_KIND, templateKind); 
     241                                                        } 
     242                                                         
     243                                                }.register(getAccess()); 
     244                                        } 
     245                                 
     246                                        this.prevTemplate = templateRef; 
     247                                        this.prevTemplateKind = templateKind;    
     248                                } 
     249                                 
     250                                return templateKind; 
     251                        } 
     252                } 
     253                 
     254                return getBean().makeProp(templateKind.class); 
     255        } 
    209256} 
  • modules/org.sophie2.main.func.templates/src/main/java/org/sophie2/main/func/templates/MainFuncTemplatesModule.java

     
    1919import org.sophie2.main.app.menus.file.SaveBookAsTemplateItem; 
    2020import org.sophie2.main.func.templates.book.BookTemplatesLogic; 
    2121import org.sophie2.main.func.templates.book.BookTemplatesPalette; 
     22import org.sophie2.main.func.templates.composite.CompositeTemplateLogic; 
    2223import org.sophie2.main.func.templates.frame.FrameTemplateLogic; 
    2324import org.sophie2.main.func.templates.frame.FrameTemplatesPalette; 
    2425import org.sophie2.main.func.templates.page.ApplyPageTemplateDialog; 
     
    6263                SimpleOperation.fillExtensions(res, FrameTemplateLogic.class);           
    6364                SimpleOperation.fillExtensions(res, PageTemplateLogic.class);            
    6465                SimpleOperation.fillExtensions(res, BookTemplatesLogic.class); 
    65                  
     66                SimpleOperation.fillExtensions(res, CompositeTemplateLogic.class); 
     67 
    6668                res.add(new SimpleSophieExtension<Dialog>(Dialog.class, 
    6769                                new ApplyPageTemplateDialog())); 
    6870                AutoVisualProvider.fillExtensions(res, ApplyPageTemplateSwingDialog.class); 
  • modules/org.sophie2.base.model.book/src/main/java/org/sophie2/base/model/book/ElementH.java

     
    55 
    66import org.sophie2.base.commons.structures.ImmTreeList; 
    77import org.sophie2.base.commons.util.ImmList; 
     8import org.sophie2.base.commons.util.NaiveImmList; 
    89import org.sophie2.base.commons.util.position.ImmArea; 
    910import org.sophie2.base.commons.util.position.ImmInsets; 
    1011import org.sophie2.base.commons.util.position.ImmMatrix; 
     
    3334import org.sophie2.base.model.resources.r4.resources.ResourceH; 
    3435import org.sophie2.base.model.resources.r4.resources.ResourceR4; 
    3536import org.sophie2.core.logging.SophieLog; 
     37import org.sophie2.core.mvc.EventParams; 
     38import org.sophie2.core.mvc.LogicR3; 
    3639import org.sophie2.core.prolib.impl.AutoProperty; 
    3740import org.sophie2.core.prolib.interfaces.Prop; 
    3841 
     
    567570                } 
    568571                return null; 
    569572        } 
     573         
     574        /** 
     575         * Property synchronizing the sub-elements of this elements with those of its template. 
     576         *  
     577         * @return 
     578         *              The property. 
     579         */ 
     580        @SuppressWarnings("unused") 
     581        private Prop<ImmList<ActivationChannel>> templateSubElements() { 
     582                class templateSubElements extends AutoProperty<ImmList<ActivationChannel>> { 
    570583 
     584                        private ImmList<ActivationChannel> prevTemplateElements =  
     585                                NaiveImmList.<ActivationChannel>getEmpty(); 
     586                        private ResourceRefR4 prevTemplate = ResourceRefR4.NONE_REF; 
     587 
     588                        @Override 
     589                        protected ImmList<ActivationChannel> compute() { 
     590 
     591                                ResourceRefR4 templateRef = getTemplate(); 
     592                                ResourceAccess templateAccess = getAccess().open(templateRef, null); 
     593                                ImmList<ActivationChannel> subelements =  
     594                                        CompositeElement.KEY_SUB_ELEMENTS.get(templateAccess); 
     595 
     596                                if (!this.prevTemplateElements.equals(subelements)) { 
     597                                         
     598                                        if (templateRef.equals(this.prevTemplate)) { 
     599                                                for (ActivationChannel channel : this.prevTemplateElements) { 
     600                                                        if (!subelements.contains(channel)) { 
     601                                                                LogicR3.fire(ElementH.this, null, null, null,  
     602                                                                                TemplateEventIds.TEMPLATE_ELEMENT_DELETED, 
     603                                                                                ResourceRefR4.PARENT_REF.append(templateRef.append(channel.getElementResource()))); 
     604                                                        } 
     605                                                } 
     606 
     607                                                for (ActivationChannel channel : subelements) { 
     608                                                        if (!this.prevTemplateElements.contains(channel)) { 
     609                                                                LogicR3.fire(ElementH.this, null, null, null,  
     610                                                                                TemplateEventIds.TEMPLATE_ELEMENT_ADDED, 
     611                                                                                templateRef.append(channel.getElementResource())); 
     612                                                        } 
     613                                                } 
     614                                        } else {                                                 
     615                                                this.prevTemplate = templateRef; 
     616                                        } 
     617 
     618                                        this.prevTemplateElements = subelements; 
     619                                } 
     620 
     621                                return subelements; 
     622                        } 
     623 
     624                } 
     625                return getBean().makeProp(templateSubElements.class); 
     626        } 
     627         
     628        /** 
     629         * Events related to changes in this element's template. 
     630         *  
     631         * @author deni 
     632         */ 
     633        public enum TemplateEventIds { 
     634                 
     635                /** 
     636                 * A new sub-element has been added to the template. 
     637                 */ 
     638                @EventParams({ ResourceRefR4.class }) 
     639                TEMPLATE_ELEMENT_ADDED, 
     640                 
     641                /** 
     642                 * A sub-element has been deleted from the template. 
     643                 */ 
     644                @EventParams({ ResourceRefR4.class }) 
     645                TEMPLATE_ELEMENT_DELETED; 
     646                 
     647                /** 
     648                 * The index of the ResourceRef parameter pointing to the sub-element 
     649                 * that was added/removed. 
     650                 */ 
     651                public static final int RESOURCE_REF_PARAM_INDEX = 0; 
     652        } 
     653 
    571654} 
  • modules/org.sophie2.main.func.templates/src/main/java/org/sophie2/main/func/templates/composite/CompositeTemplateLogic.java

     
     1package org.sophie2.main.func.templates.composite; 
     2 
     3import java.util.ArrayList; 
     4import java.util.HashMap; 
     5import java.util.List; 
     6 
     7import org.sophie2.base.model.book.ElementH; 
     8import org.sophie2.base.model.book.ElementH.TemplateEventIds; 
     9import org.sophie2.base.model.resources.r4.ResourceRefR4; 
     10import org.sophie2.base.model.resources.r4.access.ResourceAccess; 
     11import org.sophie2.base.model.resources.r4.changes.AutoAction; 
     12import org.sophie2.base.model.resources.r4.resources.ResourceH; 
     13import org.sophie2.core.mvc.EventFilterBuilder; 
     14import org.sophie2.core.mvc.OperationDef; 
     15import org.sophie2.core.mvc.events.EventR3; 
     16import org.sophie2.main.app.commons.util.TemplateUtil; 
     17 
     18/** 
     19 * Logic for handling events related to changes in the template of an element. 
     20 *  
     21 * @author deni 
     22 */ 
     23public enum CompositeTemplateLogic implements OperationDef { 
     24         
     25        /** 
     26         * Handles adding a new sub-element (sub-template) to the template of the source element. 
     27         * Creates a new sub-element by the sub-template. 
     28         */ 
     29        ON_TEMPLATE_SUBELEMENT_ADDED { 
     30 
     31                public void defineFilter(EventFilterBuilder filter) { 
     32                        filter.setSourceClass(ElementH.class); 
     33                        filter.setEventId(TemplateEventIds.TEMPLATE_ELEMENT_ADDED); 
     34                } 
     35 
     36                public boolean handle(EventR3 event) { 
     37                        ElementH source = event.getSource(ElementH.class); 
     38                        ResourceRefR4 templateRef = event.getEventParam(TemplateEventIds.RESOURCE_REF_PARAM_INDEX, 
     39                                        ResourceRefR4.class); 
     40                        ResourceAccess templateAccess = source.getAccess().open(templateRef, null); 
     41                        ElementH templateH = ResourceH.getHelper(templateAccess, ElementH.class); 
     42                         
     43                        ResourceRefR4 subelementToTemplate = ResourceRefR4.PARENT_REF.append(templateRef); 
     44                        boolean templateUsed = false; 
     45                        for (ElementH subelement : source.getSubElements()) { 
     46                                if (subelement.getTemplate().equals(subelementToTemplate)) { 
     47                                        templateUsed = true; 
     48                                        break; 
     49                                } 
     50                        } 
     51                         
     52                        if (!templateUsed) { 
     53                                TemplateUtil.templatePageElements(templateH, source, getAllSubelements(templateH),  
     54                                                new HashMap<ResourceRefR4, ResourceRefR4>()); 
     55                                AutoAction.registerEndChange(source.getAccess(), "Add elements by template."); 
     56                        } 
     57                         
     58                        return true; 
     59                } 
     60                 
     61                private List<ResourceRefR4> getAllSubelements(ElementH element) { 
     62                        List<ResourceRefR4> res = new ArrayList<ResourceRefR4>(); 
     63                        res.add(element.getRef()); 
     64                        for (ElementH subelement : element.getSubElements()) { 
     65                                res.addAll(getAllSubelements(subelement)); 
     66                        }                
     67                        return res; 
     68                } 
     69                 
     70        }, 
     71         
     72        /** 
     73         * Handles deleting a sub-element (sub-template) from the template of the source element. 
     74         * Deletes the element that was using the sub-template. 
     75         */ 
     76        ON_TEMPLATE_SUBELEMENT_DELETED { 
     77 
     78                public void defineFilter(EventFilterBuilder filter) { 
     79                        filter.setSourceClass(ElementH.class); 
     80                        filter.setEventId(TemplateEventIds.TEMPLATE_ELEMENT_DELETED);                    
     81                } 
     82 
     83                public boolean handle(EventR3 event) { 
     84                        ElementH source = event.getSource(ElementH.class); 
     85                        ResourceRefR4 templateRef = event.getEventParam(TemplateEventIds.RESOURCE_REF_PARAM_INDEX, 
     86                                        ResourceRefR4.class); 
     87                         
     88                        for (ElementH subelement : source.getSubElements()) { 
     89                                ResourceRefR4 subelementToTemplateRef = ResourceRefR4.getRelativeRef( 
     90                                                subelement.getRef(), templateRef); 
     91                                if (subelementToTemplateRef.equals(subelement.getTemplate())) { 
     92                                        source.removeSubElement(subelement.getRef().getThisChildRef(),  
     93                                                        "removing subelement", false); 
     94                                } 
     95                        } 
     96                        AutoAction.registerEndChange(source.getAccess(), "Delete elements from template."); 
     97                         
     98                        return true; 
     99                } 
     100                 
     101        } 
     102 
     103}