Ticket #2269: 2269.patch

File 2269.patch, 25.8 KB (added by diana, 15 years ago)
  • modules/org.sophie2.base.model.text/src/main/java/org/sophie2/base/model/text/smart/ImmHotText.java

    ### Eclipse Workspace Patch 1.0
    #P sophie
     
    3232 */ 
    3333@Immutable(kind="hot-text") 
    3434public final class ImmHotText { 
    35          
     35 
    3636        private static long ID_BASE = 1000000; 
    3737        private ImmList<Character> chars; 
    3838        private final long uid; 
    3939        private final ImmHotText prevText; 
    4040        private final ElemOp lastOperation; 
    41     private final HotIndexInterval subSingleInterval;  
    42     private final HotInterval lastChangedInterval; 
    43          
     41        private final HotIndexInterval subSingleInterval;  
     42        private final HotInterval lastChangedInterval; 
     43 
    4444        private ImmMap<HotAttr<?>, StyleValueSet<?>> styleValues = new ImmTreeMap<HotAttr<?>, StyleValueSet<?>>( 
    4545                        new ImmHashingTree<ImmEntry<HotAttr<?>, StyleValueSet<?>>>(), getAttrComparator()); 
    4646 
    4747        private ImmMap<HotInterval, Attachment> attachments = new ImmTreeMap<HotInterval, Attachment>( 
    4848                        new ImmHashingTree<ImmEntry<HotInterval, Attachment>>(), getIntervalComparator()); 
    49          
     49 
    5050        // Caching 
    5151        private Hash styledHash = null; 
    5252        private AttributedString attrString = null; 
    53          
     53 
    5454        // Constructors. For internal use only. 
    5555        // Factory methods should be used for creation of text  
    5656        // from the client code 
    5757        private ImmHotText(ImmList<Character> text, ImmMap<HotAttr<?>, StyleValueSet<?>> styleValues, ImmHotText prev, ElemOp lastOp, 
    5858                        HotIndexInterval subSingleInterval, ImmMap<HotInterval, Attachment> attachments, AttributedString attrString) { 
    5959                this(text, styleValues, prev, lastOp, subSingleInterval, attachments, null, attrString); 
    60                  
     60 
    6161        } 
    62          
     62 
    6363        private ImmHotText(ImmList<Character> text, ImmMap<HotAttr<?>, StyleValueSet<?>> styleValues, ImmHotText prev, ElemOp lastOp, 
    6464                        HotIndexInterval subSingleInterval, ImmMap<HotInterval, Attachment> attachments, HotInterval lastChangedInterval, AttributedString attrString) { 
    6565                this(text, styleValues, prev, lastOp, subSingleInterval, generateId(), lastChangedInterval, attachments, attrString); 
    6666        } 
    67          
    68          
     67 
     68 
    6969        private ImmHotText(ImmList<Character> text, ImmMap<HotAttr<?>, StyleValueSet<?>> styleValues, ImmHotText prev, ElemOp lastOp, 
    7070                        HotIndexInterval subSingleInterval, long uid, HotInterval lastChangedInterval, ImmMap<HotInterval, Attachment> attachments, AttributedString attrString) { 
    7171                this.chars = text; 
     
    7373                if (uid > ID_BASE) { 
    7474                        ID_BASE = uid; 
    7575                } 
    76                  
     76 
    7777                this.prevText = prev; 
    7878                this.lastOperation = lastOp; 
    79         this.subSingleInterval = subSingleInterval; 
    80         this.lastChangedInterval = (lastChangedInterval == null) ? null :  
    81                         new HotInterval(lastChangedInterval.getBegin().normalize(this), 
    82                                 lastChangedInterval.getEnd().normalize(this)); 
     79                this.subSingleInterval = subSingleInterval; 
     80                this.lastChangedInterval = (lastChangedInterval == null) ? null :  
     81                        new HotInterval(lastChangedInterval.getBegin().normalize(this), 
     82                                        lastChangedInterval.getEnd().normalize(this)); 
    8383                if (styleValues != null) { 
    8484                        this.styleValues = styleValues; 
    8585                } 
    8686                if (attachments != null) { 
    8787                        this.attachments = attachments; 
    8888                } 
    89                  
     89 
    9090                // This should be performance effective. 
    9191                if (attrString != null) { 
    9292                        this.attrString = attrString; 
     
    9999        @SuppressWarnings("unchecked") 
    100100        private ImmHotText(String text, HotStyleDef style) { 
    101101                assert text != null : "Text must be not null."; 
    102                  
     102 
    103103                this.chars = new ImmTreeList<Character>(new ImmHashingTree<Character>()); 
    104                  
     104 
    105105                for (char ch : text.toCharArray()) { 
    106106                        this.chars = this.chars.add(this.chars.size(), ch); 
    107107                } 
    108108                this.subSingleInterval = new HotIndexInterval(0 , this.chars.size()); 
    109         this.lastChangedInterval = null; 
     109                this.lastChangedInterval = null; 
    110110                this.uid = generateId(); 
    111111 
    112112                if (style != null) { 
    113113                        for (HotAttr<?> key : style.getAttributeKeys()) { 
    114114                                StyleValueSet<Object> valueSet = (StyleValueSet<Object>) 
    115                                                 StyleValueSet.create(key, getPosComparator()); 
     115                                StyleValueSet.create(key, getPosComparator()); 
    116116                                valueSet = valueSet.setValue( 
    117117                                                changePosKind(getBegin(), HotPosKind.AFTER),  
    118118                                                changePosKind(getEnd(), HotPosKind.BEFORE),  
     
    124124 
    125125                this.prevText = null; 
    126126                this.lastOperation = null; 
    127                  
     127 
    128128                // If you remove this line, every sub-text of this one will generate its own AttributedString..  
    129129                // this is a slow operation on large texts. 
    130130                this.attrString = StyleUtils.getAttributedString( 
     
    137137        } 
    138138 
    139139        // Factory methods for creation of ImmHotText. 
    140          
     140 
    141141        /** 
    142142         * Factory method for creation of a styled text. 
    143143         *  
     
    167167        public static ImmHotText empty() { 
    168168                return new ImmHotText("", null); 
    169169        } 
    170          
     170 
    171171        /** 
    172172         * Factory method for creation of text by its internals. 
    173173         * Needed by persistence. 
     
    190190        } 
    191191 
    192192        // Edition operations 
    193          
     193 
    194194        /** 
    195195         * Applies the specified style to the range of text, defined by 
    196196         * the specified interval of {@link HotPos}es. The new style values 
     
    207207                HotPos begin = orderInterval.getBegin(); 
    208208                HotPos end = orderInterval.getEnd(); 
    209209                begin = begin.equals(end) 
    210                                 ? changePosKind(begin, HotPosKind.AFTER) 
     210                ? changePosKind(begin, HotPosKind.AFTER) 
    211211                                : changePosKind(begin, HotPosKind.BEFORE); 
    212212                end = changePosKind(end, HotPosKind.BEFORE); 
    213                  
     213 
    214214                ImmMap<HotAttr<?>, StyleValueSet<?>> newStyleValues = this.styleValues; 
    215215                for (HotAttr<?> key : style.getAttributeKeys()) { 
    216216                        StyleValueSet<Object> valueSet = (StyleValueSet<Object>) 
    217                                 (newStyleValues.contains(key) ? newStyleValues.get(key) 
    218                                                 : StyleValueSet.create(key, getPosComparator())); 
     217                        (newStyleValues.contains(key) ? newStyleValues.get(key) 
     218                                        : StyleValueSet.create(key, getPosComparator())); 
    219219                        valueSet = valueSet.setValue(begin, end, style.getValue(key)); 
    220220 
    221221                        newStyleValues = newStyleValues.put(key, valueSet); 
     
    224224                // TODO consider re-using the attributed string. 
    225225                return new ImmHotText(this.chars, newStyleValues, this, lastOp, this.subSingleInterval, this.attachments, null); 
    226226        } 
    227          
     227 
    228228        @SuppressWarnings("unchecked") 
    229229        private ImmHotText applyStyles(ImmHotText insertText, HotPos beginPos) { 
    230230                int beginIndex = getIndex(beginPos) + HotPosKind.getRelativeIndex(this.subSingleInterval.getBegin()); 
     
    233233                for (ImmEntry<HotAttr<?>, StyleValueSet<?>> entry : insertText.getStyleValues()) { 
    234234                        HotAttr<?> key = entry.getKey(); 
    235235                        StyleValueSet<Object> valueSet = (StyleValueSet<Object>) 
    236                                 insertText.getStyleValues().get(key); 
     236                        insertText.getStyleValues().get(key); 
    237237                        StyleValueSet<Object> newValueSet = this.styleValues.contains(key) 
    238                                         ? StyleValueSet.create((HotAttr)key, getPosComparator(),  
    239                                                 this.styleValues.get(key).getValueSet())  
     238                        ? StyleValueSet.create((HotAttr)key, getPosComparator(),  
     239                                        this.styleValues.get(key).getValueSet())  
    240240                                        : (StyleValueSet<Object>)StyleValueSet.create(key, getPosComparator()); 
    241241 
    242242                        HotPos prevPos = null; 
     
    247247                                        continue; 
    248248                                } 
    249249                                int intervalStart = HotPosKind.getIndexForKind(beginIndex, prevPos.getKind()) +  
    250                                                         insertText.getIndex(prevPos) - insertText.getIndex( 
    251                                                         changePosKind(insertText.getBegin(), prevPos.getKind())); 
     250                                insertText.getIndex(prevPos) - insertText.getIndex( 
     251                                                changePosKind(insertText.getBegin(), prevPos.getKind())); 
    252252                                int intervalEnd = HotPosKind.getIndexForKind(beginIndex, pos.getKind()) +  
    253                                                         insertText.getIndex(pos) - insertText.getIndex( 
    254                                                         changePosKind(insertText.getBegin(), pos.getKind())); 
     253                                insertText.getIndex(pos) - insertText.getIndex( 
     254                                                changePosKind(insertText.getBegin(), pos.getKind())); 
    255255 
    256256                                Object value = valueSet.getValue(prevPos); 
    257257                                newValueSet = newValueSet.setValue(getPos(intervalStart), getPos(intervalEnd), value); 
    258258                                prevPos = pos; 
    259259                        } 
    260                          
     260 
    261261                        newStyleValues = newStyleValues.put(key, newValueSet); 
    262262                } 
    263                  
     263 
    264264                return new ImmHotText(this.chars, newStyleValues, this.prevText, this.lastOperation, 
    265265                                this.subSingleInterval, this.uid, null, this.attachments, null); 
    266266        } 
     
    274274         * @param insertText The new styled text that should be inserted. 
    275275         * @return A new text with replaced text range. 
    276276         */ 
     277        @SuppressWarnings("unchecked") 
    277278        public ImmHotText replace(HotInterval interval, ImmHotText insertText) { 
    278279                int beginIndex = getIndex(interval.getBegin()); 
    279280                int endIndex = getIndex(interval.getEnd()); 
    280281 
     282                ImmMap<HotAttr<?>, StyleValueSet<?>> newInsStyleValues = insertText.getStyleValues(); 
     283                //-------------------- 
     284                if(getPosComparator().compare(interval.getBegin(), interval.getEnd()) != 0) { 
     285                        for (ImmEntry<HotAttr<?>, StyleValueSet<?>> entry : this.styleValues) { 
     286                                HotAttr<?> key = entry.getKey(); 
     287                                StyleValueSet<Object> valueSet = (StyleValueSet<Object>) 
     288                                this.styleValues.get(key); 
     289                                StyleValueSet<Object> newValueSet = insertText.getStyleValues().contains(key) 
     290                                ? StyleValueSet.create((HotAttr)key, getPosComparator(),  
     291                                                insertText.getStyleValues().get(key).getValueSet())  
     292                                                : (StyleValueSet<Object>)StyleValueSet.create(key, getPosComparator()); 
     293 
     294                                HotPos prevPos = null; 
     295                                for (HotStyleValue<Object> styleValue : valueSet.getValueSet()) { 
     296                                        HotPos pos = styleValue.getPos(); 
     297                                        if (prevPos == null) { 
     298                                                prevPos = pos; 
     299                                                continue; 
     300                                        } 
     301 
     302                                        HotInterval newInterval = new HotInterval(interval.getBegin(),  
     303                                                        advance(interval.getBegin(), 1)); 
     304                                        if(getPosComparator().compare(interval.getBegin(), interval.getEnd()) > 0) { 
     305                                                newInterval = new HotInterval(interval.getEnd(),  
     306                                                                advance(interval.getEnd(), 1)); 
     307                                        }  
     308                                        Object value = this.getStyleValue(key, newInterval); 
     309                                        int intervalStart = HotPosKind.getIndexForKind(insertText.subSingleInterval.getBegin(), prevPos.getKind()); 
     310                                        int intervalEnd = HotPosKind.getIndexForKind(insertText.subSingleInterval.getEnd(), pos.getKind()); 
     311                                        if(intervalStart > intervalEnd) { 
     312                                                int temp = intervalEnd; 
     313                                                intervalEnd = intervalStart; 
     314                                                intervalStart = temp; 
     315                                        } 
     316                                        newValueSet = newValueSet.setValue(insertText.getPos(intervalStart), insertText.getPos(intervalEnd), value); 
     317                                        prevPos = pos; 
     318                                } 
     319 
     320                                newInsStyleValues = newInsStyleValues.put(key, newValueSet); 
     321                        } 
     322                } 
     323                //-------------------- 
     324 
    281325                // new text 
    282326                ImmList<Character> newText = this.chars; 
    283327                int index = HotPosKind.getRealIndex(getIndex(interval.getBegin())); 
    284                  
     328 
    285329                int i = index; 
    286330                for (; i < Math.min( 
    287331                                HotPosKind.getRealIndex(endIndex), getLength()); ++i) { 
     
    298342                        elemOp = new ElemOp.DeleteOp(beginIndex, endIndex); 
    299343                } 
    300344                int insertLength = HotPosKind.getRelativeIndex(insertText.getLength()); 
    301                  
     345 
    302346                if (insertLength > 0) { 
    303347                        ElemOp.InsertOp insOp = new ElemOp.InsertOp(beginIndex, insertLength); 
    304348                        if (elemOp == null) { 
     
    307351                                elemOp = new ElemOp.ReplaceOp((ElemOp.DeleteOp)elemOp, insOp); 
    308352                        } 
    309353                } 
    310                  
     354 
    311355                if (elemOp == null) { 
    312356                        elemOp = new ElemOp.NoOp(endIndex, endIndex); 
    313357                } 
     
    315359                HotIndexInterval newSingleInterval = new HotIndexInterval( 
    316360                                this.subSingleInterval.getBegin(), this.subSingleInterval.getEnd()  
    317361                                + insertText.getLength() - length); 
    318                  
    319362                ImmHotText newHotText = new ImmHotText(newText, this.styleValues, this, elemOp,newSingleInterval, this.attachments, null); 
    320                  
    321                 return newHotText.applyStyles(insertText, interval.getBegin()); 
     363 
     364                ElemOp lastInsOp = new ElemOp.NoOp(getIndex(interval.getBegin()), getIndex(interval.getEnd())); 
     365                ImmHotText newInsHotText = new ImmHotText(insertText.chars, newInsStyleValues, insertText, lastInsOp, 
     366                                insertText.subSingleInterval, insertText.attachments, null); 
     367                return newHotText.applyStyles(newInsHotText, interval.getBegin()); 
    322368        } 
    323369 
    324370        /** 
     
    328374         * @return A new styled text, that is a sub text of the current one. 
    329375         */ 
    330376        public ImmHotText subText(HotInterval interval) { 
    331         HotIndexInterval newSingleInterval = new HotIndexInterval( 
    332                         HotPosKind.getRealIndex(getIndex(interval.getBegin())), 
    333                         HotPosKind.getRealIndex(getIndex(interval.getEnd()))); 
     377                HotIndexInterval newSingleInterval = new HotIndexInterval( 
     378                                HotPosKind.getRealIndex(getIndex(interval.getBegin())), 
     379                                HotPosKind.getRealIndex(getIndex(interval.getEnd()))); 
    334380                return new ImmHotText(this.chars, this.styleValues, this.prevText,  
    335381                                this.lastOperation, newSingleInterval, this.uid,  
    336382                                this.lastChangedInterval, this.attachments, this.attrString); 
     
    352398 
    353399                // last operation 
    354400                ElemOp elemOp = new ElemOp.InsertOp(beginIndex, HotPosKind.getRelativeIndex(1)); 
    355         HotIndexInterval newInterval = new HotIndexInterval(this.subSingleInterval.getBegin(),this.subSingleInterval.getEnd() + 1); 
     401                HotIndexInterval newInterval = new HotIndexInterval(this.subSingleInterval.getBegin(),this.subSingleInterval.getEnd() + 1); 
    356402                ImmHotText newHotText = new ImmHotText(newText, this.styleValues, this, elemOp, newInterval, this.attachments, null); 
    357403                return newHotText.applyStyles(ImmHotText.createPlain(String.valueOf(ch)), pos); 
    358404        } 
     
    361407                return this.chars.subList(this.subSingleInterval.getBegin(), 
    362408                                this.subSingleInterval.getEnd()); 
    363409        } 
    364          
     410 
    365411        // Getters and conversion operations. 
    366          
     412 
    367413        /** 
    368414         * Retrieves the number of characters of the current text. 
    369415         *  
     
    371417         */ 
    372418        public int getLength() { 
    373419                return this.subSingleInterval.getEnd() 
    374                                 - this.subSingleInterval.getBegin(); 
     420                - this.subSingleInterval.getBegin(); 
    375421        } 
    376          
     422 
    377423        /** 
    378424         * Retrieves the style value of the specified attribute at the 
    379425         * given {@link HotInterval} of the current text. If the whole interval 
     
    390436        public <T> T getStyleValue(HotAttr<T> attribute, HotInterval interval) { 
    391437                if (this.styleValues.contains(attribute)) { 
    392438                        StyleValueSet<T> valueMap = (StyleValueSet<T>) 
    393                                         this.styleValues.get(attribute); 
    394                          
     439                        this.styleValues.get(attribute); 
     440 
    395441                        HotInterval orderedInterval = IntervalUtility.orderAscending( 
    396442                                        interval, getPosComparator()); 
    397443                        HotPos begin = orderedInterval.getBegin(); 
    398444                        HotPos end = orderedInterval.getEnd(); 
    399445                        begin = begin.equals(end) 
    400                                         ? changePosKind(begin, HotPosKind.AFTER) 
     446                        ? changePosKind(begin, HotPosKind.AFTER) 
    401447                                        : changePosKind(begin, HotPosKind.BEFORE); 
    402448                        end = changePosKind(end, HotPosKind.BEFORE); 
    403                          
     449 
    404450                        HotPos currentPos = changePosKind(begin, HotPosKind.MIDDLE); 
    405451                        T beginValue = valueMap.getValue(begin); 
    406452                        while(getPosComparator().compare(currentPos, orderedInterval.getEnd()) < 0 &&  
     
    411457                                } 
    412458                                currentPos = advance(currentPos, 1); 
    413459                        } 
    414                          
     460 
    415461                        if (beginValue != null) { 
    416462                                return beginValue; 
    417463                        } 
    418464                } 
    419465                return attribute.getDefaultValue(); 
    420466        } 
    421          
     467 
    422468        /** 
    423469         * Retrieves the style value of the specified attribute at the given 
    424470         * {@link HotPos} of the current text. If the attribute has no value defined 
     
    448494                } 
    449495                return attribute.getDefaultValue(); 
    450496        } 
    451          
     497 
    452498        /** 
    453499         * Adds a new attachment to this text. 
    454500         *  
     
    466512                        key = interval.reverse(); 
    467513                } 
    468514                ImmMap<HotInterval, Attachment> newAtt = this.attachments.put(key, attachment); 
    469                  
     515 
    470516                ElemOp lastOp = new ElemOp.NoOp(this.getIndex(interval.getBegin()), 
    471517                                this.getIndex(interval.getEnd())); 
    472                  
     518 
    473519                return new ImmHotText(this.chars, this.styleValues, this, lastOp, 
    474520                                this.subSingleInterval, generateId(), null, newAtt, this.attrString);    
    475521        } 
    476          
     522 
    477523        /** 
    478524         * Removes from this text the attachments associated with the given interval. 
    479525         * If there are no such attachments, returns the same text. 
     
    488534                if(getPosComparator().compare(interval.getBegin(), interval.getEnd()) > 0) { 
    489535                        key = interval.reverse(); 
    490536                } 
    491                  
     537 
    492538                if (!this.attachments.contains(key)) { 
    493539                        return this; 
    494540                } 
    495                  
     541 
    496542                ImmMap<HotInterval, Attachment> newAtt = this.attachments.remove(key); 
    497                  
     543 
    498544                ElemOp lastOp = new ElemOp.NoOp(getIndex(interval.getBegin()), 
    499545                                getIndex(interval.getEnd())); 
    500                  
     546 
    501547                return new ImmHotText(this.chars, this.styleValues, this, lastOp, 
    502548                                this.subSingleInterval, generateId(), null, newAtt, this.attrString);    
    503549        } 
    504          
     550 
    505551        /** 
    506552         * Gets a map associating the attachments of this text to {@link HotInterval}s. 
    507553         *  
     
    511557        public ImmMap<HotInterval, Attachment> getAttachments() { 
    512558                return this.attachments; 
    513559        } 
    514          
     560 
    515561        /** 
    516562         * Retrieves the style values of the current text. For internal 
    517563         * use only - needed for testing purposes. 
    518564         *  
    519565         * @return The current text's style values. 
    520566         */ 
    521       ImmMap<HotAttr<?>, StyleValueSet<?>> getStyleValues() { 
     567        ImmMap<HotAttr<?>, StyleValueSet<?>> getStyleValues() { 
    522568                return this.styleValues; 
    523569        } 
    524      
     570 
    525571        /** 
    526572         * Transforms the styleValues of the current text to a map  
    527573         * with new poses that belong to the current text. Used for persistence. 
     
    532578        ImmMap<HotAttr<?>,StyleValueSet<?>> getNormalizedStyleValues() { 
    533579                ImmMap<HotAttr<?>,StyleValueSet<?>> newValueImmMap = new ImmTreeMap<HotAttr<?>, StyleValueSet<?>>( 
    534580                                new ImmHashingTree<ImmEntry<HotAttr<?>, StyleValueSet<?>>>(), getAttrComparator()); 
    535                  
     581 
    536582                for (ImmEntry<HotAttr<?>, StyleValueSet<?>> entry : this.getStyleValues()) { 
    537583                        HotAttr<?> key = entry.getKey(); 
    538584                        StyleValueSet<Object> valueMap = (StyleValueSet<Object>) 
    539                                 this.styleValues.get(key); 
     585                        this.styleValues.get(key); 
    540586                        StyleValueSet<Object> newValueMap = (StyleValueSet<Object>)StyleValueSet.create(key, getPosComparator()); 
    541587 
    542588                        HotPos prevPos = null; 
     
    555601                                        prevPos = pos; 
    556602                                        continue; 
    557603                                } 
    558                 HotPos firstPos = getPos(HotPosKind.getIndexForKind 
    559                                 (HotPosKind.getRelativeIndex 
    560                                                 (getRealIndex(prevPos)),prevPos.getKind())); 
    561                 HotPos secondPos = getPos(HotPosKind.getIndexForKind 
    562                                 (HotPosKind.getRelativeIndex 
    563                                                 (getRealIndex(pos)),pos.getKind())); 
     604                                HotPos firstPos = getPos(HotPosKind.getIndexForKind 
     605                                                (HotPosKind.getRelativeIndex 
     606                                                                (getRealIndex(prevPos)),prevPos.getKind())); 
     607                                HotPos secondPos = getPos(HotPosKind.getIndexForKind 
     608                                                (HotPosKind.getRelativeIndex 
     609                                                                (getRealIndex(pos)),pos.getKind())); 
    564610                                Object value = valueMap.getValue(prevPos); 
    565611                                newValueMap = newValueMap.setValue(firstPos, secondPos, value); 
    566612                                prevPos = pos; 
    567613                        } 
    568                          
     614 
    569615                        newValueImmMap = newValueImmMap.put(key, newValueMap); 
    570616                } 
    571                  
     617 
    572618                return newValueImmMap; 
    573619        } 
    574620 
     
    707753                        } 
    708754                        res = index; 
    709755                } 
    710 //              int begin = HotPosKind.getIndexForKind(HotPosKind.getRelativeIndex(0), pos.getKind()); 
    711 //              int end = HotPosKind.getIndexForKind(HotPosKind.getRelativeIndex(this.chars.size()), pos.getKind()); 
    712 //              if (res < begin) { 
    713 //                      System.out.println("Begin: " + this); 
    714 //              } 
    715 //              assert res >= begin : "Invalid index: " + res + ", expected > " + begin; 
    716 //               
    717 //              if (HotPosKind.getRealIndex(res) < this.subSingleInterval.getBegin()) { 
    718 //                      res -= 4; 
    719 //              } 
    720 //              if (res > end) { 
    721 //                      System.out.println("End: " + this); 
    722 //              } 
    723 //              assert res <= end : "Invalid index: " + res + ", expected < " + end; 
     756                //              int begin = HotPosKind.getIndexForKind(HotPosKind.getRelativeIndex(0), pos.getKind()); 
     757                //              int end = HotPosKind.getIndexForKind(HotPosKind.getRelativeIndex(this.chars.size()), pos.getKind()); 
     758                //              if (res < begin) { 
     759                //                      System.out.println("Begin: " + this); 
     760                //              } 
     761                //              assert res >= begin : "Invalid index: " + res + ", expected > " + begin; 
     762                //               
     763                //              if (HotPosKind.getRealIndex(res) < this.subSingleInterval.getBegin()) { 
     764                //                      res -= 4; 
     765                //              } 
     766                //              if (res > end) { 
     767                //                      System.out.println("End: " + this); 
     768                //              } 
     769                //              assert res <= end : "Invalid index: " + res + ", expected < " + end; 
    724770 
    725771                return res; 
    726772        } 
     
    735781         */ 
    736782        int getRealIndex(HotPos pos) { 
    737783                return HotPosKind.getRealIndex(getIndex(pos))  
    738                                         - this.subSingleInterval.getBegin(); 
     784                - this.subSingleInterval.getBegin(); 
    739785        } 
    740          
     786 
    741787        /** 
    742788         * Retrieves the {@link HotPos} relative to the specified index with the appropriate kind. 
    743789         * Note that the input index is a custom index for internal use only and is not the real  
     
    763809         */ 
    764810        HotPos getRealPos(int index) { 
    765811                int relativeIndex = HotPosKind.getIndexForKind( 
    766                         HotPosKind.getRelativeIndex(index), HotPosKind.MIDDLE); 
     812                                HotPosKind.getRelativeIndex(index), HotPosKind.MIDDLE); 
    767813                return new HotPos(relativeIndex + HotPosKind.getRelativeIndex( 
    768814                                this.subSingleInterval.getBegin()), this); 
    769815        } 
    770          
     816 
    771817        private HotPos changePosKind(HotPos pos, HotPosKind kind) { 
    772818                return getPos(HotPosKind.getIndexForKind(getIndex(pos), kind)); 
    773819        } 
    774          
     820 
    775821        // Navigation operations. 
    776822 
    777823        /** 
     
    787833        public HotPos advance(HotPos from, int offset) { 
    788834                if (!hasPosition(from)) { 
    789835                        throw new IllegalArgumentException("The input position does not " + 
    790                                         "belong to the current text"); 
     836                        "belong to the current text"); 
    791837                } 
    792838                int index = getIndex(from) + HotPosKind.getRelativeIndex(offset); 
    793839                if (getIndex(changePosKind(getBegin(), from.getKind())) <= index && 
     
    796842                }  
    797843 
    798844                throw new IllegalArgumentException("The wanted position does not " + 
    799                                 "belong to the current text"); 
     845                "belong to the current text"); 
    800846        } 
    801847 
    802848        /** 
     
    832878                assert pos.getKind() == HotPosKind.MIDDLE; 
    833879                return this.chars.get(TextUtils.getIndex(this, pos) + this.subSingleInterval.getBegin() - 1); 
    834880        } 
    835          
     881 
    836882        /** 
    837883         * Retrieves the character after the specified position in  
    838884         * the current text. 
     
    883929        public boolean hasPosition(HotPos pos) { 
    884930                Comparator<HotPos> posComparator = getPosComparator(); 
    885931                return posComparator.compare(getBegin(), pos) <= 0 
    886                                 && posComparator.compare(pos, getEnd()) <= 0; 
     932                && posComparator.compare(pos, getEnd()) <= 0; 
    887933        } 
    888          
     934 
    889935        /** 
    890936         * Retrieves the interval of positions of the last operation  
    891937         * that lead to the creation of the current {@link ImmHotText}. 
     
    898944                if (this.lastOperation == null) { 
    899945                        return this.lastChangedInterval; 
    900946                } 
    901                  
     947 
    902948                HotIndexInterval indexInterval = this.lastOperation.getChangedInterval(); 
    903949                return new HotInterval(getPos(indexInterval.getBegin()), 
    904950                                getPos(indexInterval.getEnd())); 
     
    919965                        } 
    920966                }; 
    921967        } 
    922          
     968 
    923969        /** 
    924970         * Retrieves a comparator for two styling attributes.  
    925971         * The {@link HotAttr} objects are compared by string ID. 
     
    11191165                private static class NoOp extends ElemOp { 
    11201166                        private int begin; 
    11211167                        private int end; 
    1122                          
     1168 
    11231169                        public NoOp(int begin, int end) { 
    11241170                                this.begin = begin; 
    11251171                                this.end = end; 
    11261172                        } 
    1127                          
     1173 
    11281174                        @Override 
    11291175                        public int updatePastIndex(int oldIndex) { 
    11301176                                return oldIndex; 
     
    11411187                        } 
    11421188                } 
    11431189        } 
    1144          
    1145                 /** 
    1146                  * Checks whether this text has the same ID as the passed one,  
    1147                  * or this text's parent has. 
    1148                  *  
    1149                  * @param parentText 
    1150                  *                      The text this one should come from. 
    1151                  * @return 
    1152                  *                      True if this text is the same, sub-text or result of an  
    1153                  *                      {@link ElemOp} over the parent, false otherwise. 
    1154                  */ 
    1155                 public boolean derivesFrom(ImmHotText parentText) { 
    1156                         if (parentText == null) { 
    1157                                 return false; 
    1158                         } 
    1159                          
    1160                         boolean res = false; 
    1161                         res = res || ((this.prevText != null) && (parentText.getId() == this.prevText.getId())); 
    1162                         res = res || (parentText.getId() == getId()); 
    1163                          
    1164                         return res; 
     1190 
     1191        /** 
     1192         * Checks whether this text has the same ID as the passed one,  
     1193         * or this text's parent has. 
     1194         *  
     1195         * @param parentText 
     1196         *                      The text this one should come from. 
     1197         * @return 
     1198         *                      True if this text is the same, sub-text or result of an  
     1199         *                      {@link ElemOp} over the parent, false otherwise. 
     1200         */ 
     1201        public boolean derivesFrom(ImmHotText parentText) { 
     1202                if (parentText == null) { 
     1203                        return false; 
    11651204                } 
    11661205 
     1206                boolean res = false; 
     1207                res = res || ((this.prevText != null) && (parentText.getId() == this.prevText.getId())); 
     1208                res = res || (parentText.getId() == getId()); 
     1209 
     1210                return res; 
     1211        } 
     1212 
    11671213} 
  • modules/org.sophie2.main.func.text/src/main/java/org/sophie2/main/func/text/view/HotTextLogic.java

     
    363363                        HotInterval interval = getSelectionEnds(flow); 
    364364                        assert interval != null; 
    365365 
    366                         ImmHotText newText = text.replace(interval, textToInsert); 
     366                         
     367                        ImmHotText newText = text.replace(interval, ImmHotText.empty()); 
     368                        newText = newText.replace(new HotInterval(interval.getBegin(), 
     369                                        interval.getBegin()), textToInsert); 
    367370                        boolean handled = LogicR3.fire(TextFlowLogic.createSetTextEvent(newText, 
    368371                                        "Insert text", event)); 
    369372 
  • modules/org.sophie2.base.model.text/src/main/java/org/sophie2/base/model/text/mvc/TextFlowLogic.java

     
    456456 
    457457                HotInterval interval = getSelectionEnds(flow); 
    458458                assert interval != null; 
    459  
    460459                ImmHotText newText = immHotText.replace(interval, ImmHotText 
    461460                                .createPlain(text)); 
    462461