1 /***************************************************************************
2 * 2007-2021 by Peter Semiletov *
3 * peter.semiletov@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 **************************************************************************/
20
21 /* some code by
22 Copyright (C) 2006-2008 Trolltech ASA. All rights reserved.
23 */
24
25 /*
26 code from qPEditor:
27 Copyright (C) 2007 by Michael Protasov, mik-protasov@anyqsoft.com
28 */
29
30 /*
31 Diego Iastrubni <elcuco@kde.org> //some GPL'ed code from new-editor-diego-3,
32 found on qtcentre forum
33 */
34
35 /*
36 code from qwriter:
37 * Copyright (C) 2009 by Gancov Kostya *
38 * kossne@mail.ru *
39 */
40
41 #include <bitset>
42 #include <algorithm>
43
44 #include <QTextCodec>
45 #include <QApplication>
46 #include <QClipboard>
47 #include <QSettings>
48 #include <QLabel>
49 #include <QPainter>
50 #include <QDebug>
51 #include <QUrl>
52 #include <QDir>
53 #include <QXmlStreamReader>
54 #include <QMimeData>
55 #include <QFile>
56
57 #include <QTimer>
58
59 #include "document.h"
60 #include "utils.h"
61 #include "gui_utils.h"
62 #include "textproc.h"
63
64 #define SK_A 38
65 #define SK_D 40
66 #define SK_W 25
67 #define SK_S 39
68 #define SK_E 26
69 #define SK_C 54
70
71
72 QHash <QString, QString> global_palette;
73 QSettings *settings;
74 QMenu *menu_current_files;
75 int recent_list_max_items;
76 bool b_recent_off;
77 bool b_destroying_all;
78
79
text_get_bookmarks(const QString & s,const QString & sstart,const QString & send)80 QStringList text_get_bookmarks (const QString &s, const QString &sstart, const QString &send)
81 {
82 QStringList result;
83
84 int c = s.size();
85 int i = 0;
86
87 while (i < c)
88 {
89 int start = s.indexOf (sstart, i, Qt::CaseInsensitive);
90
91 if (start == -1)
92 break;
93
94 int end = s.indexOf (send, start + sstart.length());
95 if (end == -1)
96 break;
97
98 result.prepend (s.mid (start + sstart.length(), (end - start) - send.length()));
99
100 i = end + 1;
101 }
102
103 return result;
104 }
105
106
tformat_from_style(const QString & fontstyle,const QString & color,int darker_val)107 QTextCharFormat tformat_from_style (const QString &fontstyle, const QString &color, int darker_val)
108 {
109 QTextCharFormat tformat;
110 tformat.setForeground (QBrush (QColor (color).darker (darker_val)));
111
112 if (fontstyle.isEmpty())
113 return tformat;
114
115 if (fontstyle.contains ("bold"))
116 tformat.setFontWeight (QFont::Bold);
117
118 if (fontstyle.contains ("italic"))
119 tformat.setFontItalic (true);
120
121 if (fontstyle.contains ("underline"))
122 tformat.setFontUnderline (true);
123
124 if (fontstyle.contains ("strikeout"))
125 tformat.setFontStrikeOut (true);
126
127 return tformat;
128 }
129
130
CSyntaxHighlighter(QTextDocument * parent,CDocument * doc,const QString & fname)131 CSyntaxHighlighter::CSyntaxHighlighter (QTextDocument *parent, CDocument *doc, const QString &fname): QSyntaxHighlighter (parent)
132 {
133 document = doc;
134 casecare = true;
135 }
136
137
138 #if QT_VERSION < 0x050000
139
CSyntaxHighlighterQRegExp(QTextDocument * parent,CDocument * doc,const QString & fname)140 CSyntaxHighlighterQRegExp::CSyntaxHighlighterQRegExp (QTextDocument *parent, CDocument *doc, const QString &fname):
141 CSyntaxHighlighter (parent, doc, fname)
142 {
143 document = doc;
144 load_from_xml (fname);
145 }
146
147
load_from_xml(const QString & fname)148 void CSyntaxHighlighterQRegExp::load_from_xml (const QString &fname)
149 {
150 if (! file_exists (fname))
151 return;
152
153 cs = Qt::CaseSensitive;
154
155 comment_start_expr = make_pair (QRegExp(), false);
156 comment_end_expr = make_pair (QRegExp(), false);
157
158 QString temp = qstring_load (fname);
159 if (temp.isEmpty())
160 return;
161
162 int darker_val = settings->value ("darker_val", 100).toInt();
163
164 QXmlStreamReader xml (temp);
165
166 while (! xml.atEnd())
167 {
168 xml.readNext();
169
170 QString tag_name = xml.name().toString().toLower();
171
172 if (xml.isStartElement())
173 {
174 /*if (tag_name == "document")
175 {
176 exts = xml.attributes().value ("exts").toString();
177 langs = xml.attributes().value ("langs").toString();
178 }*/
179
180 if (tag_name == "item")
181 {
182 QString attr_type = xml.attributes().value ("type").toString();
183 QString attr_name = xml.attributes().value ("name").toString();
184
185 if (attr_name == "options")
186 {
187 QString s_casecare = xml.attributes().value ("casecare").toString();
188 if (! s_casecare.isEmpty())
189 if (s_casecare == "0" || s_casecare == "false")
190 casecare = false;
191
192 if (! casecare)
193 cs = Qt::CaseInsensitive;
194 }
195
196 if (attr_type == "keywords")
197 {
198 QString color = hash_get_val (global_palette, xml.attributes().value ("color").toString(), "darkBlue");
199 QTextCharFormat fmt = tformat_from_style (xml.attributes().value ("fontstyle").toString(), color, darker_val);
200
201 QString element = xml.readElementText().trimmed().remove('\n');
202 if (element.isEmpty())
203 continue;
204
205 QRegExp rg (element, cs);
206
207 if (! rg.isValid())
208 qDebug() << "! valid " << rg.pattern();
209 else
210 hl_rules.push_back (make_pair (rg, fmt));
211
212 } //keywords
213 else
214 if (attr_type == "item")
215 {
216 QString color = hash_get_val (global_palette, xml.attributes().value ("color").toString(), "darkBlue");
217 QTextCharFormat fmt = tformat_from_style (xml.attributes().value ("fontstyle").toString(), color, darker_val);
218 QString element = xml.readElementText().trimmed().remove('\n');
219 if (element.isEmpty())
220 continue;
221
222 QRegExp rg (element, cs);
223 if (rg.isValid())
224 hl_rules.push_back (make_pair (rg, fmt));
225 }
226 else
227 if (attr_type == "mcomment-start")
228 {
229 QString color = hash_get_val (global_palette, xml.attributes().value ("color").toString(), "gray");
230 QTextCharFormat fmt = tformat_from_style (xml.attributes().value ("color").toString(), color, darker_val);
231
232 fmt_multi_line_comment = fmt;
233 QString element = xml.readElementText().trimmed().remove('\n');
234 if (! element.isEmpty())
235 //commentStartExpression = QRegExp (element, cs, QRegExp::RegExp);
236 {
237 comment_start_expr.first = QRegExp (element, cs, QRegExp::RegExp);
238 comment_start_expr.second = true;
239 }
240
241 }
242 else
243 if (attr_type == "mcomment-end")
244 {
245 QString element = xml.readElementText().trimmed().remove('\n');
246 if (! element.isEmpty())
247 //commentEndExpression = QRegExp (element, cs, QRegExp::RegExp);
248 {
249 comment_end_expr.first = QRegExp (element, cs, QRegExp::RegExp);
250 comment_end_expr.second = true;
251 }
252
253 }
254 else
255 if (attr_type == "comment")
256 {
257 QString element = xml.readElementText().trimmed().remove('\n');
258 if (element.isEmpty())
259 continue;
260
261 if (xml.attributes().value ("name").toString() == "cm_mult")
262 comment_mult = element;
263 else
264 if (xml.attributes().value ("name").toString() == "cm_single")
265 comment_single = element;
266 }
267 }//item
268
269 }//is start
270
271 if (xml.hasError())
272 qDebug() << "xml parse error";
273
274 } //cycle
275 }
276
277
highlightBlock(const QString & text)278 void CSyntaxHighlighterQRegExp::highlightBlock (const QString &text)
279 {
280
281 if (hl_rules.size() == 0)
282 return;
283 /*
284 for (auto &p: hl_rules)
285 {
286 int index = text.indexOf (p.first);
287
288 while (index >= 0)
289 {
290 int length = p.first.matchedLength();
291 if (length == 0)
292 continue;
293
294 setFormat (index, length, p.second);
295 index = text.indexOf (p.first, index + length);
296 }
297 }*/
298
299 for (vector <pair <QRegExp, QTextCharFormat> >::iterator p = hl_rules.begin(); p != hl_rules.end(); ++p)
300 {
301 int index = text.indexOf (p->first);
302
303 while (index >= 0)
304 {
305 int length = p->first.matchedLength();
306 if (length == 0)
307 continue;
308
309 setFormat (index, length, p->second);
310 index = text.indexOf (p->first, index + length);
311 }
312 }
313
314
315 if (! comment_start_expr.second && ! comment_end_expr.second)
316 return;
317
318
319 setCurrentBlockState (0);
320
321 int startIndex = 0;
322
323 //if (commentStartExpression.isEmpty() || commentEndExpression.isEmpty())
324 // return;
325
326 if (previousBlockState() != 1)
327 startIndex = text.indexOf (comment_start_expr.first);
328
329 while (startIndex >= 0)
330 {
331 int endIndex = comment_end_expr.first.indexIn (text, startIndex);
332
333 int commentLength;
334
335 if (endIndex == -1)
336 {
337 setCurrentBlockState (1);
338 commentLength = text.length() - startIndex;
339 }
340 else
341 commentLength = endIndex - startIndex + comment_end_expr.first.matchedLength();
342
343 setFormat (startIndex, commentLength, fmt_multi_line_comment);
344 startIndex = text.indexOf (comment_start_expr.first, startIndex + commentLength);
345 }
346 }
347
348 #endif
349
350
351 #if QT_VERSION >= 0x050000
352
CSyntaxHighlighterQRegularExpression(QTextDocument * parent,CDocument * doc,const QString & fname)353 CSyntaxHighlighterQRegularExpression::CSyntaxHighlighterQRegularExpression (QTextDocument *parent, CDocument *doc, const QString &fname):
354 CSyntaxHighlighter (parent, doc, fname)
355 {
356 document = doc;
357 load_from_xml (fname);
358 }
359
360
load_from_xml(const QString & fname)361 void CSyntaxHighlighterQRegularExpression::load_from_xml (const QString &fname)
362 {
363 if (! file_exists (fname))
364 return;
365
366 casecare = true;
367
368 comment_start_expr = make_pair (QRegularExpression(), false);
369 comment_end_expr = make_pair (QRegularExpression(), false);
370
371 QString temp = qstring_load (fname);
372 if (temp.isEmpty())
373 return;
374
375 int darker_val = settings->value ("darker_val", 100).toInt();
376
377 QXmlStreamReader xml (temp);
378
379 while (! xml.atEnd())
380 {
381 xml.readNext();
382
383 QString tag_name = xml.name().toString().toLower();
384
385 if (xml.isStartElement())
386 {
387 if (tag_name == "item")
388 {
389 QString attr_type = xml.attributes().value ("type").toString();
390 QString attr_name = xml.attributes().value ("name").toString();
391
392 if (attr_name == "options")
393 {
394 QString s_casecare = xml.attributes().value ("casecare").toString();
395 if (! s_casecare.isEmpty())
396 if (s_casecare == "0" || s_casecare == "false")
397 casecare = false;
398
399 if (! casecare)
400 pattern_opts = pattern_opts | QRegularExpression::CaseInsensitiveOption;
401 }
402
403 if (attr_type == "keywords")
404 {
405 QString color = hash_get_val (global_palette, xml.attributes().value ("color").toString(), "darkBlue");
406 QTextCharFormat fmt = tformat_from_style (xml.attributes().value ("fontstyle").toString(), color, darker_val);
407
408 QString element = xml.readElementText().trimmed().remove('\n');
409 if (element.isEmpty())
410 continue;
411
412 QRegularExpression rg = QRegularExpression (element, pattern_opts);
413
414 if (! rg.isValid())
415 qDebug() << "! valid " << rg.pattern();
416 else
417 hl_rules.push_back (make_pair (rg, fmt));
418
419 } //keywords
420 else
421 if (attr_type == "item")
422 {
423 QString color = hash_get_val (global_palette, xml.attributes().value ("color").toString(), "darkBlue");
424 QTextCharFormat fmt = tformat_from_style (xml.attributes().value ("fontstyle").toString(), color, darker_val);
425
426 QString element = xml.readElementText().trimmed().remove('\n');
427 if (element.isEmpty())
428 continue;
429
430 QRegularExpression rg = QRegularExpression (element, pattern_opts);
431 if (! rg.isValid())
432 qDebug() << "! valid " << rg.pattern();
433 else
434 hl_rules.push_back (make_pair (rg, fmt));
435 }
436 else
437 if (attr_type == "mcomment-start")
438 {
439 QString color = hash_get_val (global_palette, xml.attributes().value ("color").toString(), "gray");
440 QTextCharFormat fmt = tformat_from_style (xml.attributes().value ("color").toString(), color, darker_val);
441
442 fmt_multi_line_comment = fmt;
443
444 QString element = xml.readElementText().trimmed().remove('\n');
445 if (element.isEmpty())
446 continue;
447
448 QRegularExpression rg = QRegularExpression (element, pattern_opts);
449 if (! rg.isValid())
450 qDebug() << "! valid " << rg.pattern();
451 else
452 {
453 comment_start_expr.first = rg;
454 comment_start_expr.second = true;
455 }
456 }
457 else
458 if (attr_type == "mcomment-end")
459 {
460 QString element = xml.readElementText().trimmed().remove('\n');
461 if (element.isEmpty())
462 continue;
463
464 QRegularExpression rg = QRegularExpression (element, pattern_opts);
465 if (! rg.isValid())
466 qDebug() << "! valid " << rg.pattern();
467 else
468 {
469 comment_end_expr.first = rg;
470 comment_end_expr.second = true;
471 }
472
473 }
474 else
475 if (attr_type == "comment")
476 {
477 if (xml.attributes().value ("name").toString() == "cm_mult")
478 comment_mult = xml.readElementText().trimmed();
479 else
480 if (xml.attributes().value ("name").toString() == "cm_single")
481 comment_single = xml.readElementText().trimmed();
482 }
483
484 }//item
485
486 }//end of "is start"
487
488 if (xml.hasError())
489 qDebug() << "xml parse error";
490
491 } //cycle
492 }
493
494
highlightBlock(const QString & text)495 void CSyntaxHighlighterQRegularExpression::highlightBlock (const QString &text)
496 {
497 if (hl_rules.size() == 0)
498 return;
499
500 for (vector <pair <QRegularExpression, QTextCharFormat> >::iterator p = hl_rules.begin(); p != hl_rules.end(); ++p)
501 {
502 QRegularExpressionMatch m = p->first.match (text);
503
504 int index = m.capturedStart();
505
506 while (index >= 0)
507 {
508 int length = m.capturedLength();
509 if (length == 0)
510 continue;
511
512 setFormat (index, length, p->second);
513 m = p->first.match (text, index + length);
514 index = m.capturedStart();
515 }
516 }
517 /*
518 for (const auto& p: hl_rules)
519 {
520 QRegularExpressionMatch m = p.first.match (text);
521
522 int index = m.capturedStart();
523
524 while (index >= 0)
525 {
526 int length = m.capturedLength();
527 if (length == 0)
528 continue;
529
530 setFormat (index, length, p.second);
531 m = p.first.match (text, index + length);
532 index = m.capturedStart();
533 }
534 }
535 */
536
537 if (! comment_start_expr.second && ! comment_end_expr.second)
538 return;
539
540 setCurrentBlockState (0);
541
542 int startIndex = 0;
543
544 QRegularExpressionMatch m_start = comment_start_expr.first.match (text);
545
546
547 if (previousBlockState() != 1)
548 startIndex = m_start.capturedStart();
549
550 while (startIndex >= 0)
551 {
552 QRegularExpressionMatch m_end = comment_end_expr.first.match (text, startIndex);
553
554 int endIndex = m_end.capturedStart();
555
556 int commentLength;
557
558 if (endIndex == -1)
559 {
560 setCurrentBlockState (1);
561 commentLength = text.length() - startIndex;
562 }
563 else
564 commentLength = endIndex - startIndex + m_end.capturedLength();
565
566 setFormat (startIndex, commentLength, fmt_multi_line_comment);
567
568 m_start = comment_start_expr.first.match (text, startIndex + commentLength);
569
570 startIndex = m_start.capturedStart();
571 }
572 }
573 #endif
574
575
createMimeDataFromSelection() const576 QMimeData* CDocument::createMimeDataFromSelection() const
577 {
578 if (has_rect_selection())
579 {
580 QMimeData *md = new QMimeData;
581 md->setText (rect_sel_get());
582 return md;
583 }
584
585 return QPlainTextEdit::createMimeDataFromSelection();
586 }
587
588
canInsertFromMimeData(const QMimeData * source) const589 bool CDocument::canInsertFromMimeData (const QMimeData *source) const
590 {
591 // if (source->hasFormat ("text/uri-list"))
592 // return true;
593 //else
594 return true;
595 }
596
597
insertFromMimeData(const QMimeData * source)598 void CDocument::insertFromMimeData (const QMimeData *source)
599 {
600 QString fname;
601 QFileInfo info;
602
603 bool b_ins_plain_text = ! source->hasUrls();
604 if (source->hasUrls() && source->urls().at(0).scheme() != "file")
605 b_ins_plain_text = true;
606
607 if (b_ins_plain_text)
608 {
609 QPlainTextEdit::insertFromMimeData (source);
610 return;
611 }
612
613 QList<QUrl> l = source->urls();
614
615 for (QList <QUrl>::iterator u = l.begin(); u != l.end(); ++u)
616 {
617 fname = u->toLocalFile();
618 info.setFile(fname);
619 if (info.isFile())
620 holder->open_file (fname, "UTF-8");
621 }
622 }
623
624
paintEvent(QPaintEvent * event)625 void CDocument::paintEvent (QPaintEvent *event)
626 {
627 if (draw_margin || highlight_current_line)
628 {
629 QPainter painter (viewport());
630
631 if (highlight_current_line)
632 {
633 QRect r = cursorRect();
634 r.setX (0);
635 r.setWidth (viewport()->width());
636 painter.fillRect (r, QBrush (current_line_color));
637 }
638
639 if (draw_margin)
640 {
641 QPen pen = painter.pen();
642 pen.setColor (margin_color);
643 painter.setPen (pen);
644 painter.drawLine (margin_x, 0, margin_x, viewport()->height());
645 }
646 }
647
648 QPlainTextEdit::paintEvent (event);
649 }
650
651
keyPressEvent(QKeyEvent * event)652 void CDocument::keyPressEvent (QKeyEvent *event)
653 {
654 // qDebug() << event->nativeScanCode() ;
655
656 // qDebug() << int_to_binary (event->nativeModifiers());
657 // std::bitset<32> btst (event->nativeModifiers());
658
659 /*
660 for (std::size_t i = 0; i < btst.size(); ++i) {
661 qDebug() << "btst[" << i << "]: " << btst[i];
662 }
663 */
664
665 //LSHIFT = 0
666 //LCTRL = 2
667 //LALT = 3
668 //LWIN = 6
669
670 if (settings->value ("wasd", "0").toBool())
671 {
672 bitset <32> btst (event->nativeModifiers());
673 QTextCursor cr = textCursor();
674
675 QTextCursor::MoveMode m = QTextCursor::MoveAnchor;
676
677 if (btst[3] == 1 || btst[6] == 1) //LALT or LWIN
678 {
679 int visible_lines;
680
681 if (btst[6] == 1)
682 m = QTextCursor::KeepAnchor;
683
684 switch (event->nativeScanCode())
685 {
686 case SK_W:
687 cr.movePosition (QTextCursor::Up, m);
688 setTextCursor (cr);
689 return;
690
691 case SK_S:
692 cr.movePosition (QTextCursor::Down, m);
693 setTextCursor (cr);
694 return;
695
696 case SK_A:
697 cr.movePosition (QTextCursor::Left, m);
698 setTextCursor (cr);
699 return;
700
701 case SK_D:
702 cr.movePosition (QTextCursor::Right, m);
703 setTextCursor (cr);
704 return;
705
706 case SK_E:
707 visible_lines = height() / fontMetrics().height();
708 cr.movePosition (QTextCursor::Down, m, visible_lines);
709 setTextCursor (cr);
710 return;
711
712 case SK_C:
713 visible_lines = height() / fontMetrics().height();
714 cr.movePosition (QTextCursor::Up, m, visible_lines);
715 setTextCursor (cr);
716 return;
717 }
718 }
719 }
720
721
722 if (auto_indent && event->key() == Qt::Key_Return)
723 {
724 calc_auto_indent();
725 QPlainTextEdit::keyPressEvent (event);
726 textCursor().insertText (indent_val);
727 return;
728 }
729
730 if (event->key() == Qt::Key_Tab)
731 {
732 indent();
733 event->accept();
734 return;
735 }
736
737 if (event->key() == Qt::Key_Backtab)
738 {
739 un_indent();
740 event->accept();
741 return;
742 }
743
744 if (event->key() == Qt::Key_Insert)
745 {
746 setOverwriteMode (! overwriteMode());
747 event->accept();
748 return;
749 }
750
751 QPlainTextEdit::keyPressEvent (event);
752 }
753
754
resizeEvent(QResizeEvent * e)755 void CDocument::resizeEvent (QResizeEvent *e)
756 {
757 QPlainTextEdit::resizeEvent (e);
758 QRect cr = contentsRect();
759 line_num_area->setGeometry (QRect (cr.left(), cr.top(), line_number_area_width(), cr.height()));
760 }
761
762
wheelEvent(QWheelEvent * e)763 void CDocument::wheelEvent (QWheelEvent *e)
764 {
765 if (e->modifiers() & Qt::ControlModifier)
766 {
767 #if QT_VERSION < 0x050000
768 const int delta = e->delta();
769 #else
770 const int delta = e->angleDelta().y();
771 #endif
772 QFont f = font();
773 int sz = f.pointSize();
774
775 if (delta > 0)
776 sz++;
777
778 if (delta < 0)
779 sz--;
780
781 f.setPointSize(sz);
782 setFont(f);
783
784 return;
785 }
786
787 QPlainTextEdit::wheelEvent(e);
788 }
789
790
CDocument(CDox * hldr,QWidget * parent)791 CDocument::CDocument (CDox *hldr, QWidget *parent): QPlainTextEdit (parent)
792 {
793 holder = hldr;
794
795 highlighter = 0;
796 tab_page = 0;
797 markup_mode = "HTML";
798 file_name = tr ("new[%1]").arg (QTime::currentTime().toString ("hh-mm-ss"));
799 cursor_xy_visible = true;
800 charset = "UTF-8";
801 text_to_search = "";
802 position = 0;
803 margin_pos = 72;
804 margin_x = brace_width * margin_pos;
805 draw_margin = false;
806 hl_brackets = false;
807 auto_indent = false;
808 tab_sp_width = 8;
809 spaces_instead_of_tabs = true;
810 highlight_current_line = false;
811
812 #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
813 eol = "\r\n";
814 #elif defined(Q_OS_UNIX)
815 eol = "\n";
816 #endif
817
818 rect_sel_reset();
819 setup_brace_width();
820
821 line_num_area = new CLineNumberArea (this);
822
823 connect (this, SIGNAL(selectionChanged()), this, SLOT(slot_selectionChanged()));
824 connect (this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth()));
825 connect (this, SIGNAL(updateRequest(QRect, int)), this, SLOT(updateLineNumberArea(QRect, int)));
826 connect (this, SIGNAL(cursorPositionChanged()), this, SLOT(cb_cursorPositionChanged()));
827
828 updateLineNumberAreaWidth();
829
830 document()->setUseDesignMetrics (true);
831
832 QString s_sel_back_color = hash_get_val (global_palette, "sel-background", "black");
833 QString s_sel_text_color = hash_get_val (global_palette, "sel-text", "white");
834
835 int darker_val = settings->value ("darker_val", 100).toInt();
836
837 sel_text_color = QColor (s_sel_text_color).darker(darker_val).name();
838 sel_back_color = QColor (s_sel_back_color).darker(darker_val).name();
839 current_line_color = QColor (hash_get_val (global_palette, "cur_line_color",
840 "#EEF6FF")).darker (settings->value ("darker_val", 100).toInt()).name();
841
842 holder->items.push_back (this);
843 int tab_index = holder->tab_widget->addTab (this, file_name);
844 tab_page = holder->tab_widget->widget (tab_index);
845
846 /* show_tabs_and_spaces = true;
847
848 QTextOption option = document()->defaultTextOption();
849 if (show_tabs_and_spaces)
850 option.setFlags(option.flags() | QTextOption::ShowTabsAndSpaces);
851 else
852 option.setFlags(option.flags() & ~QTextOption::ShowTabsAndSpaces);
853
854 option.setFlags(option.flags() | QTextOption::AddSpaceForLineAndParagraphSeparators);
855 document()->setDefaultTextOption(option);
856
857
858 ---
859 set dots color, put to hl init
860 spaceFormat = QtGui.QTextCharFormat()
861 spaceFormat.setForeground(QtCore.Qt.red)
862 self.highlightingRules.append((QtCore.QRegExp(" "), spaceFormat))
863 */
864 setFocus (Qt::OtherFocusReason);
865 }
866
867
~CDocument()868 CDocument::~CDocument()
869 {
870 if (holder->autosave_files.contains (file_name))
871 {
872 file_save_with_name (file_name, charset);
873 document()->setModified (false);
874 }
875
876 if (file_name.endsWith (".notes") && document()->isModified())
877 file_save_with_name_plain (file_name);
878 else
879 if (file_name.startsWith (holder->dir_config) && document()->isModified())
880 file_save_with_name_plain (file_name);
881 else
882 if (document()->isModified() && file_exists (file_name))
883 if (QMessageBox::warning (0, "TEA",
884 tr ("%1 has been modified.\n"
885 "Do you want to save your changes?").arg (file_name),
886 QMessageBox::Yes | QMessageBox::Default,
887 QMessageBox::No | QMessageBox::Escape) == QMessageBox::Yes)
888 file_save_with_name (file_name, charset);
889
890 if (! file_name.startsWith (holder->dir_config) && ! file_name.endsWith (".notes"))
891 {
892 holder->add_to_recent (this);
893 holder->update_recent_menu();
894 }
895
896 if (file_name.startsWith (holder->todo.dir_days))
897 holder->todo.load_dayfile();
898
899 QMainWindow *w = qobject_cast <QMainWindow *> (holder->parent_wnd);
900 w->setWindowTitle ("");
901
902 int i = holder->tab_widget->indexOf (tab_page);
903 if (i != -1)
904 holder->tab_widget->removeTab (i);
905 }
906
907
get() const908 QString CDocument::get() const
909 {
910 return textCursor().selectedText();
911 }
912
913
put(const QString & value)914 void CDocument::put (const QString &value)
915 {
916 textCursor().insertText (value);
917 }
918
919
file_open(const QString & fileName,const QString & codec)920 bool CDocument::file_open (const QString &fileName, const QString &codec)
921 {
922 CTio *tio = holder->tio_handler.get_for_fname (fileName);
923
924 if (! tio)
925 return false;
926
927 if (fileName.contains (holder->dir_config))
928 tio->charset = "UTF-8";
929 else
930 tio->charset = codec;
931
932 if (! tio->load (fileName))
933 {
934 holder->log->log (tr ("cannot open %1 because of: %2")
935 .arg (fileName)
936 .arg (tio->error_string));
937 return false;
938 }
939
940 setPlainText (tio->data);
941
942 charset = tio->charset;
943 eol = tio->eol;
944 file_name = fileName;
945
946 holder->update_project (file_name);
947
948 set_tab_caption (QFileInfo (file_name).fileName());
949 set_hl();
950 set_markup_mode();
951 document()->setModified (false);
952
953 holder->log->log (tr ("%1 is open").arg (file_name));
954
955 QMutableListIterator <QString> i (holder->recent_files);
956
957 while (i.hasNext())
958 {
959 QStringList lt = i.next().split (",");
960 if (lt.size() > 0)
961 if (lt.at(0) == file_name)
962 i.remove();
963 }
964
965 return true;
966 }
967
968
file_save_with_name(const QString & fileName,const QString & codec)969 bool CDocument::file_save_with_name (const QString &fileName, const QString &codec)
970 {
971 CTio *tio = holder->tio_handler.get_for_fname (fileName);
972
973 if (! tio)
974 return false;
975
976 if (fileName.contains (holder->dir_config))
977 tio->charset = "UTF-8";
978 else
979 tio->charset = codec;
980
981 tio->data = toPlainText();
982
983 if (eol != "\n")
984 tio->data.replace ("\n", eol);
985
986 if (! tio->save (fileName))
987 {
988 holder->log->log (tr ("cannot save %1 because of: %2")
989 .arg (fileName)
990 .arg (tio->error_string));
991 return false;
992 }
993
994 if (! b_destroying_all)
995 {
996 charset = tio->charset;
997 file_name = fileName;
998
999 set_tab_caption (QFileInfo (file_name).fileName());
1000
1001 holder->log->log (tr ("%1 is saved").arg (file_name));
1002
1003 update_title (settings->value ("full_path_at_window_title", 1).toBool());
1004 update_status();
1005
1006 document()->setModified (false);
1007
1008 holder->update_current_files_menu();
1009 holder->update_project (file_name);
1010 }
1011
1012 return true;
1013 }
1014
1015
file_save_with_name_plain(const QString & fileName)1016 bool CDocument::file_save_with_name_plain (const QString &fileName)
1017 {
1018 QFile file (fileName);
1019 if (! file.open (QFile::WriteOnly))
1020 return false;
1021
1022 QTextCodec *codec = QTextCodec::codecForName (charset.toUtf8().data());
1023 if (! codec)
1024 return false;
1025
1026 QByteArray ba = codec->fromUnicode (toPlainText());
1027
1028 file.write (ba);
1029 file.close();
1030
1031 holder->update_current_files_menu();
1032
1033 return true;
1034 }
1035
1036
get_tab_idx()1037 int CDocument::get_tab_idx()
1038 {
1039 return holder->tab_widget->indexOf (tab_page);
1040 }
1041
1042
get_triplex()1043 QString CDocument::get_triplex()
1044 {
1045 if (! file_exists (file_name))
1046 return QString ("");
1047
1048 QString s (file_name);
1049 s += ",";
1050 s += charset;
1051 s += ",";
1052 s += QString::number (textCursor().position());
1053 s += ",";
1054
1055 if (! get_word_wrap())
1056 s+="0";
1057 else
1058 s+="1";
1059
1060 return s;
1061 }
1062
1063
get_filename_at_cursor()1064 QString CDocument::get_filename_at_cursor()
1065 {
1066 if (textCursor().hasSelection())
1067 {
1068 QFileInfo nf (file_name);
1069 QDir cd (nf.absolutePath());
1070 return cd.cleanPath (cd.absoluteFilePath (textCursor().selectedText()));
1071 }
1072
1073 QString s = textCursor().block().text();
1074 if (s.isEmpty())
1075 return QString();
1076
1077 QString x;
1078
1079 if (markup_mode == "LaTeX")
1080 {
1081 int pos = textCursor().positionInBlock();
1082
1083 int end = s.indexOf ("}", pos);
1084 if (end == -1)
1085 return x;
1086
1087 int start = s.lastIndexOf ("{", pos);
1088 if (start == -1)
1089 return x;
1090
1091 x = s.mid (start + 1, end - (start + 1));
1092
1093 QFileInfo inf (file_name);
1094 QDir cur_dir (inf.absolutePath());
1095
1096 QString result = cur_dir.cleanPath (cur_dir.absoluteFilePath(x));
1097 if (file_exists (result))
1098 return result;
1099
1100 int i = x.lastIndexOf ("/");
1101 if (i < 0)
1102 i = x.lastIndexOf ("\\");
1103
1104 if (i < 0)
1105 return QString();
1106
1107 x = x.mid (i + 1);
1108
1109 result = cur_dir.cleanPath (cur_dir.absoluteFilePath(x));
1110 return result;
1111 }
1112 else
1113 {
1114 int pos = textCursor().positionInBlock();
1115
1116 int end = s.indexOf ("\"", pos);
1117 if (end == -1)
1118 return x;
1119
1120 int start = s.lastIndexOf ("\"", pos);
1121 if (start == -1)
1122 return x;
1123
1124 x = s.mid (start + 1, end - (start + 1));
1125
1126 if (x.startsWith("#"))
1127 return x;
1128
1129 QFileInfo inf (file_name);
1130 QDir cur_dir (inf.absolutePath());
1131
1132 return cur_dir.cleanPath (cur_dir.absoluteFilePath(x));
1133 }
1134 }
1135
1136
get_words()1137 QStringList CDocument::get_words()
1138 {
1139 QStringList result;
1140
1141 QTextCursor cr = textCursor();
1142
1143 QString text = toPlainText();
1144
1145 cr.setPosition (0);
1146 cr.movePosition (QTextCursor::Start, QTextCursor::MoveAnchor);
1147
1148 do
1149 {
1150 QChar c = text[cr.position()];
1151 if (char_is_bad (c))
1152 while (char_is_bad (c))
1153 {
1154 cr.movePosition (QTextCursor::NextCharacter);
1155 c = text[cr.position()];
1156 }
1157
1158 cr.movePosition (QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
1159 c = text[cr.position()];
1160
1161 QString stext = cr.selectedText();
1162
1163 if (! stext.isEmpty() && stext.endsWith ("\""))
1164 {
1165 cr.movePosition (QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
1166 stext = cr.selectedText();
1167 }
1168
1169 if (! stext.isEmpty())
1170 result.append (stext);
1171 }
1172 while (cr.movePosition (QTextCursor::NextWord));
1173
1174 return result;
1175 }
1176
1177
goto_pos(int pos)1178 void CDocument::goto_pos (int pos)
1179 {
1180 QTextCursor cr = textCursor();
1181 cr.setPosition (pos);
1182 setTextCursor (cr);
1183 }
1184
1185
set_tab_caption(const QString & fileName)1186 void CDocument::set_tab_caption (const QString &fileName)
1187 {
1188 holder->tab_widget->setTabText (get_tab_idx(), fileName);
1189 }
1190
1191
set_hl(bool mode_auto,const QString & theext)1192 void CDocument::set_hl (bool mode_auto, const QString &theext)
1193 {
1194 if (highlighter)
1195 delete highlighter;
1196
1197 highlighter = 0;
1198
1199 if (! settings->value ("hl_enabled", 1).toBool())
1200 return;
1201
1202 QString ext;
1203
1204 if (mode_auto)
1205 ext = file_get_ext (file_name);
1206 else
1207 ext = theext;
1208
1209 if (ext.isEmpty())
1210 return;
1211
1212 QString fname;
1213
1214 #if QT_VERSION >= 0x050000
1215
1216 for (vector <pair <QRegularExpression, QString> >::iterator p = holder->hl_files.begin(); p != holder->hl_files.end(); ++p)
1217 {
1218 if (p->first.isValid())
1219 if (p->first.match(file_name).hasMatch())
1220 {
1221 fname = p->second;
1222 break;
1223 }
1224 }
1225
1226 #else
1227 for (vector<pair<QRegExp, QString> >::iterator p = holder->hl_files.begin(); p != holder->hl_files.end(); ++p)
1228 {
1229 if (p->first.isValid())
1230 if (p->first.exactMatch(file_name))
1231 {
1232 fname = p->second;
1233 break;
1234 }
1235 }
1236
1237 #endif
1238
1239 if (fname.isEmpty() || ! file_exists (fname))
1240 return;
1241
1242 #if QT_VERSION >= 0x050000
1243 highlighter = new CSyntaxHighlighterQRegularExpression (document(), this, fname);
1244 #else
1245 highlighter = new CSyntaxHighlighterQRegExp (document(), this, fname);
1246 #endif
1247 }
1248
1249
set_markup_mode()1250 void CDocument::set_markup_mode()
1251 {
1252 markup_mode = holder->markup_mode;
1253
1254 QString e = file_get_ext (file_name);
1255 QString t = holder->markup_modes[e];
1256
1257 if (! t.isEmpty())
1258 markup_mode = t;
1259 }
1260
1261
insert_image(const QString & full_path)1262 void CDocument::insert_image (const QString &full_path)
1263 {
1264 put (get_insert_image (file_name, full_path, markup_mode));
1265 }
1266
1267
reload(const QString & enc)1268 void CDocument::reload (const QString &enc)
1269 {
1270 if (file_exists (file_name))
1271 file_open (file_name, enc);
1272 }
1273
1274
update_status()1275 void CDocument::update_status()
1276 {
1277 holder->l_charset->setText (charset);
1278
1279 if (! cursor_xy_visible)
1280 return;
1281
1282 int x = textCursor().position() - textCursor().block().position() + 1;
1283 int y = textCursor().block().blockNumber() + 1;
1284
1285 holder->l_status_bar->setText (QString ("%1%2[%3]").arg (
1286 QString::number (y), -10).arg (
1287 QString::number (x), -10).arg (
1288 QString::number (blockCount(), 10)));
1289
1290 holder->l_charset->setText (charset);
1291 }
1292
1293
update_title(bool fullname)1294 void CDocument::update_title (bool fullname)
1295 {
1296 if (! holder->parent_wnd)
1297 return;
1298
1299 QMainWindow *w = qobject_cast <QMainWindow *> (holder->parent_wnd);
1300
1301 if (fullname)
1302 w->setWindowTitle (file_name);
1303 else
1304 w->setWindowTitle (QFileInfo (file_name).fileName());
1305 }
1306
1307
update_labels()1308 void CDocument::update_labels()
1309 {
1310 labels.clear();
1311 labels = text_get_bookmarks (toPlainText(),
1312 settings->value ("label_start", "[?").toString(),
1313 settings->value ("label_end", "?]").toString());
1314 }
1315
1316
set_show_linenums(bool enable)1317 void CDocument::set_show_linenums (bool enable)
1318 {
1319 draw_linenums = enable;
1320 updateLineNumberAreaWidth();
1321 update();
1322 }
1323
1324
set_show_margin(bool enable)1325 void CDocument::set_show_margin (bool enable)
1326 {
1327 draw_margin = enable;
1328 update();
1329 }
1330
1331
set_margin_pos(int mp)1332 void CDocument::set_margin_pos (int mp)
1333 {
1334 margin_pos = mp;
1335 margin_x = brace_width * margin_pos;
1336 update();
1337 }
1338
1339
set_hl_cur_line(bool enable)1340 void CDocument::set_hl_cur_line (bool enable)
1341 {
1342 highlight_current_line = enable;
1343 update();
1344 }
1345
1346
set_hl_brackets(bool enable)1347 void CDocument::set_hl_brackets (bool enable)
1348 {
1349 hl_brackets = enable;
1350 update();
1351 }
1352
1353
set_word_wrap(bool wrap)1354 void CDocument::set_word_wrap (bool wrap)
1355 {
1356 if (wrap)
1357 setWordWrapMode (QTextOption::WrapAtWordBoundaryOrAnywhere);
1358 else
1359 setWordWrapMode (QTextOption::NoWrap);
1360 }
1361
1362
get_word_wrap()1363 bool CDocument::get_word_wrap()
1364 {
1365 return wordWrapMode() == QTextOption::WrapAtWordBoundaryOrAnywhere;
1366 }
1367
1368
indent()1369 void CDocument::indent()
1370 {
1371 if (! textCursor().hasSelection())
1372 {
1373 QString fl;
1374 fl = fl.fill (' ', tab_sp_width);
1375
1376 if (spaces_instead_of_tabs)
1377 textCursor().insertText (fl);
1378 else
1379 textCursor().insertText ("\t");
1380
1381 return;
1382 }
1383
1384 QStringList l = textCursor().selectedText().split (QChar::ParagraphSeparator);
1385 if (l.size() == 0)
1386 return;
1387
1388 QString fl;
1389 fl = fl.fill (' ', tab_sp_width);
1390
1391 for (QList <QString>::iterator i = l.begin(); i != l.end(); ++i)
1392 {
1393 if (spaces_instead_of_tabs)
1394 i->prepend (fl);
1395 else
1396 i->prepend ("\t");
1397 }
1398
1399 textCursor().insertText (l.join ("\n"));
1400
1401 QTextCursor cur = textCursor();
1402 cur.movePosition (QTextCursor::Up, QTextCursor::KeepAnchor, l.size() - 1);
1403 cur.movePosition (QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
1404
1405 setTextCursor (cur);
1406 }
1407
1408
un_indent()1409 void CDocument::un_indent()
1410 {
1411 QStringList l = textCursor().selectedText().split (QChar::ParagraphSeparator);
1412 if (l.size() == 0)
1413 return;
1414
1415 for (QList <QString>::iterator t = l.begin(); t != l.end(); ++t)
1416 {
1417 if (! t->isEmpty())
1418 if (t->at(0) == '\t' || t->at(0) == ' ')
1419 (*t) = t->mid (1);//eat first
1420 }
1421
1422 textCursor().insertText (l.join ("\n"));
1423
1424 QTextCursor cur = textCursor();
1425 cur.movePosition (QTextCursor::Up, QTextCursor::KeepAnchor, l.size() - 1);
1426 cur.movePosition (QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
1427
1428 setTextCursor (cur);
1429 }
1430
1431
1432 //если строка пустая - пофиг, а надо бы смотреть тогда строку выше
calc_auto_indent()1433 void CDocument::calc_auto_indent()
1434 {
1435 QTextCursor cur = textCursor();
1436 cur.movePosition (QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
1437 int aindent = 0;
1438
1439 QString s = cur.selectedText();
1440 int len = s.size();
1441
1442 QChar t = ' '; //what to detect - space or tab?
1443 if (s.indexOf ('\t') != -1)
1444 t = '\t';
1445
1446 if (t != '\t')
1447 {
1448 for (int i = 0; i < len; i++)
1449 if (! s.at(i).isSpace())
1450 {
1451 aindent = i;
1452 break;
1453 }
1454 }
1455 else
1456 {
1457 for (int i = 0; i < len; i++)
1458 if (s.at(i) != '\t')
1459 {
1460 aindent = i;
1461 break;
1462 }
1463 }
1464
1465
1466 if (aindent != 0)
1467 indent_val = indent_val.fill (t, aindent);
1468 else
1469 indent_val.clear();
1470 }
1471
1472
setup_brace_width()1473 void CDocument::setup_brace_width()
1474 {
1475 QFontMetrics *fm = new QFontMetrics (font());
1476 brace_width = fm->averageCharWidth();
1477 }
1478
1479
brace_highlight()1480 void CDocument::brace_highlight()
1481 {
1482 brace_selection.format.setBackground (brackets_color);
1483
1484 QTextDocument *doc = document();
1485 QTextCursor cursor = textCursor();
1486 QTextCursor beforeCursor = cursor;
1487
1488 cursor.movePosition (QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
1489 QString brace = cursor.selectedText();
1490
1491 beforeCursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
1492 QString beforeBrace = beforeCursor.selectedText();
1493
1494 if ((brace != "{") &&
1495 (brace != "}") &&
1496 (brace != "[") &&
1497 (brace != "]") &&
1498 (brace != "(") &&
1499 (brace != ")") &&
1500 (brace != "<") &&
1501 (brace != ">"))
1502 {
1503 if ((beforeBrace == "{")
1504 || (beforeBrace == "}")
1505 || (beforeBrace == "[")
1506 || (beforeBrace == "]")
1507 || (beforeBrace == "(")
1508 || (beforeBrace == ")")
1509 || (beforeBrace == "<")
1510 || (beforeBrace == ">"))
1511 {
1512 cursor = beforeCursor;
1513 brace = cursor.selectedText();
1514 }
1515 else
1516 return;
1517 }
1518
1519 QString openBrace;
1520 QString closeBrace;
1521
1522 if ((brace == "{") || (brace == "}"))
1523 {
1524 openBrace = "{";
1525 closeBrace = "}";
1526 }
1527 else
1528 if ((brace == "[") || (brace == "]"))
1529 {
1530 openBrace = "[";
1531 closeBrace = "]";
1532 }
1533 else
1534 if ((brace == "(") || (brace == ")"))
1535 {
1536 openBrace = "(";
1537 closeBrace = ")";
1538 }
1539 else
1540 if ((brace == "<") || (brace == ">"))
1541 {
1542 openBrace = "<";
1543 closeBrace = ">";
1544 }
1545
1546
1547 if (brace == openBrace)
1548 {
1549 QTextCursor cursor1 = doc->find (closeBrace, cursor);
1550 QTextCursor cursor2 = doc->find (openBrace, cursor);
1551 if (cursor2.isNull())
1552 {
1553 brace_selection.cursor = cursor;
1554 extra_selections.append (brace_selection);
1555 brace_selection.cursor = cursor1;
1556 extra_selections.append (brace_selection);
1557 setExtraSelections (extra_selections);
1558 }
1559 else
1560 {
1561 while (cursor1.position() > cursor2.position())
1562 {
1563 cursor1 = doc->find (closeBrace, cursor1);
1564 cursor2 = doc->find (openBrace, cursor2);
1565 if (cursor2.isNull())
1566 break;
1567 }
1568
1569 brace_selection.cursor = cursor;
1570 extra_selections.append (brace_selection);
1571 brace_selection.cursor = cursor1;
1572 extra_selections.append (brace_selection);
1573 setExtraSelections (extra_selections);
1574 }
1575 }
1576 else
1577 {
1578 if (brace == closeBrace)
1579 {
1580 QTextCursor cursor1 = doc->find (openBrace, cursor, QTextDocument::FindBackward);
1581 QTextCursor cursor2 = doc->find (closeBrace, cursor, QTextDocument::FindBackward);
1582 if (cursor2.isNull())
1583 {
1584 brace_selection.cursor = cursor;
1585 extra_selections.append (brace_selection);
1586 brace_selection.cursor = cursor1;
1587 extra_selections.append (brace_selection);
1588 setExtraSelections (extra_selections);
1589 }
1590 else
1591 {
1592 while (cursor1.position() < cursor2.position())
1593 {
1594 cursor1 = doc->find (openBrace, cursor1, QTextDocument::FindBackward);
1595 cursor2 = doc->find (closeBrace, cursor2, QTextDocument::FindBackward);
1596 if (cursor2.isNull())
1597 break;
1598 }
1599
1600 brace_selection.cursor = cursor;
1601 extra_selections.append (brace_selection);
1602 brace_selection.cursor = cursor1;
1603 extra_selections.append (brace_selection);
1604 setExtraSelections (extra_selections);
1605 }
1606 }
1607 }
1608 }
1609
1610
update_ext_selections()1611 void CDocument::update_ext_selections()
1612 {
1613 extra_selections.clear();
1614 setExtraSelections (extra_selections);
1615 rect_sel_upd();
1616 brace_highlight();
1617 }
1618
1619
rect_block_start()1620 void CDocument::rect_block_start()
1621 {
1622 int x = textCursor().position() - textCursor().block().position();
1623 int y = textCursor().block().blockNumber();
1624
1625 rect_sel_start.setX (x);
1626 rect_sel_start.setY (y);
1627
1628 update_ext_selections();
1629 }
1630
1631
rect_block_end()1632 void CDocument::rect_block_end()
1633 {
1634 int x = textCursor().position() - textCursor().block().position();
1635 int y = textCursor().block().blockNumber();
1636
1637 rect_sel_end.setX (x);
1638 rect_sel_end.setY (y);
1639
1640 update_ext_selections();
1641 }
1642
1643
has_rect_selection() const1644 bool CDocument::has_rect_selection() const
1645 {
1646 if (rect_sel_start.y() == -1 || rect_sel_end.y() == -1)
1647 return false;
1648
1649 return true;
1650 }
1651
1652
rect_sel_reset()1653 void CDocument::rect_sel_reset()
1654 {
1655 rect_sel_start.setX (-1);
1656 rect_sel_start.setY (-1);
1657 rect_sel_end.setX (-1);
1658 rect_sel_end.setY (-1);
1659 }
1660
1661
rect_sel_replace(const QString & s,bool insert)1662 void CDocument::rect_sel_replace (const QString &s, bool insert)
1663 {
1664 /*
1665
1666 1. Определить с какой строки начинаем вставку
1667 2. Определить как вставляемый текст перекрывает старый. Если строк в старом меньше (или конец файла),
1668 добавляем в выходной буфер строки.
1669 3. Составляем выходной буфер из строк старого и нового.
1670 4. Заменяем старый текст на выходной буфер.
1671
1672 */
1673 int y1 = std::min (rect_sel_start.y(), rect_sel_end.y());
1674 int y2 = std::max (rect_sel_start.y(), rect_sel_end.y());
1675 int ydiff = y2 - y1;
1676
1677 int x1 = std::min (rect_sel_start.x(), rect_sel_end.x());
1678 int x2 = std::max (rect_sel_start.x(), rect_sel_end.x());
1679
1680 QStringList sl_source;
1681
1682 for (int line = y1; line <= y2; line++)
1683 {
1684 QTextBlock b = document()->findBlockByNumber (line);
1685 sl_source.append (b.text());
1686 }
1687
1688 QStringList sl_insert = s.split ("\n");
1689
1690 QStringList sl_dest;
1691
1692 for (int line = 0; line < sl_insert.size(); line++)
1693 {
1694 QString t;
1695
1696 if (line >= sl_source.size())
1697 {
1698 t = sl_insert [line];
1699 sl_dest.append (t);
1700 continue;
1701 }
1702
1703 t = sl_source[line].left (x1);
1704 t += sl_insert [line];
1705
1706 if (! insert)
1707 t += sl_source[line].mid (x2);
1708 else
1709 t += sl_source[line].mid (x1);
1710
1711 sl_dest.append (t);
1712 }
1713
1714 QString new_text = sl_dest.join ("\n");
1715
1716 //теперь выделить при помощи курсора всё от y1 до y2 и обычным способом заменить текст
1717
1718 QTextCursor cursor = textCursor();
1719
1720 cursor.movePosition (QTextCursor::Start, QTextCursor::MoveAnchor);
1721 cursor.movePosition (QTextCursor::NextBlock, QTextCursor::MoveAnchor, y1);
1722 cursor.movePosition (QTextCursor::NextBlock, QTextCursor::KeepAnchor, ydiff);
1723 cursor.movePosition (QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1724
1725 cursor.removeSelectedText();
1726
1727 textCursor().insertText (new_text);
1728 }
1729
1730
rect_sel_upd()1731 void CDocument::rect_sel_upd()
1732 {
1733 if (rect_sel_start.y() == -1 || rect_sel_end.y() == -1)
1734 return;
1735
1736 QTextEdit::ExtraSelection rect_selection;
1737
1738 int y1 = std::min (rect_sel_start.y(), rect_sel_end.y());
1739 int y2 = std::max (rect_sel_start.y(), rect_sel_end.y());
1740
1741 int x1 = std::min (rect_sel_start.x(), rect_sel_end.x());
1742 int x2 = std::max (rect_sel_start.x(), rect_sel_end.x());
1743 int xdiff = x2 - x1;
1744
1745 int correction = 0;
1746
1747 QTextCursor cursor = textCursor();
1748
1749 cursor.movePosition (QTextCursor::Start, QTextCursor::MoveAnchor);
1750 cursor.movePosition (QTextCursor::NextBlock, QTextCursor::MoveAnchor, y1);
1751
1752 for (int y = y1; y <= y2; y++)
1753 {
1754 QTextBlock b = document()->findBlockByNumber (y);
1755
1756 if (b.text().length() == 0)
1757 {
1758 correction++;
1759 continue;
1760 }
1761
1762 int sel_len = xdiff;
1763
1764 if ((b.text().length() - x1) < xdiff)
1765 sel_len = b.text().length() - x1;
1766
1767 cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, x1 + correction);
1768 cursor.movePosition (QTextCursor::Right, QTextCursor::KeepAnchor, sel_len);
1769
1770 rect_selection.cursor = cursor;
1771 rect_selection.format.setBackground (sel_back_color);
1772 rect_selection.format.setForeground (sel_text_color);
1773
1774 extra_selections.append (rect_selection);
1775
1776 cursor.movePosition (QTextCursor::NextBlock, QTextCursor::MoveAnchor);
1777
1778 if (b.text().length() != 0)
1779 correction = 0;
1780 }
1781
1782 setExtraSelections (extra_selections);
1783 }
1784
1785
rect_sel_get() const1786 QString CDocument::rect_sel_get() const
1787 {
1788 QString result;
1789
1790 int y1 = std::min (rect_sel_start.y(), rect_sel_end.y());
1791 int y2 = std::max (rect_sel_start.y(), rect_sel_end.y());
1792
1793 int x1 = std::min (rect_sel_start.x(), rect_sel_end.x());
1794 int x2 = std::max (rect_sel_start.x(), rect_sel_end.x());
1795 int xdiff = x2 - x1; //sel length
1796
1797 for (int y = y1; y <= y2; y++)
1798 {
1799 QTextBlock b = document()->findBlockByNumber (y);
1800 QString t = b.text();
1801
1802 result += t.mid (x1, xdiff);
1803
1804 if (y != y2)
1805 result += '\n';
1806 }
1807
1808 return result;
1809 }
1810
1811
rect_sel_cut(bool just_del)1812 void CDocument::rect_sel_cut (bool just_del)
1813 {
1814 int y1 = std::min (rect_sel_start.y(), rect_sel_end.y());
1815 int y2 = std::max (rect_sel_start.y(), rect_sel_end.y());
1816 int ydiff = y2 - y1;
1817
1818 int x1 = std::min (rect_sel_start.x(), rect_sel_end.x());
1819 int x2 = std::max (rect_sel_start.x(), rect_sel_end.x());
1820
1821 QStringList sl_source;
1822
1823 for (int line = y1; line <= y2; line++)
1824 {
1825 QTextBlock b = document()->findBlockByNumber (line);
1826 sl_source.append (b.text());
1827 }
1828
1829 QStringList sl_dest;
1830 QStringList sl_copy;
1831
1832 for (int line = 0; line < sl_source.size(); line++)
1833 {
1834 QString t;
1835
1836 t = sl_source[line].left (x1);
1837 t += sl_source[line].mid (x2);
1838 sl_dest.append (t);
1839
1840 sl_copy.append (sl_source[line].mid (x1, x2 - x1));
1841 }
1842
1843 QString new_text = sl_dest.join ("\n");
1844
1845 //теперь выделить при помощи курсора всё от y1 до y2 и обычным способом заменить текст
1846
1847 QTextCursor cursor = textCursor();
1848
1849 cursor.movePosition (QTextCursor::Start, QTextCursor::MoveAnchor);
1850 cursor.movePosition (QTextCursor::NextBlock, QTextCursor::MoveAnchor, y1);
1851 cursor.movePosition (QTextCursor::NextBlock, QTextCursor::KeepAnchor, ydiff);
1852 cursor.movePosition (QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1853
1854 cursor.beginEditBlock();
1855
1856 cursor.removeSelectedText();
1857
1858 cursor.insertText (new_text);
1859
1860 cursor.endEditBlock();
1861
1862 if (! just_del)
1863 QApplication::clipboard()->setText (sl_copy.join ("\n"));
1864 }
1865
1866
lineNumberAreaPaintEvent(QPaintEvent * event)1867 void CDocument::lineNumberAreaPaintEvent (QPaintEvent *event)
1868 {
1869 if (! draw_linenums)
1870 return;
1871
1872 QPainter painter (line_num_area);
1873 painter.fillRect (event->rect(), linenums_bg);
1874 painter.setPen (text_color);
1875
1876 QTextBlock block = firstVisibleBlock();
1877 int blockNumber = block.blockNumber();
1878 int top = (int) blockBoundingGeometry (block).translated (contentOffset()).top();
1879 int bottom = top + (int) blockBoundingRect (block).height();
1880
1881 int w = line_num_area->width();
1882 int h = fontMetrics().height();
1883
1884 while (block.isValid() && top <= event->rect().bottom())
1885 {
1886 if (block.isVisible() && bottom >= event->rect().top())
1887 {
1888 QString number = QString::number (blockNumber + 1) + " ";
1889 painter.drawText (0, top, w, h, Qt::AlignRight, number);
1890 }
1891
1892 block = block.next();
1893 top = bottom;
1894 bottom = top + (int) blockBoundingRect(block).height();
1895 ++blockNumber;
1896 }
1897 }
1898
1899
line_number_area_width()1900 int CDocument::line_number_area_width()
1901 {
1902 if (! draw_linenums)
1903 return 0;
1904
1905 int digits = 1;
1906 int max = qMax (1, blockCount());
1907
1908 while (max >= 10)
1909 {
1910 max /= 10;
1911 ++digits;
1912 }
1913
1914 return (brace_width * 2) + (brace_width * digits);
1915 }
1916
1917
updateLineNumberAreaWidth()1918 void CDocument::updateLineNumberAreaWidth()
1919 {
1920 setViewportMargins (line_number_area_width(), 0, 0, 0);
1921 }
1922
1923
cb_cursorPositionChanged()1924 void CDocument::cb_cursorPositionChanged()
1925 {
1926 viewport()->update();
1927
1928 update_status();
1929
1930 if (hl_brackets)
1931 update_ext_selections();
1932 }
1933
1934
updateLineNumberArea(const QRect & rect,int dy)1935 void CDocument::updateLineNumberArea (const QRect &rect, int dy)
1936 {
1937 if (dy)
1938 line_num_area->scroll (0, dy);
1939 else
1940 line_num_area->update (0, rect.y(), line_num_area->width(), rect.height());
1941
1942 if (rect.contains (viewport()->rect()))
1943 updateLineNumberAreaWidth();
1944 }
1945
1946
slot_selectionChanged()1947 void CDocument::slot_selectionChanged()
1948 {
1949 QTextCursor cursor = this->textCursor();
1950
1951 if (cursor.selectionStart() != cursor.selectionEnd())
1952 {
1953 rect_sel_start.setX (-1);
1954 rect_sel_end.setX (-1);
1955 update_ext_selections();
1956 }
1957 }
1958
1959
CDox()1960 CDox::CDox()
1961 {
1962 markup_modes.insert ("htm", "HTML");
1963 markup_modes.insert ("html", "HTML");
1964 markup_modes.insert ("xhtml", "XHTML");
1965 markup_modes.insert ("xml", "Docbook");
1966 markup_modes.insert ("tex", "LaTeX");
1967 markup_modes.insert ("lout", "Lout");
1968 markup_modes.insert ("dokuwiki", "DokuWiki");
1969 markup_modes.insert ("mediawiki", "MediaWiki");
1970 markup_modes.insert ("md", "Markdown");
1971 markup_modes.insert ("markdown", "Markdown");
1972
1973 menu_recent = 0;
1974 main_tab_widget = 0;
1975 tab_widget = 0;
1976 parent_wnd = 0;
1977 log = 0;
1978 l_status_bar = 0;
1979 l_charset = 0;
1980
1981 //timer_autosave = new QTimer (this);
1982 timer_autosave.setInterval (settings->value ("timer_autosave_period", "1000").toInt() * 1000);
1983 connect(&timer_autosave, SIGNAL(timeout()), this, SLOT(autosave()));
1984
1985 //timer_joystick = new QTimer (this);
1986 timer_joystick.setInterval (100);
1987
1988 #if defined(JOYSTICK_SUPPORTED)
1989
1990 joystick = new CJoystick (0, this);
1991
1992 if (joystick->initialized)
1993 {
1994 connect(&timer_joystick, SIGNAL(timeout()), joystick, SLOT(read_joystick()));
1995
1996 if (settings->value ("use_joystick", "0").toBool())
1997 timer_joystick.start();
1998 }
1999 #endif
2000
2001
2002 }
2003
2004
~CDox()2005 CDox::~CDox()
2006 {
2007 b_destroying_all = true;
2008
2009 if (items.size() > 0)
2010 for (vector <size_t>::size_type i = 0; i < items.size(); i++)
2011 delete items[i];
2012
2013 qstring_save (recent_list_fname, recent_files.join ("\n"));
2014
2015 #if defined(JOYSTICK_SUPPORTED)
2016 delete joystick;
2017 #endif
2018 }
2019
2020
update_project(const QString & fileName)2021 void CDox::update_project (const QString &fileName)
2022 {
2023 if (file_get_ext (fileName) == "teaproject")
2024 {
2025 fname_current_project = fileName;
2026 hash_project.clear();
2027 hash_project = hash_load_keyval (fileName);
2028 }
2029 }
2030
2031
reload_recent_list(void)2032 void CDox::reload_recent_list (void)
2033 {
2034 if (! file_exists (recent_list_fname))
2035 return;
2036
2037 recent_files = qstring_load (recent_list_fname).split ("\n");
2038 }
2039
2040
add_to_recent(CDocument * d)2041 void CDox::add_to_recent (CDocument *d)
2042 {
2043 if (b_recent_off)
2044 return;
2045
2046 if (! file_exists (d->file_name))
2047 return;
2048
2049 QString s (d->file_name);
2050 s += ",";
2051 s += d->charset;
2052 s += ",";
2053 s += QString::number (d->textCursor().position());
2054 s += ",";
2055
2056 if (! d->get_word_wrap())
2057 s+="0";
2058 else
2059 s+="1";
2060
2061 recent_files.prepend (s);
2062 if (recent_files.size() > recent_list_max_items)
2063 recent_files.removeLast();
2064 }
2065
2066
update_recent_menu()2067 void CDox::update_recent_menu()
2068 {
2069 menu_recent->clear();
2070 create_menu_from_list (this, menu_recent, recent_files, SLOT(open_recent()));
2071 }
2072
2073
update_current_files_menu()2074 void CDox::update_current_files_menu()
2075 {
2076 QStringList current_files;
2077
2078 if (items.size() > 0)
2079 for (vector <size_t>::size_type i = 0; i < items.size(); i++)
2080 current_files.prepend (items[i]->file_name);
2081
2082 menu_current_files->clear();
2083 create_menu_from_list (this, menu_current_files, current_files, SLOT(open_current()));
2084 }
2085
2086
move_cursor(QTextCursor::MoveOperation mo)2087 void CDox::move_cursor (QTextCursor::MoveOperation mo)
2088 {
2089 CDocument *d = get_current();
2090
2091 if (! d)
2092 return;
2093
2094 QTextCursor cr = d->textCursor();
2095 if (cr.isNull())
2096 return;
2097
2098 if (mo != QTextCursor::NoMove)
2099 {
2100 cr.movePosition (mo, QTextCursor::MoveAnchor);
2101 d->setTextCursor (cr);
2102 }
2103 }
2104
2105
create_new()2106 CDocument* CDox::create_new()
2107 {
2108 CDocument *doc = new CDocument (this, 0);
2109 doc->markup_mode = markup_mode;
2110
2111 tab_widget->setCurrentIndex (tab_widget->indexOf (doc->tab_page));
2112 apply_settings_single (doc);
2113
2114 doc->update_title (settings->value ("full_path_at_window_title", 1).toBool());
2115 doc->update_status();
2116
2117 update_current_files_menu();
2118
2119 return doc;
2120 }
2121
2122
open_file(const QString & fileName,const QString & codec)2123 CDocument* CDox::open_file (const QString &fileName, const QString &codec)
2124 {
2125 if (! file_exists (fileName) || ! path_is_file (fileName))
2126 return 0;
2127
2128 if (is_image (fileName))
2129 {
2130 CDocument *td = get_current();
2131 if (td)
2132 {
2133 td->insert_image (fileName);
2134 td->setFocus (Qt::OtherFocusReason);
2135 }
2136 return td;
2137 }
2138
2139 CDocument *d = get_document_by_fname (fileName);
2140 if (d)
2141 {
2142 tab_widget->setCurrentIndex (tab_widget->indexOf (d->tab_page));
2143 d->reload (codec);
2144 return d;
2145 }
2146
2147 //else truly create the new doc
2148 d = create_new();
2149 d->file_open (fileName, codec);
2150
2151 dir_last = get_file_path (d->file_name);
2152
2153 d->update_status();
2154 d->update_title (settings->value ("full_path_at_window_title", 1).toBool());
2155
2156 main_tab_widget->setCurrentIndex (0);
2157
2158 update_current_files_menu();
2159
2160 return d;
2161 }
2162
2163
open_file_triplex(const QString & triplex)2164 CDocument* CDox::open_file_triplex (const QString &triplex)
2165 {
2166 QStringList sl = triplex.split (",");
2167 if (sl.size() < 3)
2168 return 0;
2169
2170 CDocument *d = open_file (sl[0], sl[1]);
2171 if (! d)
2172 return 0;
2173
2174 d->goto_pos (sl[2].toInt());
2175
2176 if (sl.size() >= 4)
2177 {
2178 if (sl[3] == "1")
2179 d->set_word_wrap (true);
2180 else
2181 d->set_word_wrap (false);
2182 }
2183
2184 return d;
2185 }
2186
2187
get_document_by_fname(const QString & fileName)2188 CDocument* CDox::get_document_by_fname (const QString &fileName)
2189 {
2190 if (fileName.isEmpty() || items.size() == 0)
2191 return 0;
2192
2193 for (vector <CDocument *>::iterator i = items.begin(); i != items.end(); ++i)
2194 if ((*i)->file_name == fileName)
2195 return *i;
2196
2197 return 0;
2198 }
2199
2200
get_current()2201 CDocument* CDox::get_current()
2202 {
2203 int i = tab_widget->currentIndex();
2204 if (i < 0)
2205 return 0;
2206
2207 return items[i];
2208 }
2209
2210
close_by_idx(int i)2211 void CDox::close_by_idx (int i)
2212 {
2213 if (i < 0)
2214 return;
2215
2216 delete items[i];
2217 items.erase (items.begin() + i);
2218
2219 update_current_files_menu();
2220 }
2221
2222
close_current()2223 void CDox::close_current()
2224 {
2225 close_by_idx (tab_widget->currentIndex());
2226 }
2227
2228
save_to_session(const QString & fileName)2229 void CDox::save_to_session (const QString &fileName)
2230 {
2231 if (items.size() == 0)
2232 return;
2233
2234 fname_current_session = fileName;
2235 QString l;
2236
2237 for (vector <CDocument*>::iterator i = items.begin(); i != items.end(); ++i)
2238 {
2239 QString t = (*i)->get_triplex();
2240 if (! t.isEmpty())
2241 {
2242 l += t;
2243 l += "\n";
2244 }
2245 }
2246
2247 qstring_save (fileName, l.trimmed());
2248 }
2249
2250
load_from_session(const QString & fileName)2251 void CDox::load_from_session (const QString &fileName)
2252 {
2253 if (! file_exists (fileName))
2254 return;
2255
2256 QStringList l = qstring_load (fileName).split ("\n");
2257 if (l.size() < 0)
2258 return;
2259
2260 for (int i = 0; i < l.size(); i++)
2261 open_file_triplex (l[i]);
2262
2263 fname_current_session = fileName;
2264 }
2265
save_buffers(const QString & fileName)2266 void CDox::save_buffers (const QString &fileName)
2267 {
2268 QFile::remove (fileName);
2269
2270 if (items.size() == 0)
2271 return;
2272
2273 fname_current_session = fileName;
2274 QString l;
2275
2276 for (vector <CDocument*>::iterator i = items.begin(); i != items.end(); ++i)
2277 {
2278 if (! file_exists ((*i)->file_name))
2279 {
2280 l += (*i)->toPlainText();
2281 l += '\f';
2282 }
2283 }
2284
2285 qstring_save (fileName, l.trimmed());
2286 }
2287
2288
load_from_buffers(const QString & fileName)2289 void CDox::load_from_buffers (const QString &fileName)
2290 {
2291 if (! file_exists (fileName))
2292 return;
2293
2294 QStringList l = qstring_load (fileName).split ("\f");
2295 if (l.size() < 0)
2296 return;
2297
2298 for (int i = 0; i < l.size(); i++)
2299 {
2300 CDocument *d = create_new();
2301 d->put (l[i]);
2302
2303 QTextCursor cr = d->textCursor();
2304 if (! cr.isNull())
2305 {
2306 cr.movePosition (QTextCursor::Start, QTextCursor::MoveAnchor);
2307 d->setTextCursor (cr);
2308 }
2309 }
2310
2311 fname_current_session = fileName;
2312 }
2313
2314
apply_settings()2315 void CDox::apply_settings()
2316 {
2317 if (items.size() == 0)
2318 return;
2319
2320 for (vector <size_t>::size_type i = 0; i < items.size(); i++)
2321 apply_settings_single (items[i]);
2322 }
2323
2324
apply_settings_single(CDocument * d)2325 void CDox::apply_settings_single (CDocument *d)
2326 {
2327 int darker_val = settings->value ("darker_val", 100).toInt();
2328
2329 d->setCursorWidth (settings->value ("cursor_width", 2).toInt());
2330 d->setCenterOnScroll (settings->value ("center_on_scroll", true).toBool());
2331
2332 QString s_sel_back_color = hash_get_val (global_palette, "sel-background", "black");
2333 QString s_sel_text_color = hash_get_val (global_palette, "sel-text", "white");
2334
2335 d->sel_text_color = QColor (s_sel_text_color).darker(darker_val).name();
2336 d->sel_back_color = QColor (s_sel_back_color).darker(darker_val).name();
2337
2338 d->tab_sp_width = settings->value ("tab_sp_width", 8).toInt();
2339 d->spaces_instead_of_tabs = settings->value ("spaces_instead_of_tabs", true).toBool();
2340
2341 #if (QT_VERSION_MAJOR <= 5 && QT_VERSION_MINOR < 10)
2342 d->setTabStopWidth (d->tab_sp_width * d->brace_width);
2343 #else
2344 d->setTabStopDistance (d->tab_sp_width * d->brace_width);
2345 #endif
2346
2347 d->setup_brace_width();
2348
2349 d->set_show_linenums (settings->value ("show_linenums", false).toBool());
2350 d->set_show_margin (settings->value ("show_margin", false).toBool());
2351 d->set_margin_pos (settings->value ("margin_pos", 72).toInt());
2352 d->highlight_current_line = settings->value ("additional_hl", false).toBool();
2353 d->hl_brackets = settings->value ("hl_brackets", false).toBool();
2354 d->brackets_color = QColor (hash_get_val (global_palette, "brackets", "yellow")).darker (darker_val);
2355 d->current_line_color = QColor (hash_get_val (global_palette, "cur_line_color", "#EEF6FF")).darker (darker_val);
2356
2357 d->cursor_xy_visible = settings->value ("cursor_xy_visible", "2").toBool();
2358 d->auto_indent = settings->value ("auto_indent", false).toBool();
2359
2360 QString text_color = hash_get_val (global_palette, "text", "black");
2361 QString t_text_color = QColor (text_color).darker(darker_val).name();
2362 d->text_color = QColor (t_text_color);
2363
2364 QString back_color = hash_get_val (global_palette, "background", "white");
2365 d->margin_color = QColor (hash_get_val (global_palette, "margin_color", text_color)).darker(darker_val);
2366 d->linenums_bg = QColor (hash_get_val (global_palette, "linenums_bg", back_color)).darker(darker_val);
2367 d->set_word_wrap (settings->value ("word_wrap", true).toBool());
2368
2369 d->repaint();
2370 d->set_hl();
2371 }
2372
2373
open_recent()2374 void CDox::open_recent()
2375 {
2376 QAction *act = qobject_cast<QAction *>(sender());
2377
2378 int i = recent_files.indexOf (act->text());
2379 if (i == -1)
2380 return;
2381
2382 CDocument *d = open_file_triplex (recent_files[i]);
2383 dir_last = get_file_path (d->file_name);
2384
2385
2386 update_recent_menu();
2387 }
2388
2389
open_current()2390 void CDox::open_current()
2391 {
2392 QAction *act = qobject_cast<QAction *>(sender());
2393
2394 CDocument *d = get_document_by_fname (act->text());
2395 if (d)
2396 tab_widget->setCurrentIndex (tab_widget->indexOf (d->tab_page));
2397 }
2398
2399
autosave()2400 void CDox::autosave()
2401 {
2402 if (! settings->value ("autosave", false).toBool())
2403 return;
2404
2405 if (items.size() == 0)
2406 return;
2407
2408 for (vector <CDocument *>::iterator i = items.begin(); i != items.end(); ++i)
2409 {
2410 if (autosave_files.contains ((*i)->file_name))
2411 (*i)->file_save_with_name ((*i)->file_name, (*i)->charset);
2412 }
2413
2414 save_buffers (fname_saved_buffers);
2415 }
2416
2417
move_cursor_up()2418 void CDox::move_cursor_up()
2419 {
2420 move_cursor (QTextCursor::Up);
2421 }
2422
2423
move_cursor_down()2424 void CDox::move_cursor_down()
2425 {
2426 move_cursor (QTextCursor::Down);
2427 }
2428
2429
move_cursor_left()2430 void CDox::move_cursor_left()
2431 {
2432 move_cursor (QTextCursor::Left);
2433 }
2434
2435
move_cursor_right()2436 void CDox::move_cursor_right()
2437 {
2438 move_cursor (QTextCursor::Right);
2439 }
2440
2441
move_cursor_x(double v)2442 void CDox::move_cursor_x (double v)
2443 {
2444 if (v < 0)
2445 move_cursor (QTextCursor::Right);
2446 if (v > 0)
2447 move_cursor (QTextCursor::Left);
2448 }
2449
2450
move_cursor_y(double v)2451 void CDox::move_cursor_y (double v)
2452 {
2453 if (v < 0)
2454 move_cursor (QTextCursor::Up);
2455 if (v > 0)
2456 move_cursor (QTextCursor::Down);
2457 }
2458
2459
2460 #if defined(JOYSTICK_SUPPORTED)
2461
event(QEvent * ev)2462 bool CDox::event (QEvent *ev)
2463 {
2464 if (static_cast<int>(ev->type() == evtJoystickAxis))
2465 {
2466 CJoystickAxisEvent* custom_event = reinterpret_cast<CJoystickAxisEvent*>(ev);
2467 handle_joystick_event (custom_event);
2468 custom_event->accept();
2469 return true;
2470 }
2471
2472 return QObject::event(ev);
2473 }
2474
2475
handle_joystick_event(CJoystickAxisEvent * event)2476 void CDox::handle_joystick_event (CJoystickAxisEvent *event)
2477 {
2478 QTextCursor::MoveOperation mo = QTextCursor::NoMove;
2479
2480 if (event->axis == 1 && event->value < 0) //up
2481 mo = QTextCursor::Up;
2482
2483 if (event->axis == 1 && event->value > 0) //down
2484 mo = QTextCursor::Down;
2485
2486 if (event->axis == 0 && event->value < 0) //left
2487 mo = QTextCursor::Left;
2488
2489 if (event->axis == 0 && event->value > 0) //right
2490 mo = QTextCursor::Right;
2491
2492 move_cursor (mo);
2493 }
2494
2495 #endif
2496