1 /*
2 Qalculate (library)
3
4 Copyright (C) 2003-2007, 2008, 2016 Hanna Knutsson (hanna.knutsson@protonmail.com)
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 */
11
12 #include "support.h"
13
14 #include "ExpressionItem.h"
15 #include "Calculator.h"
16 #include "util.h"
17
18 using std::string;
19 using std::vector;
20
ExpressionName(string sname)21 ExpressionName::ExpressionName(string sname) : suffix(false), unicode(false), plural(false), reference(false), avoid_input(false), completion_only(false) {
22 name = sname;
23 if(text_length_is_one(sname)) {
24 abbreviation = true;
25 case_sensitive = true;
26 } else {
27 abbreviation = false;
28 case_sensitive = false;
29 }
30 if(sname.length() > 2) {
31 size_t i = sname.find('_', 1);
32 if(i != string::npos && i < sname.length() - 1 && sname.find('_', i + 1) == string::npos) suffix = true;
33 }
34 }
ExpressionName()35 ExpressionName::ExpressionName() : abbreviation(false), suffix(false), unicode(false), plural(false), reference(false), avoid_input(false), case_sensitive(false), completion_only(false) {
36 }
operator =(const ExpressionName & ename)37 void ExpressionName::operator = (const ExpressionName &ename) {
38 name = ename.name;
39 abbreviation = ename.abbreviation;
40 case_sensitive = ename.case_sensitive;
41 suffix = ename.suffix;
42 unicode = ename.unicode;
43 plural = ename.plural;
44 reference = ename.reference;
45 avoid_input = ename.avoid_input;
46 completion_only = ename.completion_only;
47 }
operator ==(const ExpressionName & ename) const48 bool ExpressionName::operator == (const ExpressionName &ename) const {
49 return name == ename.name && abbreviation == ename.abbreviation && case_sensitive == ename.case_sensitive && suffix == ename.suffix && unicode == ename.unicode && plural == ename.plural && reference == ename.reference && avoid_input == ename.avoid_input && completion_only == ename.completion_only;
50 }
operator !=(const ExpressionName & ename) const51 bool ExpressionName::operator != (const ExpressionName &ename) const {
52 return name != ename.name || abbreviation != ename.abbreviation || case_sensitive != ename.case_sensitive || suffix != ename.suffix || unicode != ename.unicode || plural != ename.plural || reference != ename.reference || avoid_input != ename.avoid_input || completion_only != ename.completion_only;
53 }
54
ExpressionItem(string cat_,string name_,string title_,string descr_,bool is_local,bool is_builtin,bool is_active)55 ExpressionItem::ExpressionItem(string cat_, string name_, string title_, string descr_, bool is_local, bool is_builtin, bool is_active) {
56
57 b_local = is_local;
58 b_builtin = is_builtin;
59 remove_blank_ends(name_);
60 remove_blank_ends(cat_);
61 remove_blank_ends(title_);
62
63 if(!name_.empty()) {
64 names.resize(1);
65 names[0].name = name_;
66 names[0].unicode = false;
67 names[0].abbreviation = false;
68 names[0].case_sensitive = text_length_is_one(name_);
69 size_t i = name_.find('_');
70 if(i != string::npos && i > 0 && i < name_.length() - 1 && name_.find('_', i + 1) == string::npos) names[0].suffix = true;
71 else names[0].suffix = false;
72 names[0].avoid_input = false;
73 names[0].reference = true;
74 names[0].plural = false;
75 }
76
77 stitle = title_;
78 scat = cat_;
79 sdescr = descr_;
80 b_changed = false;
81 b_approx = false;
82 i_precision = -1;
83 b_active = is_active;
84 b_registered = false;
85 b_hidden = false;
86 b_destroyed = false;
87 i_ref = 0;
88
89 }
ExpressionItem()90 ExpressionItem::ExpressionItem() {
91 b_changed = false;
92 b_approx = false;
93 i_precision = -1;
94 b_active = true;
95 b_local = true;
96 b_builtin = false;
97 b_registered = false;
98 b_hidden = false;
99 b_destroyed = false;
100 i_ref = 0;
101 }
~ExpressionItem()102 ExpressionItem::~ExpressionItem() {
103 }
set(const ExpressionItem * item)104 void ExpressionItem::set(const ExpressionItem *item) {
105 b_changed = item->hasChanged();
106 b_approx = item->isApproximate();
107 i_precision = item->precision();
108 b_active = item->isActive();
109 for(size_t i = 1; i <= item->countNames(); i++) {
110 names.push_back(item->getName(1));
111 }
112 stitle = item->title(false);
113 scat = item->category();
114 sdescr = item->description();
115 b_local = item->isLocal();
116 b_builtin = item->isBuiltin();
117 b_hidden = item->isHidden();
118 }
destroy()119 bool ExpressionItem::destroy() {
120 CALCULATOR->expressionItemDeleted(this);
121 if(v_refs.size() > 0) {
122 return false;
123 } else if(i_ref > 0) {
124 b_destroyed = true;
125 } else {
126 delete this;
127 }
128 return true;
129 }
isRegistered() const130 bool ExpressionItem::isRegistered() const {
131 return b_registered;
132 }
setRegistered(bool is_registered)133 void ExpressionItem::setRegistered(bool is_registered) {
134 b_registered = is_registered;
135 }
title(bool return_name_if_no_title,bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const136 const string &ExpressionItem::title(bool return_name_if_no_title, bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
137 if(return_name_if_no_title && stitle.empty()) {
138 return preferredName(false, use_unicode, false, false, can_display_unicode_string_function, can_display_unicode_string_arg).name;
139 }
140 return stitle;
141 }
setTitle(string title_)142 void ExpressionItem::setTitle(string title_) {
143 remove_blank_ends(title_);
144 if(stitle != title_) {
145 stitle = title_;
146 b_changed = true;
147 }
148 }
description() const149 const string &ExpressionItem::description() const {
150 return sdescr;
151 }
setDescription(string descr_)152 void ExpressionItem::setDescription(string descr_) {
153 remove_blank_ends(descr_);
154 if(sdescr != descr_) {
155 sdescr = descr_;
156 b_changed = true;
157 }
158 }
name(bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const159 const string &ExpressionItem::name(bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
160 bool undisplayable_uni = false;
161 for(size_t i = 0; i < names.size(); i++) {
162 if(names[i].unicode == use_unicode && (!names[i].completion_only || i + 1 == names.size())) {
163 if(use_unicode && can_display_unicode_string_function && !((*can_display_unicode_string_function) (names[i].name.c_str(), can_display_unicode_string_arg))) {
164 undisplayable_uni = true;
165 } else {
166 return names[i].name;
167 }
168 }
169 }
170 if(undisplayable_uni) return name(false);
171 if(names.size() > 0) return names[0].name;
172 return empty_string;
173 }
referenceName() const174 const string &ExpressionItem::referenceName() const {
175 for(size_t i = 0; i < names.size(); i++) {
176 if(names[i].reference) {
177 return names[i].name;
178 }
179 }
180 if(names.size() > 0) return names[0].name;
181 return empty_string;
182 }
183
preferredName(bool abbreviation,bool use_unicode,bool plural,bool reference,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const184 const ExpressionName &ExpressionItem::preferredName(bool abbreviation, bool use_unicode, bool plural, bool reference, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
185 if(names.size() == 1) return names[0];
186 int index = -1;
187 for(size_t i = 0; i < names.size(); i++) {
188 if((!reference || names[i].reference) && names[i].abbreviation == abbreviation && names[i].unicode == use_unicode && names[i].plural == plural && !names[i].completion_only && (!use_unicode || !can_display_unicode_string_function || (*can_display_unicode_string_function) (names[i].name.c_str(), can_display_unicode_string_arg))) return names[i];
189 if(index < 0) {
190 index = i;
191 } else if(names[i].completion_only != names[index].completion_only) {
192 if(!names[i].completion_only) index = i;
193 } else if(reference && names[i].reference != names[index].reference) {
194 if(names[i].reference) index = i;
195 } else if(!use_unicode && names[i].unicode != names[index].unicode) {
196 if(!names[i].unicode) index = i;
197 } else if(names[i].abbreviation != names[index].abbreviation) {
198 if(names[i].abbreviation == abbreviation) index = i;
199 } else if(names[i].plural != names[index].plural) {
200 if(names[i].plural == plural) index = i;
201 } else if(use_unicode && names[i].unicode != names[index].unicode) {
202 if(names[i].unicode) index = i;
203 }
204 }
205 if(use_unicode && names[index].unicode && can_display_unicode_string_function && !((*can_display_unicode_string_function) (names[index].name.c_str(), can_display_unicode_string_arg))) {
206 return preferredName(abbreviation, false, plural, reference, can_display_unicode_string_function, can_display_unicode_string_arg);
207 }
208 if(index >= 0) return names[index];
209 return empty_expression_name;
210 }
preferredInputName(bool abbreviation,bool use_unicode,bool plural,bool reference,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const211 const ExpressionName &ExpressionItem::preferredInputName(bool abbreviation, bool use_unicode, bool plural, bool reference, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
212 if(names.size() == 1) return names[0];
213 int index = -1;
214 for(size_t i = 0; i < names.size(); i++) {
215 if((!reference || names[i].reference) && names[i].abbreviation == abbreviation && names[i].unicode == use_unicode && names[i].plural == plural && !names[i].avoid_input && !names[i].completion_only) return names[i];
216 if(index < 0) {
217 index = i;
218 } else if(names[i].completion_only != names[index].completion_only) {
219 if(!names[i].completion_only) index = i;
220 } else if(reference && names[i].reference != names[index].reference) {
221 if(names[i].reference) index = i;
222 } else if(!use_unicode && names[i].unicode != names[index].unicode) {
223 if(!names[i].unicode) index = i;
224 } else if(names[i].avoid_input != names[index].avoid_input) {
225 if(!names[i].avoid_input) index = i;
226 } else if(abbreviation && names[i].abbreviation != names[index].abbreviation) {
227 if(names[i].abbreviation) index = i;
228 } else if(plural && names[i].plural != names[index].plural) {
229 if(names[i].plural) index = i;
230 } else if(!abbreviation && names[i].abbreviation != names[index].abbreviation) {
231 if(!names[i].abbreviation) index = i;
232 } else if(!plural && names[i].plural != names[index].plural) {
233 if(!names[i].plural) index = i;
234 } else if(use_unicode && names[i].unicode != names[index].unicode) {
235 if(names[i].unicode) index = i;
236 }
237 }
238 if(use_unicode && names[index].unicode && can_display_unicode_string_function && !((*can_display_unicode_string_function) (names[index].name.c_str(), can_display_unicode_string_arg))) {
239 return preferredInputName(abbreviation, false, plural, reference, can_display_unicode_string_function, can_display_unicode_string_arg);
240 }
241 if(index >= 0) return names[index];
242 return empty_expression_name;
243 }
preferredDisplayName(bool abbreviation,bool use_unicode,bool plural,bool reference,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const244 const ExpressionName &ExpressionItem::preferredDisplayName(bool abbreviation, bool use_unicode, bool plural, bool reference, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
245 return preferredName(abbreviation, use_unicode, plural, reference, can_display_unicode_string_function, can_display_unicode_string_arg);
246 }
getName(size_t index) const247 const ExpressionName &ExpressionItem::getName(size_t index) const {
248 if(index > 0 && index <= names.size()) return names[index - 1];
249 return empty_expression_name;
250 }
setName(const ExpressionName & ename,size_t index,bool force)251 void ExpressionItem::setName(const ExpressionName &ename, size_t index, bool force) {
252 if(index < 1) addName(ename, 1);
253 if(index > names.size()) addName(ename);
254 if(b_registered && names[index - 1].name != ename.name) {
255 names[index - 1] = ename;
256 names[index - 1].name = CALCULATOR->getName(ename.name, this, force);
257 b_changed = true;
258 CALCULATOR->nameChanged(this);
259 } else if(ename != names[index - 1]) {
260 names[index - 1] = ename;
261 b_changed = true;
262 }
263 }
setName(string sname,size_t index,bool force)264 void ExpressionItem::setName(string sname, size_t index, bool force) {
265 if(index < 1) addName(sname, 1);
266 if(index > names.size()) addName(sname);
267 if(b_registered && names[index - 1].name != sname) {
268 names[index - 1].name = CALCULATOR->getName(sname, this, force);
269 b_changed = true;
270 CALCULATOR->nameChanged(this);
271 } else if(sname != names[index - 1].name) {
272 names[index - 1].name = sname;
273 b_changed = true;
274 }
275 }
addName(const ExpressionName & ename,size_t index,bool force)276 void ExpressionItem::addName(const ExpressionName &ename, size_t index, bool force) {
277 if(index < 1 || index > names.size()) {
278 names.push_back(ename);
279 index = names.size();
280 } else {
281 names.insert(names.begin() + (index - 1), ename);
282 }
283 if(b_registered) {
284 names[index - 1].name = CALCULATOR->getName(names[index - 1].name, this, force);
285 CALCULATOR->nameChanged(this);
286 }
287 b_changed = true;
288 }
addName(string sname,size_t index,bool force)289 void ExpressionItem::addName(string sname, size_t index, bool force) {
290 if(index < 1 || index > names.size()) {
291 names.push_back(ExpressionName(sname));
292 index = names.size();
293 } else {
294 names.insert(names.begin() + (index - 1), ExpressionName(sname));
295 }
296 if(b_registered) {
297 names[index - 1].name = CALCULATOR->getName(names[index - 1].name, this, force);
298 CALCULATOR->nameChanged(this);
299 }
300 b_changed = true;
301 }
countNames() const302 size_t ExpressionItem::countNames() const {
303 return names.size();
304 }
clearNames()305 void ExpressionItem::clearNames() {
306 if(names.size() > 0) {
307 names.clear();
308 if(b_registered) {
309 CALCULATOR->nameChanged(this);
310 }
311 b_changed = true;
312 }
313 }
clearNonReferenceNames()314 void ExpressionItem::clearNonReferenceNames() {
315 bool b = false;
316 for(vector<ExpressionName>::iterator it = names.begin(); it != names.end(); ++it) {
317 if(!it->reference) {
318 it = names.erase(it);
319 --it;
320 b = true;
321 }
322 }
323 if(b) {
324 if(b_registered) {
325 CALCULATOR->nameChanged(this);
326 }
327 b_changed = true;
328 }
329 }
removeName(size_t index)330 void ExpressionItem::removeName(size_t index) {
331 if(index > 0 && index <= names.size()) {
332 names.erase(names.begin() + (index - 1));
333 if(b_registered) {
334 CALCULATOR->nameChanged(this);
335 }
336 b_changed = true;
337 }
338 }
hasName(const string & sname,bool case_sensitive) const339 size_t ExpressionItem::hasName(const string &sname, bool case_sensitive) const {
340 for(size_t i = 0; i < names.size(); i++) {
341 if(case_sensitive && names[i].case_sensitive && sname == names[i].name) return i + 1;
342 if((!case_sensitive || !names[i].case_sensitive) && equalsIgnoreCase(names[i].name, sname)) return i + 1;
343 }
344 return 0;
345 }
hasNameCaseSensitive(const string & sname) const346 size_t ExpressionItem::hasNameCaseSensitive(const string &sname) const {
347 for(size_t i = 0; i < names.size(); i++) {
348 if(sname == names[i].name) return i + 1;
349 }
350 return 0;
351 }
findName(int abbreviation,int use_unicode,int plural,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const352 const ExpressionName &ExpressionItem::findName(int abbreviation, int use_unicode, int plural, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
353 for(size_t i = 0; i < names.size(); i++) {
354 if((abbreviation < 0 || names[i].abbreviation == abbreviation) && (use_unicode < 0 || names[i].unicode == use_unicode) && (plural < 0 || names[i].plural == plural) && (!names[i].unicode || !can_display_unicode_string_function || ((*can_display_unicode_string_function) (names[i].name.c_str(), can_display_unicode_string_arg)))) return names[i];
355 }
356 return empty_expression_name;
357 }
358
category() const359 const string &ExpressionItem::category() const {
360 return scat;
361 }
setCategory(string cat_)362 void ExpressionItem::setCategory(string cat_) {
363 remove_blank_ends(cat_);
364 if(scat != cat_) {
365 scat = cat_;
366 b_changed = true;
367 }
368 }
isLocal() const369 bool ExpressionItem::isLocal() const {
370 return b_local;
371 }
setLocal(bool is_local,int will_be_active)372 bool ExpressionItem::setLocal(bool is_local, int will_be_active) {
373 if(b_builtin) return false;
374 if(is_local != b_local) {
375 if(!b_local) {
376 bool was_active = b_active;
377 b_active = false;
378 ExpressionItem *item = copy();
379 b_local = is_local;
380 b_active = was_active;
381 if(will_be_active) {
382 setActive(true);
383 } else if(will_be_active == 0) {
384 setActive(false);
385 }
386 CALCULATOR->addExpressionItem(item);
387 if(was_active != item->isActive()) {
388 item->setChanged(true);
389 }
390 if(was_active && will_be_active == 0) {
391 item->setActive(true);
392 }
393 }
394 b_local = is_local;
395 } else if(will_be_active >= 0) {
396 setActive(will_be_active);
397 }
398 return true;
399 }
isBuiltin() const400 bool ExpressionItem::isBuiltin() const {
401 return b_builtin;
402 }
hasChanged() const403 bool ExpressionItem::hasChanged() const {
404 return b_changed;
405 }
setChanged(bool has_changed)406 void ExpressionItem::setChanged(bool has_changed) {
407 b_changed = has_changed;
408 }
isApproximate() const409 bool ExpressionItem::isApproximate() const {
410 return b_approx;
411 }
setApproximate(bool is_approx)412 void ExpressionItem::setApproximate(bool is_approx) {
413 if(is_approx != b_approx) {
414 b_approx = is_approx;
415 if(!b_approx) i_precision = -1;
416 b_changed = true;
417 }
418 }
precision() const419 int ExpressionItem::precision() const {
420 return i_precision;
421 }
setPrecision(int prec)422 void ExpressionItem::setPrecision(int prec) {
423 if(i_precision != prec) {
424 i_precision = prec;
425 if(i_precision >= 0) b_approx = true;
426 b_changed = true;
427 }
428 }
isActive() const429 bool ExpressionItem::isActive() const {
430 return b_active;
431 }
setActive(bool is_active)432 void ExpressionItem::setActive(bool is_active) {
433 if(is_active != b_active) {
434 b_active = is_active;
435 if(b_registered) {
436 if(is_active) {
437 CALCULATOR->expressionItemActivated(this);
438 } else {
439 CALCULATOR->expressionItemDeactivated(this);
440 }
441 }
442 b_changed = true;
443 }
444 }
isHidden() const445 bool ExpressionItem::isHidden() const {
446 return b_hidden;
447 }
setHidden(bool is_hidden)448 void ExpressionItem::setHidden(bool is_hidden) {
449 if(is_hidden != b_hidden) {
450 b_hidden = is_hidden;
451 b_changed = true;
452 }
453 }
454
refcount() const455 int ExpressionItem::refcount() const {
456 return i_ref;
457 }
ref()458 void ExpressionItem::ref() {
459 i_ref++;
460 }
unref()461 void ExpressionItem::unref() {
462 i_ref--;
463 if(b_destroyed && i_ref <= 0) {
464 delete this;
465 }
466 }
ref(ExpressionItem * o)467 void ExpressionItem::ref(ExpressionItem *o) {
468 i_ref++;
469 v_refs.push_back(o);
470 }
unref(ExpressionItem * o)471 void ExpressionItem::unref(ExpressionItem *o) {
472 for(size_t i = 0; i < v_refs.size(); i++) {
473 if(v_refs[i] == o) {
474 i_ref--;
475 v_refs.erase(v_refs.begin() + i);
476 break;
477 }
478 }
479 }
getReferencer(size_t index) const480 ExpressionItem *ExpressionItem::getReferencer(size_t index) const {
481 if(index > 0 && index <= v_refs.size()) {
482 return v_refs[index - 1];
483 }
484 return NULL;
485 }
changeReference(ExpressionItem *,ExpressionItem *)486 bool ExpressionItem::changeReference(ExpressionItem*, ExpressionItem*) {
487 return false;
488 }
id() const489 int ExpressionItem::id() const {
490 return 0;
491 }
492