Revision | a9baf779083304208769e43b4c6dbf28b6ac40f6 (tree) |
---|---|
Zeit | 2017-10-23 21:05:05 |
Autor | <exeal@user...> |
Replaced adaption flag with new adaptation level in kernel.AbstractPoint interface.
@@ -29,14 +29,23 @@ | ||
29 | 29 | /// Base class of @c Point and @c viewer#VisualPoint. |
30 | 30 | class AbstractPoint { |
31 | 31 | public: |
32 | + /** | |
33 | + * Adaptation levels. | |
34 | + * @see #adaptationLevel, #setAdaptationLevel | |
35 | + */ | |
36 | + enum AdaptationLevel { | |
37 | + /// The point is moved automatically according to the document change. | |
38 | + ADAPT_TO_DOCUMENT, | |
39 | + /// @c ADAPT_TO_DOCUMENT and the point is shrunk to the accessible region of the document. | |
40 | + ADAPT_TO_DOCUMENT_ACCESSIBLE_REGION | |
41 | + }; | |
42 | + | |
32 | 43 | explicit AbstractPoint(Document& document); |
33 | 44 | AbstractPoint(const AbstractPoint& other); |
34 | 45 | virtual ~AbstractPoint() BOOST_NOEXCEPT; |
35 | 46 | |
36 | 47 | /// @name Document |
37 | 48 | /// @{ |
38 | - bool adaptsToDocument() const BOOST_NOEXCEPT; | |
39 | - AbstractPoint& adaptToDocument(bool adapt) BOOST_NOEXCEPT; | |
40 | 49 | Document& document(); |
41 | 50 | const Document& document() const; |
42 | 51 | bool isDocumentDisposed() const BOOST_NOEXCEPT; |
@@ -44,7 +53,9 @@ | ||
44 | 53 | |
45 | 54 | /// @name Behaviors |
46 | 55 | /// @{ |
56 | + const boost::optional<AdaptationLevel>& adaptationLevel() const BOOST_NOEXCEPT; | |
47 | 57 | Direction gravity() const BOOST_NOEXCEPT; |
58 | + AbstractPoint& setAdaptationLevel(const boost::optional<AdaptationLevel>& level); | |
48 | 59 | AbstractPoint& setGravity(Direction gravity); |
49 | 60 | /// @} |
50 | 61 |
@@ -55,41 +66,22 @@ | ||
55 | 66 | /// @} |
56 | 67 | |
57 | 68 | private: |
58 | - /// Called when @c Document#resetContent of the document was called. | |
69 | + virtual void adaptationLevelChanged() BOOST_NOEXCEPT; | |
59 | 70 | virtual void contentReset() = 0; |
60 | - /** | |
61 | - * Called when the content of the document is about to be changed. | |
62 | - * @param change The change | |
63 | - */ | |
64 | 71 | virtual void documentAboutToBeChanged(const DocumentChange& change) = 0; |
65 | - /** | |
66 | - * Called when the content of the document was changed. | |
67 | - * @param change The change | |
68 | - */ | |
69 | 72 | virtual void documentChanged(const DocumentChange& change) = 0; |
70 | - /// Called when the document is disposed. | |
71 | 73 | void documentDisposed() BOOST_NOEXCEPT; |
72 | 74 | friend class Document; |
73 | 75 | private: |
74 | 76 | Document* document_; // weak reference |
75 | - bool adapting_; | |
77 | + boost::optional<AdaptationLevel> adaptationLevel_; | |
76 | 78 | Direction gravity_; |
77 | 79 | DestructionSignal destructionSignal_; |
78 | 80 | }; |
79 | 81 | |
80 | 82 | /// Returns @c true if the point is adapting to the document change. |
81 | - inline bool AbstractPoint::adaptsToDocument() const BOOST_NOEXCEPT { | |
82 | - return adapting_; | |
83 | - } | |
84 | - | |
85 | - /** | |
86 | - * Adapts the point to the document change. | |
87 | - * @param adapt | |
88 | - * @post #adaptsToDocument() == adapt | |
89 | - */ | |
90 | - inline AbstractPoint& AbstractPoint::adaptToDocument(bool adapt) BOOST_NOEXCEPT { | |
91 | - adapting_ = adapt; | |
92 | - return *this; | |
83 | + inline const boost::optional<AbstractPoint::AdaptationLevel>& AbstractPoint::adaptationLevel() const BOOST_NOEXCEPT { | |
84 | + return adaptationLevel_; | |
93 | 85 | } |
94 | 86 | |
95 | 87 | /// Returns the @c AbstractPoint#DestructionSignal signal connector. |
@@ -118,19 +110,17 @@ | ||
118 | 110 | } |
119 | 111 | |
120 | 112 | /** |
121 | - * @internal The document is in destruction. | |
122 | - * @post #isDocumentDisposed() == true | |
113 | + * Returns the gravity. | |
114 | + * @see #setGravity | |
123 | 115 | */ |
124 | - inline void AbstractPoint::documentDisposed() BOOST_NOEXCEPT { | |
125 | - document_ = nullptr; | |
126 | - } | |
127 | - | |
128 | - /// Returns the gravity. | |
129 | 116 | inline Direction AbstractPoint::gravity() const BOOST_NOEXCEPT { |
130 | 117 | return gravity_; |
131 | 118 | } |
132 | 119 | |
133 | - /// Returns @c true if the document is already disposed. | |
120 | + /** | |
121 | + * Returns @c true if the document is already disposed. | |
122 | + * @see #DestructionSignal | |
123 | + */ | |
134 | 124 | inline bool AbstractPoint::isDocumentDisposed() const BOOST_NOEXCEPT { |
135 | 125 | return document_ == nullptr; |
136 | 126 | } |
@@ -72,7 +72,7 @@ | ||
72 | 72 | /// @defgroup accessible_regions_of_document Accessible Regions of Document |
73 | 73 | /// Free functions related to document's accessible region. |
74 | 74 | /// @{ |
75 | -// bool isOutsideOfAccessibleRegion(const PointProxy& p) BOOST_NOEXCEPT; | |
75 | + bool isOutsideOfAccessibleRegion(const PointProxy& p) BOOST_NOEXCEPT; | |
76 | 76 | Position shrinkToAccessibleRegion(const PointProxy& p) BOOST_NOEXCEPT; |
77 | 77 | Region shrinkToAccessibleRegion(const Document& document, const Region& region) BOOST_NOEXCEPT; |
78 | 78 | /// @} |
@@ -38,6 +38,7 @@ | ||
38 | 38 | virtual void moved(const Position& from) BOOST_NOEXCEPT; |
39 | 39 | private: |
40 | 40 | // AbstractPoint |
41 | + void adaptationLevelChanged() BOOST_NOEXCEPT override; | |
41 | 42 | void contentReset() override; |
42 | 43 | void documentAboutToBeChanged(const DocumentChange& change) override; |
43 | 44 | void documentChanged(const DocumentChange& change) override; |
@@ -106,6 +106,7 @@ | ||
106 | 106 | virtual void aboutToMove(TextHit& to); |
107 | 107 | virtual void moved(const TextHit& from) BOOST_NOEXCEPT; |
108 | 108 | // kernel.AbstractPoint |
109 | + virtual void adaptationLevelChanged() BOOST_NOEXCEPT override; | |
109 | 110 | virtual void contentReset() override; |
110 | 111 | virtual void documentAboutToBeChanged(const kernel::DocumentChange& change) override; |
111 | 112 | virtual void documentChanged(const kernel::DocumentChange& change) override; |
@@ -15,10 +15,10 @@ | ||
15 | 15 | * Constructor. |
16 | 16 | * @param document The document to which the point attaches |
17 | 17 | * @post &#document() == &document |
18 | - * @post #adaptsToDocument() == true | |
18 | + * @post #adaptationLevel() == #ADAPT_TO_DOCUMENT | |
19 | 19 | * @post #gravity() == Direction#forward() |
20 | 20 | */ |
21 | - AbstractPoint::AbstractPoint(Document& document) : document_(&document), adapting_(true), gravity_(Direction::forward()) { | |
21 | + AbstractPoint::AbstractPoint(Document& document) : document_(&document), adaptationLevel_(ADAPT_TO_DOCUMENT), gravity_(Direction::forward()) { | |
22 | 22 | static_cast<detail::PointCollection<AbstractPoint>*>(document_)->addNewPoint(*this); |
23 | 23 | } |
24 | 24 |
@@ -27,10 +27,10 @@ | ||
27 | 27 | * @param other The source object |
28 | 28 | * @throw DocumentDisposedException The document to which @a other belongs had been disposed |
29 | 29 | * @post &#document() == &other.document |
30 | - * @post #adaptsToDocument() == other.adaptsToDocument() | |
30 | + * @post #adaptationLevel() == other.adaptationLevel() | |
31 | 31 | * @post #gravity() == other.gravity() |
32 | 32 | */ |
33 | - AbstractPoint::AbstractPoint(const AbstractPoint& other) : document_(other.document_), adapting_(other.adapting_), gravity_(other.gravity_) { | |
33 | + AbstractPoint::AbstractPoint(const AbstractPoint& other) : document_(other.document_), adaptationLevel_(other.adaptationLevel()), gravity_(other.gravity()) { | |
34 | 34 | if(document_ == nullptr) |
35 | 35 | throw DocumentDisposedException(); |
36 | 36 | static_cast<detail::PointCollection<AbstractPoint>*>(document_)->addNewPoint(*this); |
@@ -44,21 +44,65 @@ | ||
44 | 44 | } |
45 | 45 | |
46 | 46 | /** |
47 | + * @internal The adaptation level was changed. | |
48 | + * @see #setAdaptationLevel | |
49 | + */ | |
50 | + void AbstractPoint::adaptationLevelChanged() BOOST_NOEXCEPT { | |
51 | + } | |
52 | + | |
53 | + /** | |
47 | 54 | * @fn ascension::kernel::AbstractPoint::contentReset |
48 | 55 | * @c Document#resetContent method was called. |
49 | 56 | */ |
50 | 57 | |
51 | 58 | /** |
59 | + * @fn ascension::kernel::AbstractPoint::documentAboutToBeChanged | |
60 | + * Called when the content of the document is about to be changed. | |
61 | + * @param change The content of the document change | |
62 | + */ | |
63 | + | |
64 | + /** | |
52 | 65 | * @fn ascension::kernel::AbstractPoint::documentChanged |
53 | 66 | * Called when the document was changed. |
54 | 67 | * @param change The content of the document change |
55 | 68 | */ |
56 | 69 | |
57 | 70 | /** |
71 | + * @internal The document is in destruction. | |
72 | + * @post #isDocumentDisposed() == true | |
73 | + * @see #DestructionSignal | |
74 | + */ | |
75 | + void AbstractPoint::documentDisposed() BOOST_NOEXCEPT { | |
76 | + document_ = nullptr; | |
77 | + } | |
78 | + | |
79 | + /** | |
80 | + * Sets the adaptation level. | |
81 | + * @param level The new adaptation level | |
82 | + * @return This object | |
83 | + * @post #adaptationLevel() == level | |
84 | + * @throw UnknownValueException @a level is unknown | |
85 | + * @note This method may invoke @c #adaptationLevelChanged method | |
86 | + * @see #adaptationLevel | |
87 | + */ | |
88 | + AbstractPoint& AbstractPoint::setAdaptationLevel(const boost::optional<AdaptationLevel>& level) { | |
89 | + if(level != adaptationLevel_) { | |
90 | + if(level != boost::none) { | |
91 | + if(boost::get(level) != ADAPT_TO_DOCUMENT && boost::get(level) != ADAPT_TO_DOCUMENT_ACCESSIBLE_REGION) | |
92 | + throw UnknownValueException("level"); | |
93 | + } | |
94 | + adaptationLevel_ = level; | |
95 | + adaptationLevelChanged(); | |
96 | + } | |
97 | + return *this; | |
98 | + } | |
99 | + | |
100 | + /** | |
58 | 101 | * Sets the gravity. |
59 | 102 | * @param gravity The new gravity value |
60 | 103 | * @return This object |
61 | 104 | * @post #gravity() == gravity |
105 | + * @see #gravity | |
62 | 106 | */ |
63 | 107 | AbstractPoint& AbstractPoint::setGravity(Direction gravity) { |
64 | 108 | if(isDocumentDisposed()) |
@@ -328,7 +328,7 @@ | ||
328 | 328 | (partitioner.get()->*partitionerMethod)(change); |
329 | 329 | if(pointMethod != nullptr) { |
330 | 330 | BOOST_FOREACH(AbstractPoint* p, points) { |
331 | - if(p->adaptsToDocument()) | |
331 | + if(p->adaptationLevel() != boost::none) | |
332 | 332 | (p->*pointMethod)(change); |
333 | 333 | } |
334 | 334 | } |
@@ -528,7 +528,7 @@ | ||
528 | 528 | else { |
529 | 529 | widen(); |
530 | 530 | BOOST_FOREACH(AbstractPoint* p, points_) { |
531 | - if(p->adaptsToDocument()) | |
531 | + if(p->adaptationLevel() != boost::none) | |
532 | 532 | p->contentReset(); |
533 | 533 | } |
534 | 534 | bookmarker_->clear(); |
@@ -157,12 +157,21 @@ | ||
157 | 157 | } |
158 | 158 | |
159 | 159 | /** |
160 | + * Returns @c true if the given position is outside of the accessible region of the document. | |
161 | + * @param p The point to check | |
162 | + * @return true if @a p is outside of the document | |
163 | + */ | |
164 | + bool isOutsideOfAccessibleRegion(const PointProxy& p) BOOST_NOEXCEPT { | |
165 | + return shrinkToAccessibleRegion(p) != position(p); | |
166 | + } | |
167 | + | |
168 | + /** | |
160 | 169 | * Returns @c true if the given position is outside of the document. |
161 | 170 | * @param p The point to check |
162 | 171 | * @return true if @a p is outside of the document |
163 | 172 | */ |
164 | 173 | bool isOutsideOfDocumentRegion(const PointProxy& p) BOOST_NOEXCEPT { |
165 | - return line(p) >= document(p).numberOfLines() || offsetInLine(p) > document(p).lineLength(line(p)); | |
174 | + return shrinkToDocumentRegion(p) != position(p); | |
166 | 175 | } |
167 | 176 | |
168 | 177 | /** |
@@ -107,17 +107,23 @@ | ||
107 | 107 | boost::ignore_unused(to); |
108 | 108 | } |
109 | 109 | |
110 | + /// @see AbstractPoint#adaptationLevelChanged | |
111 | + void Point::adaptationLevelChanged() BOOST_NOEXCEPT { | |
112 | + if(adaptationLevel() != boost::none && boost::get(adaptationLevel()) == ADAPT_TO_DOCUMENT_ACCESSIBLE_REGION && locations::isOutsideOfAccessibleRegion(*this)) | |
113 | + moveTo(locations::shrinkToAccessibleRegion(*this)); | |
114 | + } | |
115 | + | |
110 | 116 | /// @see AbstractPoint#contentReset |
111 | 117 | void Point::contentReset() { |
112 | 118 | assert(!isDocumentDisposed()); |
113 | - assert(adaptsToDocument()); | |
119 | + assert(adaptationLevel() != boost::none); | |
114 | 120 | moveTo(Position::zero()); |
115 | 121 | } |
116 | 122 | |
117 | 123 | /// @see AbstractPoint#documentAboutToBeChanged |
118 | 124 | void Point::documentAboutToBeChanged(const DocumentChange& change) { |
119 | 125 | assert(!isDocumentDisposed()); |
120 | - assert(adaptsToDocument()); | |
126 | + assert(adaptationLevel() != boost::none); | |
121 | 127 | assert(destination_ == boost::none); |
122 | 128 | destination_ = locations::updatePosition(position(), change, gravity()); |
123 | 129 | } |
@@ -125,7 +131,7 @@ | ||
125 | 131 | /// @see AbstractPoint#documentChanged |
126 | 132 | void Point::documentChanged(const DocumentChange& change) { |
127 | 133 | assert(!isDocumentDisposed()); |
128 | - assert(adaptsToDocument()); | |
134 | + assert(adaptationLevel() != boost::none); | |
129 | 135 | if(destination_ != boost::none) { |
130 | 136 | const auto newPosition(boost::get(destination_)); |
131 | 137 | destination_ = boost::none; |
@@ -452,8 +452,8 @@ | ||
452 | 452 | void destructiveInsert(Caret& caret, const StringPiece& text, bool keepNewline = true) { |
453 | 453 | if(text.cbegin() == nullptr || text.cend() == nullptr) |
454 | 454 | throw NullPointerException("text"); |
455 | - const bool adapts = caret.adaptsToDocument(); | |
456 | - caret.adaptToDocument(false); | |
455 | + const boost::optional<kernel::AbstractPoint::AdaptationLevel> adaptationLevel(caret.adaptationLevel()); | |
456 | + caret.setAdaptationLevel(boost::none); | |
457 | 457 | const auto p(insertionPosition(caret)); |
458 | 458 | kernel::Position e((keepNewline && kernel::locations::isEndOfLine(caret)) ? |
459 | 459 | p : kernel::locations::nextCharacter(caret, Direction::forward(), kernel::locations::GRAPHEME_CLUSTER)); |
@@ -461,12 +461,12 @@ | ||
461 | 461 | try { |
462 | 462 | e = caret.document().replace(kernel::Region(p, e), text); |
463 | 463 | } catch(...) { |
464 | - caret.adaptToDocument(adapts); | |
464 | + caret.setAdaptationLevel(adaptationLevel); | |
465 | 465 | throw; |
466 | 466 | } |
467 | 467 | caret.moveTo(TextHit::leading(e)); |
468 | 468 | } |
469 | - caret.adaptToDocument(adapts); | |
469 | + caret.setAdaptationLevel(adaptationLevel); | |
470 | 470 | } |
471 | 471 | } // namespace @0 |
472 | 472 |
@@ -248,6 +248,12 @@ | ||
248 | 248 | uninstall(); |
249 | 249 | } |
250 | 250 | |
251 | + /// @see AbstractPoint#adaptationLevelChanged | |
252 | + void VisualPoint::adaptationLevelChanged() BOOST_NOEXCEPT { | |
253 | + if(adaptationLevel() != boost::none && boost::get(adaptationLevel()) == ADAPT_TO_DOCUMENT_ACCESSIBLE_REGION && kernel::locations::isOutsideOfAccessibleRegion(*this)) | |
254 | + moveTo(TextHit::leading(kernel::locations::shrinkToAccessibleRegion(*this))); | |
255 | + } | |
256 | + | |
251 | 257 | /** |
252 | 258 | * See @c kernel#Point#aboutToMove. @c VisualPoint#aboutToMove does nothing. |
253 | 259 | * @param to The destination position |
@@ -276,14 +282,14 @@ | ||
276 | 282 | /// @see AbstractPoint#contentReset |
277 | 283 | void VisualPoint::contentReset() { |
278 | 284 | assert(!isDocumentDisposed()); |
279 | - assert(adaptsToDocument()); | |
285 | + assert(adaptationLevel() != boost::none); | |
280 | 286 | moveTo(TextHit::leading(kernel::Position::zero())); |
281 | 287 | } |
282 | 288 | |
283 | 289 | /// @see AbstractPoint#documentAboutToBeChanged |
284 | 290 | void VisualPoint::documentAboutToBeChanged(const kernel::DocumentChange& change) { |
285 | 291 | assert(!isDocumentDisposed()); |
286 | - assert(adaptsToDocument()); | |
292 | + assert(adaptationLevel() != boost::none); | |
287 | 293 | assert(hitAfterChange_ == boost::none); |
288 | 294 | hitAfterChange_ = locations::updateTextHit(hit(), document(), change, gravity()); |
289 | 295 | } |
@@ -291,7 +297,7 @@ | ||
291 | 297 | /// @see AbstractPoint#documentChanged |
292 | 298 | void VisualPoint::documentChanged(const kernel::DocumentChange& change) { |
293 | 299 | assert(!isDocumentDisposed()); |
294 | - assert(adaptsToDocument()); | |
300 | + assert(adaptationLevel() != boost::none); | |
295 | 301 | if(hitAfterChange_ != boost::none) { |
296 | 302 | const auto newHit(boost::get(hitAfterChange_)); |
297 | 303 | hitAfterChange_ = boost::none; |
@@ -530,13 +536,13 @@ | ||
530 | 536 | |
531 | 537 | /// @see VisualLinesListener#visualLinesDeleted |
532 | 538 | void VisualPoint::visualLinesDeleted(const boost::integer_range<Index>& lines, Index, bool) BOOST_NOEXCEPT { |
533 | - if(!adaptsToDocument() && includes(lines, kernel::line(hit().characterIndex()))) | |
539 | + if(adaptationLevel() == boost::none && includes(lines, kernel::line(hit().characterIndex()))) | |
534 | 540 | lineNumberCaches_ = boost::none; |
535 | 541 | } |
536 | 542 | |
537 | 543 | /// @see VisualLinesListener#visualLinesInserted |
538 | 544 | void VisualPoint::visualLinesInserted(const boost::integer_range<Index>& lines) BOOST_NOEXCEPT { |
539 | - if(!adaptsToDocument() && includes(lines, kernel::line(hit().characterIndex()))) | |
545 | + if(adaptationLevel() == boost::none && includes(lines, kernel::line(hit().characterIndex()))) | |
540 | 546 | lineNumberCaches_ = boost::none; |
541 | 547 | } |
542 | 548 |