Ticket #2171: performance.patch

File performance.patch, 40.1 KB (added by mira, 15 years ago)

change-set

  • src/test/java/org/sophie2/dev/author/PlainTextImportTest.java

    ### Eclipse Workspace Patch 1.0
    #P org.sophie2.dev
     
    8787 
    8888                TextFrameView frame = (TextFrameView) vw; 
    8989                TextFrameH firstFrameContent = frame.model().get(); 
    90                 HotTextResourceH text1 = firstFrameContent.getHeadHelper(vw.getBookView()).getTextModel(); 
     90                HotTextResourceH text1 = firstFrameContent.getHeadHelper(vw.getBookView().model().get()).getTextModel(); 
    9191                ImmHotText ht = text1.getText(); 
    9292                 
    9393                BufferedReader reader = new BufferedReader(new FileReader(plainFile.getAbsolutePath())); 
  • src/test/java/org/sophie2/dev/author/HtmlImportTest.java

     
    9393 
    9494                TextFrameView frame = (TextFrameView) vw; 
    9595                TextFrameH firstFrameContent = frame.model().get(); 
    96                 HotTextResourceH text1 = firstFrameContent.getHeadHelper(vw.getBookView()).getTextModel(); 
     96                HotTextResourceH text1 = firstFrameContent.getHeadHelper(vw.getBookView().model().get()).getTextModel(); 
    9797                ImmHotText ht = text1.getText(); 
    9898                 
    9999                StyledEditorKit kit = new HTMLEditorKit(); 
  • src/test/java/org/sophie2/dev/author/TextChainingSystemTest.java

     
    247247                assertEquals(ChainingMode.AUTO_CHAINING, selectedFrameView.model().get().getChainMode()); 
    248248                assertEquals(EXPECTED_PAGE_COUNT, curBook().getPageCount()); 
    249249                assertEquals(EXPECTED_FRAME_COUNT, selectedFrameView.model().get().getChainedFrames( 
    250                                 selectedFrameView.getBookView()).size()); 
     250                                selectedFrameView.getBookView().model().get()).size()); 
    251251        } 
    252252         
    253253        /** 
  • src/main/java/org/sophie2/base/model/text/smart/layout/HotLayout.java

    #P org.sophie2.base.model.text
     
    137137                List<ImmArea> areas = this.layout.getAreas(); 
    138138                int lastIndex = areas.size() - 1; 
    139139                if (lastIndex == -1) { 
    140                         return -1; 
     140                        if (text.getLength() == 0) { 
     141                                return -1; 
     142                        } 
     143                        return 0; 
    141144                } 
    142145                int firstInLastPage = areas.size() - areasCount; 
    143146                ImmHotText hotText = this.getAreaContent(firstInLastPage); 
     
    157160                return dryRun(text, areasToAdd, this); 
    158161        } 
    159162 
    160         /** 
    161          * Simpler and faster check whether the layout is surely appropriate and does not need  
    162          * any corrections. Its evaluation is based on the assumption that the last page of the 
    163          * chain contains only one chained frame.   
    164          * 
    165          * @param text 
    166          *              The text that needs to be laid out.  
    167          *  
    168          * @return 
    169          *              True if the current layout is ok, false otherwise.  
    170          */ 
    171         public boolean isLayoutOK(ImmHotText text) { 
    172                 ImmHotText lastAreaText = this.getAreaContent(this.layout.getAreas().size() -1); 
    173  
    174                 if ((lastAreaText.getLength() != 0) &&  this.isTextConsumed(text)){ 
    175                         return true; 
    176                 } 
    177                 return false; 
    178         } 
     163//      /** 
     164//       * Simpler and faster check whether the layout is surely appropriate and does not need  
     165//       * any corrections. Its evaluation is based on the assumption that the last page of the 
     166//       * chain contains only one chained frame.   
     167//       * 
     168//       * @param text 
     169//       *              The text that needs to be laid out.  
     170//       *  
     171//       * @return 
     172//       *              True if the current layout is ok, false otherwise.  
     173//       */ 
     174//      public boolean isLayoutOK(ImmHotText text) { 
     175//              ImmHotText lastAreaText = this.getAreaContent(this.layout.getAreas().size() -1); 
     176// 
     177//              if ((lastAreaText.getLength() != 0) &&  this.isTextConsumed(text)){ 
     178//                      return true; 
     179//              } 
     180//              return false; 
     181//      } 
    179182 
    180183        private static int dryRun(ImmHotText text, List<ImmArea> areasToAdd, HotLayout prevLayout) { 
    181184 
  • src/main/java/org/sophie2/base/model/resources/r4/keys/Key.java

    #P org.sophie2.base.model.resources.r4
     
    2929         * it when building keys. 
    3030         */ 
    3131        public static final String SEPARATOR = ":"; 
    32          
     32 
    3333        /** 
    3434         * Pattern used for splitting keys. 
    3535         */ 
     
    5252         *                      The default value of the new <code>Key</code>. 
    5353         */ 
    5454        protected Key(ImmList<String> parts, Class<T> valueClass, T defValue) { 
    55                 this.parts = parts; 
     55                this.parts = filterEmptyStrings(parts); 
    5656                this.valueClass = valueClass; 
    5757                assert (defValue != null) : "The default value of a key should not be null."; 
    5858                this.defValue = defValue; 
    5959        } 
    60          
     60 
    6161        /** 
    6262         * Key constructor that constructs a <code>Key</code> by a given string id. 
    6363         *  
     
    8585        public Key(Class<T> valueClass, T defValue, String... parts) { 
    8686                this(NaiveImmList.create(parts), valueClass, defValue); 
    8787        } 
    88          
    89          
     88 
     89 
    9090        /** 
    9191         * Retrieves the value class for this <code>Key</code>. 
    9292         *  
     
    114114         *                      The id of this <code>Key</code>. 
    115115         */ 
    116116        public String getId() { 
     117                if (this.parts.size() == 0) { 
     118                        return RootKey.ROOT_ID; 
     119                } 
    117120                if (this.parts.size() == 1) { 
    118121                        return this.parts.get(0); 
    119122                } 
    120                  
     123 
    121124                StringBuilder result = new StringBuilder(); 
    122125                for (String part : getParts()) { 
    123                         if (!part.equals("")) { 
    124                                 result.append(part + Key.SEPARATOR); 
    125                         } 
     126                        result.append(part + Key.SEPARATOR); 
    126127                } 
    127                  
     128 
    128129                result.deleteCharAt(result.length() - 1); 
    129130                return result.toString(); 
    130131        } 
    131132 
     133        private static ImmList<String> filterEmptyStrings(ImmList<String> parts) { 
     134                String elem = ""; 
     135                ImmList<String> res = parts; 
     136                while (res.contains(elem)) { 
     137                        res = res.remove(elem); 
     138                } 
     139                return res; 
     140        } 
     141         
    132142        /** 
    133143         * Retrieves the effective value of this <code>Key</code>. 
    134144         *  
     
    162172        public ImmList<String> getParts() { 
    163173                return this.parts; 
    164174        } 
    165          
     175 
    166176        /** 
    167177         * Extends the key; 
    168178         * If <var>prefix</var> is for example <b>book</b>, 
     
    177187         */ 
    178188        protected abstract Key<T> extend(ImmList<String> prefix); 
    179189 
     190 
     191        // TODO Think if it is not a good idea to make the hash code and equals methods 
     192        // consistent in ImmLists used for key parts. 
    180193        @Override 
    181194        public int hashCode() { 
    182                 return getId() == null ? 0 : getId().hashCode(); 
     195                int hashCode = 0; 
     196                for (String part : getParts()) { 
     197                        hashCode += part.hashCode(); 
     198                } 
     199                return hashCode; 
    183200        } 
    184201 
    185202        @Override 
    186203        public boolean equals(Object obj) { 
    187204                if(obj instanceof Key<?>) { 
    188                         String otherKeyId = ((Key<?>)obj).getId(); 
    189                         return getId() == null ?  otherKeyId == null :  
    190                                                                         getId().equals(otherKeyId); 
     205                        ImmList<String> otherKeyParts = ((Key<?>)obj).getParts(); 
     206                        if (getParts().size() !=  otherKeyParts.size()) { 
     207                                if (getParts().contains("") || otherKeyParts.contains("")) { 
     208                                        System.out.println(); 
     209                                } 
     210                                return false; 
     211                        } 
     212                        for (int i = 0; i < getParts().size(); i++) { 
     213                                if (!getParts().get(i).equals(otherKeyParts.get(i))) { 
     214                                        return false; 
     215                                } 
     216                        } 
     217                        return true; 
    191218                } 
    192219                return false; 
    193220        } 
     221         
    194222        @Override 
    195223        public String toString() { 
    196224                return String.format("[%s]", RootKey.ROOT_ID_PARTS.equals(getParts()) ? "ROOT" : getId()); 
    197225        } 
    198          
     226 
    199227        /** 
    200228         * Persist the value of some keys to and from an given {@link ValueRef}.  
    201229         *  
  • src/main/java/org/sophie2/main/func/text/chaining/TextChainHaloButton.java

    #P org.sophie2.main.func.text
     
    44import org.sophie2.base.commons.skin.IconsSet; 
    55import org.sophie2.base.commons.util.ImageUtil; 
    66import org.sophie2.base.halos.HudHaloButton; 
     7import org.sophie2.base.model.book.BookH; 
    78import org.sophie2.base.skins.SkinElementId; 
    89import org.sophie2.base.visual.skins.ElementSkinPart; 
    910import org.sophie2.base.visual.skins.RelatedChildren; 
    1011import org.sophie2.base.visual.skins.SkinPartDef; 
    1112import org.sophie2.base.visual.skins.VisualElementDef; 
    12 import org.sophie2.main.app.commons.book.BookView; 
    1313import org.sophie2.main.app.commons.page.PageWorkArea; 
    1414import org.sophie2.main.app.halos.common.AppHaloUtil; 
    1515import org.sophie2.main.func.text.model.HeadTextFrameH; 
     
    5050                        return false; 
    5151                } 
    5252 
    53                 BookView bookView = workArea.bookView().get(); 
     53                BookH bookH = workArea.bookView().get().model().get(); 
    5454                TextFrameH selectedModel = selectedView.model().get(); 
    55                 HeadTextFrameH headHelper = selectedModel.getHeadHelper(bookView); 
     55                HeadTextFrameH headHelper = selectedModel.getHeadHelper(bookH); 
    5656 
    57                 int chainIndex = selectedModel.getChainIndex(bookView); 
    58                 int chainLength = headHelper.getChainedFrames(bookView).size(); 
     57                int chainIndex = selectedModel.getChainIndex(bookH); 
     58                int chainLength = headHelper.getChainedFrames(bookH).size(); 
    5959 
    6060                return chainIndex == chainLength; 
    6161        } 
  • src/main/java/org/sophie2/main/func/text/model/TailTextFrameH.java

     
    33import java.util.Comparator; 
    44import java.util.List; 
    55 
     6import org.sophie2.base.model.book.BookH; 
    67import org.sophie2.base.model.resources.r4.ResourceRefR4; 
    78import org.sophie2.base.model.resources.r4.access.ResourceAccess; 
    89import org.sophie2.base.model.resources.r4.resources.ResourceH; 
    9 import org.sophie2.main.app.commons.book.BookView; 
     10import org.sophie2.main.func.text.view.ChainMaster; 
    1011 
    1112/** 
    1213 * A helper class for working with {@link TailTextFrameR4}s. 
     
    5051        } 
    5152         
    5253        @Override 
    53         public HeadTextFrameH getHeadHelper(BookView bookView) { 
    54                 assert bookView != null : "Cannot get the head helper in a null bookView."; 
     54        public HeadTextFrameH getHeadHelper(BookH bookH) { 
     55                assert bookH != null : "Cannot get the head helper from a null book."; 
    5556 
    5657                ResourceAccess headAccess =  
    57                         bookView.getAccess().open(getHeadReference(bookView.getAccess().getRef()), null); 
     58                        bookH.getAccess().open(getHeadReference(bookH.getAccess().getRef()), null); 
    5859         
    5960                return ResourceH.getHelper(headAccess, HeadTextFrameH.class); 
    6061        } 
    6162         
    6263        @Override 
    63         public int getChainIndex(BookView bookView) { 
    64                 assert bookView != null : "Cannot get the chained index in a null bookView.";    
     64        public int getChainIndex(BookH bookH) { 
     65                assert bookH != null : "Cannot get the chained index in a null book.";   
    6566                 
    66                 HeadTextFrameH headFrame = getHeadHelper(bookView);              
    67                 List<TailTextFrameH> chainedFrames = headFrame.getChainedFrames(bookView); 
     67                HeadTextFrameH headFrame = getHeadHelper(bookH);                 
     68                List<TailTextFrameH> chainedFrames =  
     69                        ChainMaster.getChainedFrames(bookH, headFrame.getRef()); 
    6870                int res = chainedFrames.indexOf(this); 
    6971                if (res == -1) { 
    7072                        res = chainedFrames.size(); 
  • src/main/java/org/sophie2/main/func/text/chaining/TextChainingLogic.java

     
    1010import org.sophie2.base.commons.util.ImmMap; 
    1111import org.sophie2.base.commons.util.ImmMap.ImmEntry; 
    1212import org.sophie2.base.halos.HaloButton; 
     13import org.sophie2.base.model.book.BookH; 
    1314import org.sophie2.base.model.book.interfaces.ResourceFrame; 
    1415import org.sophie2.base.model.resources.r4.ResourceRefList; 
    1516import org.sophie2.base.model.resources.r4.ResourceRefR4; 
     
    3940import org.sophie2.main.func.text.model.TextFrameH; 
    4041import org.sophie2.main.func.text.model.TextTemplateR4; 
    4142import org.sophie2.main.func.text.utils.TextChainUtils; 
     43import org.sophie2.main.func.text.view.ChainMaster; 
    4244import org.sophie2.main.func.text.view.HeadTextFrameView; 
    4345import org.sophie2.main.func.text.view.TailTextFrameView; 
    4446import org.sophie2.main.func.text.view.TextFrameView; 
     
    7072                                        BoundControl.EventIds.INPUT_PARAM_INDEX, ComboInput.class); 
    7173                        TextFrameView selFrameView = AppHaloUtil.getSingleSelected(source, TextFrameView.class); 
    7274                        BookView bookView = selFrameView.getBookView(); 
    73                         HeadTextFrameH headH = selFrameView.model().get().getHeadHelper(bookView); 
     75                        HeadTextFrameH headH = selFrameView.model().get().getHeadHelper(bookView.model().get()); 
    7476 
    7577                        boolean res; 
    7678                        ChainHudElement element = input.getSelectedItem(); 
     
    119121                        filter.setSourceClass(TextUnchainNextHaloButton.class); 
    120122                        filter.setEventId(HaloButton.EventIds.HALO_CLICK); 
    121123                } 
    122  
     124                 
     125                @SuppressWarnings("synthetic-access") 
    123126                public boolean handle(EventR3 event) { 
    124127                        TextUnchainNextHaloButton source = event.getSource(TextUnchainNextHaloButton.class); 
    125128                        TextFrameView selFrameView = AppHaloUtil.getSingleSelected(source, TextFrameView.class); 
    126129 
    127130                        assert selFrameView != null: "The halo button should be of a textFrameView"; 
    128131                        boolean beforeThisFrame = true; 
    129                         splitChain(selFrameView, beforeThisFrame, false, true); 
     132                        splitChainOnly(selFrameView, beforeThisFrame, false, true); 
    130133                        return true; 
    131134                } 
    132135 
     
    142145                        filter.setSourceClass(TextUnchainPrevHaloButton.class); 
    143146                        filter.setEventId(HaloButton.EventIds.HALO_CLICK); 
    144147                } 
    145  
     148                @SuppressWarnings("synthetic-access") 
    146149                public boolean handle(EventR3 event) { 
    147150                        TextUnchainPrevHaloButton source = event.getSource(TextUnchainPrevHaloButton.class); 
    148151                        TailTextFrameView selFrameView = 
    149152                                AppHaloUtil.getSingleSelected(source, TailTextFrameView.class); 
    150153                        assert selFrameView != null; 
    151154                        boolean beforeThisFrame = false; 
    152                         splitChain(selFrameView, beforeThisFrame, false, true); 
     155 
     156                        splitChainOnly(selFrameView, beforeThisFrame, false, true); 
    153157                        return true; 
    154158                } 
    155159 
     
    169173                 
    170174        } 
    171175 
     176        @SuppressWarnings("synthetic-access") 
    172177        public boolean handle(EventR3 event) { 
    173178                HeadTextFrameView selFrameView = event.getEventParam(BookView.EventIds.VIEW_PARAM_INDEX, 
    174179                                HeadTextFrameView.class); 
    175180                if (selFrameView != null) { 
    176                         splitChain(selFrameView, true, true, false); 
     181                        splitChainOnly(selFrameView, true, true, false); 
    177182                } 
    178183                return false; 
    179184        } 
    180                  
     185 
    181186        }, 
    182187         
    183  
    184188        /** 
    185189         * Handles a user request to delete a page. First checks whether there are 
    186190         * any head text frames on the page and unchains them. This should be 
     
    200204 
    201205                        List<TextFrameView> textViews = pageToRemView.getAll(TextFrameView.class);                       
    202206                        BookView bookView = pageToRemView.getBookView(); 
     207                        BookH bookH = bookView.model().get(); 
    203208                        Map<ResourceRefR4, TextFrameView> toUnchain = new HashMap<ResourceRefR4, TextFrameView>(); 
    204209 
     210                         
    205211                        for (TextFrameView textView:textViews) { 
    206212                                HeadTextFrameView headView = textView.getHeadView(); 
    207213                                if (textViews.contains(headView)) { 
    208214                                        HeadTextFrameH headModel = headView.model().get(); 
    209                                         if (headModel.getChainedFrames(bookView).size() > 0) { 
     215                                        if (headModel.getChainedFrames(bookH).size() > 0) { 
    210216                                                TextFrameView current = toUnchain.get(headModel.getRef()); 
    211217                                                if (TextChainUtils.TEXT_VIEW_COMP.compare(textView, current) > 0) { 
    212218                                                        toUnchain.put(headModel.getRef(), textView); 
     
    214220                                        } 
    215221                                } 
    216222                        } 
     223                        ChainMaster chainMaster = ChainMaster.get(bookH); 
     224                        chainMaster.massCnanging().set(true); 
    217225                        for (TextFrameView textView:toUnchain.values()) { 
    218226                                splitChain(textView, true, true, false); 
    219227                        } 
     228                        chainMaster.massCnanging().set(false); 
    220229 
    221230                        return false; // Should not be handled! Other logics actually delete the page. 
    222231                } 
     
    270279 
    271280                HeadTextFrameH frameToChain = (HeadTextFrameH) textFrameH; 
    272281 
    273                 List<TailTextFrameH> chainedFrames = frameToChain.getChainedFrames(bookView); 
     282                List<TailTextFrameH> chainedFrames = frameToChain.getChainedFrames(bookView.model().get()); 
    274283                ImmMap<ResourceRefR4, String> chainedFramesMap = ImmTreeMap.empty(); 
    275284                for(TailTextFrameH frameH:chainedFrames) { 
    276285                        chainedFramesMap = chainedFramesMap.put(frameH.getRef(), frameH.getChainOrder()); 
     
    308317                ResourceAccess textAccess = bookAccess.open(oldTextRef, null);           
    309318                ImmHotText secondFrameText = HotTextResourceR4.KEY_TEXT.get(textAccess);                 
    310319                if (!secondFrameText.equals(ImmHotText.empty())) { 
    311                         HeadTextFrameH headHelper = prevModel.getHeadHelper(bookView); 
     320                        HeadTextFrameH headHelper = prevModel.getHeadHelper(bookView.model().get()); 
    312321                        final ResourceRefR4 headRef = ResourceRefR4.getRelativeRef(bookRef, headHelper.getRef()); 
    313322                        HotTextResourceH firstFrameTextHelper = headHelper.getTextModel();       
    314323                        ImmHotText firstFrameText = firstFrameTextHelper.getText(); 
     
    357366                }.register(bookAccess); 
    358367        } 
    359368 
     369        // Calls the splitChain method in way that the view properties  
     370        // that depend on text chains will be recomputed only once  
     371        static private void splitChainOnly(TextFrameView frameView, boolean beforeThisFrame,  
     372                        final boolean useSameText, boolean isSign) { 
     373                BookH bookH = frameView.getBookView().model().get(); 
     374                ChainMaster chainMaster = ChainMaster.get(bookH); 
     375                chainMaster.massCnanging().set(true); 
     376                splitChain(frameView, beforeThisFrame, useSameText, isSign); 
     377                chainMaster.massCnanging().set(false); 
     378        } 
     379         
    360380        /** 
    361381         * Helper method used to split the chain of frames from a given frame.  
    362382         *  
     
    380400                TextFrameH selFrameH = frameView.model().get(); 
    381401                ResourceRefList chainedFramesRefs = ResourceRefList.EMPTY; 
    382402                HeadTextFrameH headHelper = frameView.getHeadView().model().get(); 
    383                 List<TailTextFrameH> chainedFrames = headHelper.getChainedFrames(bookView); 
     403                List<TailTextFrameH> chainedFrames =  
     404                        headHelper.getChainedFrames(bookView.model().get()); 
    384405                int thisFrameIndex = -1; 
    385406 
    386407                for (int i = 0; i < chainedFrames.size(); i++) { 
  • src/main/java/org/sophie2/main/func/text/model/TextFrameH.java

     
    11package org.sophie2.main.func.text.model; 
    22 
     3import org.sophie2.base.model.book.BookH; 
    34import org.sophie2.base.model.book.FrameH; 
    45import org.sophie2.base.model.resources.r4.ResourceRefR4; 
    56import org.sophie2.base.model.resources.r4.access.ResourceAccess; 
    6 import org.sophie2.main.app.commons.book.BookView; 
    77 
    88/** 
    99 * A helper class for working with text frames. Provides common methods for 
     
    3636        /** 
    3737         * Gets the helper for the head of the chain this frame is in. 
    3838         *  
    39          * @param bookView 
    40          *            The parent of the view associated with this model. 
     39         * @param bookH 
     40         *          The parent book of this frame. 
     41         *           
    4142         * @return The head text frame helper. 
    4243         */ 
    43         public abstract HeadTextFrameH getHeadHelper(BookView bookView); 
     44        public abstract HeadTextFrameH getHeadHelper(BookH bookH); 
    4445 
    4546        /** 
    4647         * Gets the effective index of this frame in the chain. It is not 
    4748         * necessarily the index of the frame in 
    48          * {@link HeadTextFrameH#getChainedFrames(BookView)}. 
     49         * {@link HeadTextFrameH#getChainedFrames(BookH)}. 
    4950         *  
    50          * @param bookView 
    51          *          The parent of the view associated with this model. 
     51         * @param bookH 
     52         *          The parent book of this frame. 
    5253         * @return  
    5354         *                      The index of the frame in the chain. 
    5455         */ 
    55         public abstract int getChainIndex(BookView bookView); 
     56        public abstract int getChainIndex(BookH bookH); 
    5657} 
  • src/main/java/org/sophie2/main/func/text/view/TailTextFrameView.java

     
    124124                                        @Override 
    125125                                        public Integer getIndex() { 
    126126                                                if (getBookView() != null) { 
    127                                                         return model().get().getChainIndex(getBookView()); 
     127                                                        return model().get().getChainIndex(getBookView().model().get()); 
    128128                                                } 
    129129                                                return 1; 
    130130                                        } 
  • src/main/java/org/sophie2/main/func/text/utils/TextStyleUtils.java

     
    11package org.sophie2.main.func.text.utils; 
    22 
    33 
     4import org.sophie2.base.model.book.BookH; 
    45import org.sophie2.base.model.text.HotAttr; 
    56import org.sophie2.base.model.text.mvc.TextView; 
    67import org.sophie2.base.model.text.mvc.TextViewFlow; 
     
    9596                                TextViewFlow flow = contentView.textFlow().get(); 
    9697                                HotPos caretPos = flow.caretPos().get(); 
    9798                HotPos markPos = flow.markPos().get(); 
    98                 ImmHotText text = contentView.model().get().getHeadHelper(contentView.getBookView()) 
     99                BookH book = contentView.getBookView().model().get(); 
     100                ImmHotText text = contentView.model().get().getHeadHelper(book) 
    99101                        .getTextModel().getText(); 
    100102                         
    101103                                return text.getStyleValue(attribute, new HotInterval(caretPos, markPos)); 
  • src/main/java/org/sophie2/main/func/text/model/HeadTextFrameH.java

     
    11package org.sophie2.main.func.text.model; 
    22 
    33import java.net.URI; 
    4 import java.util.Collections; 
    5 import java.util.LinkedList; 
    64import java.util.List; 
    75 
    86import org.sophie2.base.commons.util.ImmList; 
     
    2523import org.sophie2.base.model.resources.r4.keys.TemplatedKey.Mode; 
    2624import org.sophie2.base.model.resources.r4.resources.ResourceH; 
    2725import org.sophie2.base.model.text.smart.ImmHotText; 
    28 import org.sophie2.main.app.commons.book.BookView; 
    29 import org.sophie2.main.app.commons.page.RootPageView; 
    3026import org.sophie2.main.func.text.chaining.ChainingMode; 
    31 import org.sophie2.main.func.text.view.TailTextFrameView; 
     27import org.sophie2.main.func.text.view.ChainMaster; 
    3228 
    3329/** 
    3430 * A helper class for working with {@link HeadTextFrameR4}s. 
     
    8581        } 
    8682 
    8783        @Override 
    88         public HeadTextFrameH getHeadHelper(BookView bookView) { 
     84        public HeadTextFrameH getHeadHelper(BookH bookH) { 
    8985                return this; 
    9086        } 
    9187 
    9288        @Override 
    93         public int getChainIndex(BookView bookView) { 
     89        public int getChainIndex(BookH bookH) { 
    9490                return 0; 
    9591        } 
    9692 
     
    9995         * These are the frames the current flow will be displayed in in the order  
    10096         * they should be displayed. 
    10197         *  
    102          * @param bookView 
     98         * @param bookH 
    10399         *            The book view this frame is in. 
    104100         * @return  
    105101         *                        List of the frames in their chain order. 
    106102         */ 
    107         public List<TailTextFrameH> getChainedFrames(final BookView bookView) { 
    108                 assert bookView != null : "Cannot get the chained frames in a null bookView."; 
    109                  
    110                 List<TailTextFrameH> chainedFrames = new LinkedList<TailTextFrameH>(); 
    111                 ResourceRefR4 bookRef = bookView.model().get().getRef(); 
    112                  
    113                 ResourceRefR4 thisRelativeRef = ResourceRefR4.getRelativeRef( 
    114                                 bookRef, getRef()); 
    115                  
    116                 for (ResourceRefR4 pageRef : bookView.model().get().getPages()) { 
    117                         RootPageView pageView = bookView.getPageView(pageRef); 
    118                         for (TailTextFrameView tailFrameView : pageView.getAll(TailTextFrameView.class)) { 
    119                                 TailTextFrameH tailModel = tailFrameView.model().get(); 
    120                                 ResourceRefR4 tailRef = tailModel.getHeadReference(bookRef); 
    121                                 if (thisRelativeRef.equals(tailRef)) { 
    122                                         chainedFrames.add(tailModel); 
    123                                 } 
    124                         } 
    125                 } 
    126                 Collections.sort(chainedFrames, TailTextFrameH.CHAIN_ORDER_COMPARARTOR); 
    127                 return chainedFrames; 
     103        public List<TailTextFrameH> getChainedFrames(final BookH bookH) { 
     104                return ChainMaster.getChainedFrames(bookH, getRef()); 
    128105        } 
    129106         
    130107        /** 
  • src/main/java/org/sophie2/main/func/text/utils/TextChainUtils.java

     
    4343import org.sophie2.main.func.text.model.TailTextFrameH; 
    4444import org.sophie2.main.func.text.model.TailTextFrameR4; 
    4545import org.sophie2.main.func.text.model.TextFrameH; 
     46import org.sophie2.main.func.text.view.ChainMaster; 
    4647import org.sophie2.main.func.text.view.HeadTextFrameView; 
    4748import org.sophie2.main.func.text.view.TailTextFrameView; 
    4849import org.sophie2.main.func.text.view.TextFrameView; 
     
    7879                        assert (bookView1 == bookView2) && (view1.getHeadView() == view2.getHeadView()) : 
    7980                                "You can not compare text frame views from different chains"; 
    8081 
    81                         int chainOrder1 = view1.model().get().getChainIndex(bookView1); 
    82                         int chainOrder2 = view2.model().get().getChainIndex(bookView1); 
    83                         if (chainOrder1 < chainOrder2) { 
     82                        if (view1 instanceof HeadTextFrameView) { 
     83                                if (view2 instanceof HeadTextFrameView) { 
     84                                        return 0; 
     85                                } 
    8486                                return -1; 
    85                         } else if (chainOrder1 == chainOrder2) { 
    86                                 return 0; 
    87                         } else { 
     87                        } 
     88                        if (view2 instanceof HeadTextFrameView) { 
    8889                                return 1; 
    8990                        } 
     91 
     92                        TailTextFrameH frame1 = (TailTextFrameH) view1.model().get(); 
     93                        TailTextFrameH frame2 = (TailTextFrameH) view2.model().get(); 
     94 
     95                        return frame1.getChainOrder().compareTo(frame2.getChainOrder()); 
    9096                } 
    9197        }; 
    9298 
     
    108114                } 
    109115                chainedFrameViews.add(headFrameView); 
    110116                Collections.sort(chainedFrameViews, TEXT_VIEW_COMP); 
     117                 
    111118                return chainedFrameViews; 
    112119        } 
    113120 
     
    120127         *                      which flow will be recalculated. 
    121128         */ 
    122129        public static void reflowText(HeadTextFrameView headFrameView) { 
    123                 BookView bookView = headFrameView.getBookView();  
     130                BookView bookView = headFrameView.getBookView(); 
     131                 
    124132                if (bookView == null || bookView.getViewOptions().isPreviewMode()) { 
    125133                        //this happens if the headFrame is no longer part of this bookView 
    126134                        return; 
    127135                } 
    128  
     136                BookH bookH = bookView.model().get(); 
    129137                TextViewFlow flow = headFrameView.textFlow().get(); 
    130                 if (flow.getTextLayout().isLayoutOK(flow.getText())) { 
    131                         return; 
    132                 } 
    133138                 
    134139                //This is done here because we need to know the last frame-view... 
    135140                List<TextFrameView> chainedFrameViews = getChainedFrameViews(bookView, headFrameView); 
     
    141146                        return; 
    142147                } 
    143148                boolean changesMade = true; 
     149                 
     150                ChainMaster chainMaster = ChainMaster.get(bookH); 
     151                chainMaster.massCnanging().set(true); 
    144152                if (neededPages > 0) { 
    145153                        expandChain(chainedFrameViews, neededPages); 
    146154                } else { 
    147155                        changesMade = reduceChain(chainedFrameViews); 
    148156                } 
     157                chainMaster.massCnanging().set(false); 
     158                 
    149159                if (changesMade) { 
    150160                        new AutoAction("Auto-fit text flow.", true) { 
    151161                                @Override 
     
    254264         * @return 
    255265         *                      True if the pages were added and false otherwise. 
    256266         */ 
    257         public static boolean expandChain(List<TextFrameView> chainedTextViews, final int neededPages) { 
     267public static boolean expandChain(List<TextFrameView> chainedTextViews, final int neededPages) { 
     268                 
    258269                TextFrameView lastTextView = chainedTextViews.get(chainedTextViews.size() - 1); 
    259270                RootPageView page = lastTextView.findParentElement(RootPageView.class); 
    260271 
     
    265276                final ResourceRefR4 pageTemplateRef = getPageTemplate(page); 
    266277 
    267278                List<FrameView> frameViews = page.getAll(FrameView.class); 
     279                 
    268280                final ResourceRefList frameTemplatesList = getFrameTemplates(book, frameViews); 
    269281 
    270282                final ImmList<String> kindsList = getFrameKinds(frameViews); 
    271  
     283                 
    272284                Map<ResourceRefR4, List<TextFrameView>> chainsInThisPage =  
    273285                                                                                        getChainsInPage(bookRef, frameViews); 
    274286                final ImmList<String> frameChainOrders =  
    275287                        getChainOrders(bookRef, frameViews, chainedTextViews, chainsInThisPage); 
     288                 
    276289                final ImmList<Integer> frameChainIndexes = getIndexInPage(bookRef, frameViews, chainsInThisPage); 
    277290 
    278291                //Generate page`s and frame`s refs and titles 
     
    312325                new AutoAction("Expand auto-chain", false) { 
    313326                        @Override 
    314327                        public void performAuto() { 
     328                                 
    315329                                int size = frameTemplatesList.size(); 
    316330                                ResourceRefR4 pageRef = pages.get(lastPageIndex); 
    317331                                ResourceRefR4 relPageTemplRef = ResourceRefR4.getRelativeRef(pageRef, pageTemplateRef); 
     
    425439 
    426440                return true; 
    427441        } 
     442 
    428443         
    429444        private static ResourceRefList getFramesRefs(RootPageView page) { 
    430445                List<FrameView> frameViews = page.getAll(FrameView.class); 
     
    604619        private static String getNextOrderInChain(TextFrameView textView) { 
    605620                BookView bookView = textView.getBookView(); 
    606621                TextFrameH model = textView.model().get(); 
    607                 //XXX getChainedFrames IS SO SLOW... 
    608                 List<TailTextFrameH> wholeChain = model.getHeadHelper(bookView).getChainedFrames(bookView); 
     622                BookH bookH = bookView.model().get(); 
     623                List<TailTextFrameH> wholeChain =  
     624                        ChainMaster.getChainedFrames(bookH, model.getHeadReference(bookH.getRef())); 
    609625                int thisFrameIndex = wholeChain.indexOf(model); 
    610626                if (thisFrameIndex == wholeChain.size()-1){ 
    611627                        return ""; 
     
    691707        } 
    692708 
    693709        private static boolean isEmpty(TailTextFrameView tail) { 
    694                 BookView bookView = tail.getBookView(); 
    695                 int index = tail.model().get().getChainIndex(bookView); 
     710                BookH book = tail.getBookView().model().get(); 
     711                int index = tail.model().get().getChainIndex(book); 
    696712                TextViewFlow flow = tail.textFlow().get(); 
    697713                return (flow.getTextLayout().getAreaContent(index).getLength() == 0); 
    698714        } 
  • src/main/java/org/sophie2/main/func/text/chaining/TextUnchainNextHaloButton.java

     
    44import org.sophie2.base.commons.skin.IconsSet; 
    55import org.sophie2.base.commons.util.ImageUtil; 
    66import org.sophie2.base.halos.ClickHaloButton; 
     7import org.sophie2.base.model.book.BookH; 
    78import org.sophie2.base.skins.SkinElementId; 
    89import org.sophie2.base.visual.skins.ElementSkinPart; 
    910import org.sophie2.base.visual.skins.SkinPartDef; 
    1011import org.sophie2.base.visual.skins.VisualElementDef; 
    11 import org.sophie2.main.app.commons.book.BookView; 
    1212import org.sophie2.main.app.commons.page.PageWorkArea; 
    1313import org.sophie2.main.app.halos.common.AppHaloUtil; 
    1414import org.sophie2.main.func.text.model.HeadTextFrameH; 
     
    4747                        return false; 
    4848                } 
    4949 
    50                 BookView bookView = workArea.bookView().get(); 
     50                BookH bookH = workArea.bookView().get().model().get(); 
    5151                TextFrameH selectedModel = selectedView.model().get(); 
    52                 HeadTextFrameH headHelper = selectedModel.getHeadHelper(bookView); 
     52                HeadTextFrameH headHelper = selectedModel.getHeadHelper(bookH); 
    5353 
    54                 int chainIndex = selectedModel.getChainIndex(bookView); 
    55                 int chainLength = headHelper.getChainedFrames(bookView).size(); 
     54                int chainIndex = selectedModel.getChainIndex(bookH); 
     55                int chainLength = headHelper.getChainedFrames(bookH).size(); 
    5656 
    5757                return chainIndex < chainLength; 
    5858        } 
  • src/main/java/org/sophie2/main/func/text/view/ChainMaster.java

     
     1package org.sophie2.main.func.text.view; 
     2 
     3import java.util.ArrayList; 
     4import java.util.HashMap; 
     5import java.util.List; 
     6import java.util.Map; 
     7 
     8import org.sophie2.base.commons.structures.ImmTreeList; 
     9import org.sophie2.base.commons.structures.ImmTreeMap; 
     10import org.sophie2.base.commons.util.ImmList; 
     11import org.sophie2.base.commons.util.ImmMap; 
     12import org.sophie2.base.model.book.BookH; 
     13import org.sophie2.base.model.book.PageH; 
     14import org.sophie2.base.model.resources.r4.ResourceRefR4; 
     15import org.sophie2.base.model.resources.r4.resources.ResourceH; 
     16import org.sophie2.core.prolib.annot.Immutable; 
     17import org.sophie2.core.prolib.impl.AutoProperty; 
     18import org.sophie2.core.prolib.impl.BaseProObject; 
     19import org.sophie2.core.prolib.interfaces.Prop; 
     20import org.sophie2.core.prolib.interfaces.RwProp; 
     21import org.sophie2.main.func.text.model.HeadTextFrameH; 
     22import org.sophie2.main.func.text.model.TailTextFrameH; 
     23 
     24/** 
     25 * Class that keeps lists of all chains in all books opened in the application. 
     26 *  
     27 * @author mira 
     28 */ 
     29public class ChainMaster extends BaseProObject { 
     30 
     31        private static Map<BookH, ChainMaster> chainMasters = new HashMap<BookH, ChainMaster>(); 
     32 
     33        /** 
     34         * Gets the ChainMaster responsible for a given BookH. If there is no such, a new one is  
     35         * created and added. 
     36         *  
     37         * @param bookH 
     38         *                      The book whose ChainMaster is wanted. 
     39         * @return 
     40         *                      The ChainMaster of a book. 
     41         */ 
     42        public static ChainMaster get(BookH bookH) { 
     43                if(!chainMasters.containsKey(bookH)) { 
     44                        chainMasters.put(bookH, new ChainMaster(bookH)); 
     45                } 
     46                return chainMasters.get(bookH); 
     47        } 
     48 
     49        private final BookH bookH; 
     50 
     51        private ChainMaster(BookH bookH){ 
     52                this.bookH = bookH; 
     53        } 
     54 
     55        /** 
     56         * Flag that indicates that the model is being mass-changed and there is no need 
     57         * to recompute the chain info of this book. Remember to always set this back 
     58         * to false after the mass-changes are done.   
     59         *  
     60         * @return 
     61         *                      The Property. 
     62         */ 
     63        public RwProp<Boolean> massCnanging() { 
     64                return getBean().makeValueProp("massCnanging", Boolean.class, false); 
     65        } 
     66         
     67        /** 
     68         * Property that keeps the last value of chainInfo property. It is used  
     69         * instead of when there are mass changes.  
     70         *  
     71         * @return 
     72         *                      The Property. 
     73         */ 
     74        public RwProp<ChainInfo> oldValue() { 
     75                return getBean().makeValueProp("oldValue", ChainInfo.class, ChainInfo.INITIAL); 
     76        } 
     77         
     78        /** 
     79         * Property that keeps accurate information about all chained frames in a book. 
     80         *  
     81         * @return 
     82         *                      The Property. 
     83         */ 
     84        public Prop<ChainInfo> chainInfo() { 
     85                class chainInfo extends AutoProperty<ChainInfo> { 
     86 
     87                        @SuppressWarnings("synthetic-access") 
     88                        @Override 
     89                        protected ChainInfo compute() { 
     90                                if (massCnanging().get()) { 
     91                                        return oldValue().get(); 
     92                                } 
     93                                 
     94                                assert (ChainMaster.this.bookH != null) :  
     95                                        "Cannot get the chained frames in a null book."; 
     96 
     97                                ImmMap<ResourceRefR4, ImmList<TailTextFrameH>> chainsMap =  
     98                                        ImmTreeMap.<ResourceRefR4, ImmList<TailTextFrameH>>empty(); 
     99 
     100                                for (ResourceRefR4 pageRef : ChainMaster.this.bookH.getPages()) { 
     101 
     102                                        PageH pageH = ResourceH.getHelper(ChainMaster.this.bookH.getAccess().open(pageRef, null), PageH.class); 
     103                                        List<TailTextFrameH> tailsInPage = pageH.getSubElements(TailTextFrameH.class); 
     104                                        for (TailTextFrameH tailFrameH : tailsInPage) { 
     105                                                ResourceRefR4 bookRef = ChainMaster.this.bookH.getRef(); 
     106                                                ResourceRefR4 relHeadRef = tailFrameH.getHeadReference(bookRef); 
     107                                                ResourceRefR4 headRef = bookRef.append(relHeadRef); 
     108                                                ImmList<TailTextFrameH> chain;  
     109 
     110                                                if (chainsMap.contains(headRef)) { 
     111                                                        chain = chainsMap.get(headRef); 
     112                                                        chainsMap = chainsMap.remove(headRef); 
     113                                                        int index = findIndexFor(chain, tailFrameH); 
     114                                                        chain = chain.add(index, tailFrameH); 
     115                                                } else { 
     116                                                        chain = ImmTreeList.create(tailFrameH); 
     117                                                } 
     118                                                chainsMap = chainsMap.put(headRef, chain); 
     119                                        } 
     120                                } 
     121                                ChainInfo res = new ChainInfo(chainsMap); 
     122                                oldValue().set(res); 
     123                                return res; 
     124                        } 
     125 
     126                        private int findIndexFor(ImmList<TailTextFrameH> chain, 
     127                                        TailTextFrameH tailFrameH) { 
     128                                int i; 
     129                                for (i=0;i<chain.size();i++) { 
     130                                        if (chain.get(i).getChainOrder().compareTo(tailFrameH.getChainOrder()) > 0){ 
     131                                                break; 
     132                                        } 
     133                                } 
     134                                return i; 
     135                        } 
     136 
     137                } 
     138                return getBean().makeProp(chainInfo.class); 
     139        } 
     140 
     141        /** 
     142         * Gets all tail-frames of a given book that are chained to the given head-frame. 
     143         *  
     144         * @param bookH 
     145         *                      The book in which to look or chained frames. 
     146         * @param headFrame 
     147         *                      The head of the chain we look for.  
     148         * @return 
     149         *                      All TailTextFrames in this chain ordered by their chain-order. 
     150         */ 
     151        public static List<TailTextFrameH> getChainedFrames(BookH bookH, ResourceRefR4 headFrame) { 
     152 
     153                ChainInfo info = get(bookH).chainInfo().get(); 
     154                assert info != null; 
     155 
     156                List<TailTextFrameH> res = new ArrayList<TailTextFrameH>(info.getChain(headFrame).asList()); 
     157                //Collections.sort(res, TailTextFrameH.CHAIN_ORDER_COMPARARTOR); 
     158 
     159                return res; 
     160        } 
     161 
     162        /** 
     163         * Immutable class used to wrap an ImmMap of <ResourceRefR4, ImmList<TailTextFrameH>> elements. 
     164         * It is used to keep the all chains in a book. 
     165         * @author mira 
     166         */ 
     167        @Immutable 
     168        static class ChainInfo { 
     169                 
     170                /** 
     171                 * The empty chain info. 
     172                 */ 
     173                public static final ChainInfo INITIAL = new ChainInfo(ImmTreeMap.<ResourceRefR4, ImmList<TailTextFrameH>>empty()); 
     174                private final ImmMap<ResourceRefR4, ImmList<TailTextFrameH>> chains; 
     175 
     176                private ChainInfo(ImmMap<ResourceRefR4, ImmList<TailTextFrameH>> chains) { 
     177                        this.chains = chains; 
     178                } 
     179 
     180                /** 
     181                 * Gets the last computed chain for a given {@link HeadTextFrameH}. 
     182                 *  
     183                 * @param headRef 
     184                 *                      {@link ResourceRefR4} pointing to the head of the desired chain. 
     185                 * @return 
     186                 *                      {@link ImmList} containing the tails of the chain, ordered by chain-order. 
     187                 *                      Null if the head has no tails. 
     188                 */ 
     189                public ImmList<TailTextFrameH> getChain(ResourceRefR4 headRef) { 
     190 
     191                        if (!this.chains.contains(headRef)) { 
     192                                // The head does not have tails, so the chain is empty. 
     193                                return ImmTreeList.<TailTextFrameH>empty(); 
     194                        } 
     195 
     196                        return this.chains.get(headRef); 
     197                } 
     198                 
     199                @Override 
     200                public int hashCode() { 
     201                        final int prime = 31; 
     202                        int result = 1; 
     203                        result = prime * result 
     204                                        + ((this.chains == null) ? 0 : this.chains.hashCode()); 
     205                        return result; 
     206                } 
     207 
     208                @Override 
     209                public boolean equals(Object obj) { 
     210                        if (this == obj) { 
     211                                return true; 
     212                        } 
     213                        if (obj == null) { 
     214                                return false; 
     215                        } 
     216                        if (getClass() != obj.getClass()) { 
     217                                return false; 
     218                        } 
     219                        ChainInfo other = (ChainInfo) obj; 
     220                        if (this.chains == null) { 
     221                                if (other.chains != null) { 
     222                                        return false; 
     223                                } 
     224                        } else if (!this.chains.equals(other.chains)) { 
     225                                return false; 
     226                        } 
     227                        return true; 
     228                } 
     229 
     230        } 
     231} 
     232 No newline at end of file 
  • src/main/java/org/sophie2/main/func/text/view/HeadTextFrameView.java

     
    9898 
    9999                                        @Override 
    100100                                        public Integer getIndex() { 
    101                                                 return model().get().getChainIndex(getBookView()); 
     101                                                return 0; 
     102                                                // TODO HEAD is always first... 
     103                                                // return model().get().getChainIndex(getBookView().model().get()); 
    102104                                        } 
    103105 
    104106                                        @Override 
     
    164166                                                                                                if (bookView == null) { 
    165167                                                                                                        return ImmTreeList.empty(); 
    166168                                                                                                } 
    167                                                                                                 return ImmTreeList.create(model().get().getChainedFrames(bookView)); 
     169                                                                                                return ImmTreeList.create( 
     170                                                                                                                model().get().getChainedFrames(bookView.model().get())); 
    168171                                                                                        } 
    169172                                                                                } 
    170173                                                                                return getBean().makeProp(chainedFrames.class); 
  • src/main/java/org/sophie2/main/func/text/chaining/TextChainHud.java

     
    8282                                textFrames.addAll(availableTextFrames); 
    8383                                BookView bookView = selectedView.getBookView(); 
    8484                                TextFrameH frameH = selectedView.model().get(); 
    85                                 HeadTextFrameH headH = frameH.getHeadHelper(bookView); 
     85                                HeadTextFrameH headH = frameH.getHeadHelper(bookView.model().get()); 
    8686                                if (ChainingMode.AUTO_CHAINING == headH.getChainMode()) { 
    8787                                        selectedElem = ChainHudElement.AUTO_CHAIN_ELEM; 
    8888                                }