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