1 /**
2  * \file CursorSlice.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Matthias Ettrich
8  * \author André Pönitz
9  * \author Jürgen Vigna
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13 
14 #include <config.h>
15 
16 #include "CursorSlice.h"
17 
18 #include "Text.h"
19 #include "Paragraph.h"
20 
21 #include "support/debug.h"
22 
23 #include "insets/Inset.h"
24 
25 #include "mathed/InsetMath.h"
26 #include "mathed/InsetMathMacro.h"
27 
28 #include "support/ExceptionMessage.h"
29 #include "support/gettext.h"
30 #include "support/lassert.h"
31 
32 #include <ostream>
33 
34 using namespace std;
35 
36 namespace lyx {
37 
38 
CursorSlice()39 CursorSlice::CursorSlice()
40 	: inset_(0), idx_(0), pit_(0), pos_(0)
41 {}
42 
43 
CursorSlice(Inset & p)44 CursorSlice::CursorSlice(Inset & p)
45 	: inset_(&p), idx_(0), pit_(0), pos_(0)
46 {
47 	LBUFERR(inset_);
48 }
49 
50 
cell() const51 MathData & CursorSlice::cell() const
52 {
53 	return inset_->asInsetMath()->cell(idx_);
54 }
55 
56 
paragraph() const57 Paragraph & CursorSlice::paragraph() const
58 {
59 	return text()->getPar(pit_);
60 }
61 
62 
lastpos() const63 pos_type CursorSlice::lastpos() const
64 {
65 	LBUFERR(inset_);
66 	InsetMath const * math = inset_->asInsetMath();
67 	bool paramless_macro = math && math->asMacro() && !math->asMacro()->nargs();
68 	return math ? (paramless_macro ? 0 : cell().size())
69 		    : (text()->empty() ? 0 : paragraph().size());
70 }
71 
72 
lastpit() const73 pit_type CursorSlice::lastpit() const
74 {
75 	if (inset_->inMathed())
76 		return 0;
77 	return text()->paragraphs().size() - 1;
78 }
79 
80 
row() const81 CursorSlice::row_type CursorSlice::row() const
82 {
83 	LASSERT(inset_, return 0);
84 	return inset_->row(idx_);
85 }
86 
87 
col() const88 CursorSlice::col_type CursorSlice::col() const
89 {
90 	LASSERT(inset_, return 0);
91 	return inset_->col(idx_);
92 }
93 
94 
setPitPos(pit_type pit,pos_type pos)95 void CursorSlice::setPitPos(pit_type pit, pos_type pos)
96 {
97 	LASSERT(pit != int(text()->paragraphs().size()), return);
98 	pit_ = pit;
99 	pos_ = pos;
100 
101 	// Now some strict checking. None of these should happen, but
102 	// we're scaredy-cats
103 	if (pos < 0) {
104 		LYXERR0("Don't like -1!");
105 		LATTEST(false);
106 	}
107 
108 	if (pos > paragraph().size()) {
109 		LYXERR0("Don't like 1, pos: " << pos
110 				<< " size: " << paragraph().size()
111 		       << " par: " << pit);
112 		LATTEST(false);
113 	}
114 }
115 
116 
forwardPos()117 void CursorSlice::forwardPos()
118 {
119 	//  move on one position if possible
120 	if (pos_ < lastpos()) {
121 		//lyxerr << "... next pos" << endl;
122 		++pos_;
123 		return;
124 	}
125 
126 	// otherwise move on one paragraph if possible
127 	if (pit_ < lastpit()) {
128 		//lyxerr << "... next par" << endl;
129 		++pit_;
130 		pos_ = 0;
131 		return;
132 	}
133 
134 	// otherwise move on one cell
135 	//lyxerr << "... next idx" << endl;
136 
137 	LASSERT(idx_ < nargs(), return);
138 
139 	++idx_;
140 	pit_ = 0;
141 	pos_ = 0;
142 }
143 
144 
forwardIdx()145 void CursorSlice::forwardIdx()
146 {
147 	LASSERT(idx_ < nargs(), return);
148 
149 	++idx_;
150 	pit_ = 0;
151 	pos_ = 0;
152 }
153 
154 
backwardPos()155 void CursorSlice::backwardPos()
156 {
157 	if (pos_ != 0) {
158 		--pos_;
159 		return;
160 	}
161 
162 	if (pit_ != 0) {
163 		--pit_;
164 		pos_ = lastpos();
165 		return;
166 	}
167 
168 	if (idx_ != 0) {
169 		--idx_;
170 		pit_ = lastpit();
171 		pos_ = lastpos();
172 		return;
173 	}
174 
175 	LATTEST(false);
176 }
177 
178 
at_cell_end() const179 bool CursorSlice::at_cell_end() const
180 {
181 	return pit_ == lastpit() && pos_ == lastpos();
182 }
183 
184 
at_cell_begin() const185 bool CursorSlice::at_cell_begin() const
186 {
187 	return pit_ == 0 && pos_ == 0;
188 }
189 
190 
at_end() const191 bool CursorSlice::at_end() const
192 {
193 	return idx_ == lastidx() && at_cell_end();
194 }
195 
196 
at_begin() const197 bool CursorSlice::at_begin() const
198 {
199 	return idx_ == 0 && at_cell_begin();
200 }
201 
202 
operator ==(CursorSlice const & p,CursorSlice const & q)203 bool operator==(CursorSlice const & p, CursorSlice const & q)
204 {
205 	return p.inset_ == q.inset_
206 	       && p.idx_ == q.idx_
207 	       && p.pit_ == q.pit_
208 	       && p.pos_ == q.pos_;
209 }
210 
211 
operator !=(CursorSlice const & p,CursorSlice const & q)212 bool operator!=(CursorSlice const & p, CursorSlice const & q)
213 {
214 	return p.inset_ != q.inset_
215 	       || p.idx_ != q.idx_
216 	       || p.pit_ != q.pit_
217 	       || p.pos_ != q.pos_;
218 }
219 
220 
operator <(CursorSlice const & p,CursorSlice const & q)221 bool operator<(CursorSlice const & p, CursorSlice const & q)
222 {
223 	if (p.inset_ != q.inset_) {
224 		LYXERR0("can't compare cursor and anchor in different insets\n"
225 		       << "p: " << p << '\n' << "q: " << q);
226 		// It should be safe to continue, just registering the error.
227 		LASSERT(false, return false);
228 	}
229 	if (p.idx_ != q.idx_)
230 		return p.idx_ < q.idx_;
231 	if (p.pit_ != q.pit_)
232 		return p.pit_ < q.pit_;
233 	return p.pos_ < q.pos_;
234 }
235 
236 
operator >(CursorSlice const & p,CursorSlice const & q)237 bool operator>(CursorSlice const & p, CursorSlice const & q)
238 {
239 	return q < p;
240 }
241 
242 
operator <=(CursorSlice const & p,CursorSlice const & q)243 bool operator<=(CursorSlice const & p, CursorSlice const & q)
244 {
245 	return !(q < p);
246 }
247 
248 
operator <<(ostream & os,CursorSlice const & item)249 ostream & operator<<(ostream & os, CursorSlice const & item)
250 {
251 	return os
252 	   << "inset: " << (void *)item.inset_
253 //	   << " text: " << item.text()
254 	   << " idx: " << item.idx_
255 	   << " par: " << item.pit_
256 	   << " pos: " << item.pos_
257 //	   << " x: " << item.inset_->x()
258 //	   << " y: " << item.inset_->y()
259 ;
260 }
261 
262 
263 } // namespace lyx
264