1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "style/lspclientkeeper.h"
6#include "textedittabwidget.h"
7#include "textedittitlebar.h"
8#include "textedittabbar.h"
9#include "textedit.h"
10#include "mainframe/texteditkeeper.h"
11#include "transceiver/codeeditorreceiver.h"
12#include "codelens/codelens.h"
13#include "common/common.h"
14#include <QGridLayout>
15#include <QFileInfo>
16#include <QKeyEvent>
17
18static TextEditTabWidget *ins{nullptr};
19
20class TextEditTabWidgetPrivate
21{
22 friend class TextEditTabWidget;
23 TextEditTabBar *tab {nullptr};
24 QGridLayout *gridLayout {nullptr};
25 QHash<QString, TextEdit*> textEdits{};
26 QHash<QString, TextEditTitleBar*> titleBars{};
27 QHash<QString, bool> textEditAutoReloadFlags;
28 TextEdit defaultEdit;
29 QString runningFilePathCache;
30 bool selFlag = false;
31 QColor selColor{};
32 QColor defColor{};
33};
34
35TextEditTabWidget::TextEditTabWidget(QWidget *parent)
36 : QWidget(parent)
37 , d(new TextEditTabWidgetPrivate)
38{
39 d->gridLayout = new QGridLayout(this);
40 d->gridLayout->setSpacing(0);
41 d->gridLayout->setMargin(0);
42
43 d->tab = new TextEditTabBar(this);
44 d->gridLayout->addWidget(d->tab);
45 d->gridLayout->addWidget(&d->defaultEdit);
46 this->setLayout(d->gridLayout);
47 this->setAcceptDrops(true);
48
49 setDefaultFileEdit();
50 setFocusPolicy(Qt::ClickFocus);
51
52 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toOpenFileWithKey,
53 this, &TextEditTabWidget::openFileWithKey);
54
55 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toRunFileLineWithKey,
56 this, &TextEditTabWidget::runningToLineWithKey);
57
58 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toRunClean,
59 this, &TextEditTabWidget::runningEnd);
60
61 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toDebugPointClean,
62 this, &TextEditTabWidget::debugPointClean);
63
64 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toJumpFileLineWithKey,
65 this, &TextEditTabWidget::jumpToLineWithKey);
66
67 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toSetLineBackground,
68 this, &TextEditTabWidget::setLineBackground);
69
70 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toDelLineBackground,
71 this, &TextEditTabWidget::delLineBackground);
72
73 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toCleanLineBackground,
74 this, &TextEditTabWidget::cleanLineBackground);
75
76 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toSetAnnotation,
77 this, &TextEditTabWidget::setAnnotation);
78
79 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toCleanAnnotation,
80 this, &TextEditTabWidget::cleanAnnotation);
81
82 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toCleanAllAnnotation,
83 this, &TextEditTabWidget::cleanAllAnnotation);
84
85 QObject::connect(d->tab, &TextEditTabBar::fileSwitched,
86 this, &TextEditTabWidget::showFileEdit, Qt::QueuedConnection);
87
88 QObject::connect(d->tab, &TextEditTabBar::fileClosed,
89 this, &TextEditTabWidget::removeFileEdit, Qt::QueuedConnection);
90
91 QObject::connect(d->tab, &TextEditTabBar::fileClosed,
92 this, &TextEditTabWidget::removeFileStatusBar, Qt::QueuedConnection);
93
94 QObject::connect(d->tab, &TextEditTabBar::closeClicked, this, &TextEditTabWidget::closed);
95
96 QObject::connect(d->tab, &TextEditTabBar::splitClicked, this, [=](Qt::Orientation ori) {
97 QString currSelFile = d->tab->currentFile();
98 newlsp::ProjectKey key = {};
99 if(d->textEdits[currSelFile] && !currSelFile.isEmpty()) {
100 key = d->textEdits[currSelFile]->projectKey();
101 }
102 emit splitClicked(ori, key, currSelFile);
103 });
104
105 QObject::connect(Inotify::globalInstance(), &Inotify::deletedSelf,
106 this, &TextEditTabWidget::fileDeleted, Qt::QueuedConnection);
107 QObject::connect(Inotify::globalInstance(), &Inotify::movedSelf,
108 this, &TextEditTabWidget::fileMoved, Qt::QueuedConnection);
109 QObject::connect(Inotify::globalInstance(), &Inotify::modified,
110 this, &TextEditTabWidget::fileModifyed, Qt::QueuedConnection);
111}
112
113TextEditTabWidget::~TextEditTabWidget()
114{
115 if (d) {
116 if (d->tab) {
117 delete d->tab;
118 d->tab = nullptr;
119 }
120
121 auto editsItera = d->textEdits.begin();
122 while (editsItera != d->textEdits.end()) {
123 delete editsItera.value(); // free instance
124 editsItera = d->textEdits.erase(editsItera);
125 }
126
127 auto titleItera = d->titleBars.begin();
128 while (titleItera != d->titleBars.end()) {
129 delete titleItera.value();
130 titleItera = d->titleBars.erase(titleItera);
131 }
132
133 delete d; // free private
134 }
135}
136
137TextEditTabWidget *TextEditTabWidget::instance()
138{
139 if (!ins)
140 ins = new TextEditTabWidget;
141 return ins;
142}
143
144void TextEditTabWidget::openFile(const QString &filePath)
145{
146 QFileInfo info(filePath);
147 if (!info.exists() || !d->tab )
148 return;
149 // can't add widget to much
150 if (d->textEdits.keys().contains(info.filePath())) {
151 d->tab->switchFile(filePath);
152 return;
153 }
154
155 d->tab->setFile(filePath);
156
157
158 TextEdit *edit = new TextEdit;
159
160 QObject::connect(edit, &TextEdit::focusChanged,
161 this, &TextEditTabWidget::selectSelf);
162
163 QObject::connect(edit, &TextEdit::fileChanged, d->tab,
164 &TextEditTabBar::doFileChanged, Qt::UniqueConnection);
165
166 QObject::connect(edit, &TextEdit::fileSaved, d->tab,
167 &TextEditTabBar::doFileSaved, Qt::UniqueConnection);
168
169 edit->setFile(info.filePath());
170 d->textEdits[filePath] = edit;
171
172 // 添加监听
173 Inotify::globalInstance()->addPath(info.filePath());
174 // set display textedit
175 d->gridLayout->addWidget(edit);
176
177 if (!d->defaultEdit.isHidden())
178 d->defaultEdit.hide();
179
180 d->tab->switchFile(filePath);
181
182 d->textEditAutoReloadFlags[filePath] = false;
183
184 showFileEdit(filePath);
185 emit sigOpenFile();
186}
187
188void TextEditTabWidget::openFileWithKey(const newlsp::ProjectKey &key, const QString &filePath)
189{
190 QFileInfo info(filePath);
191 if (!info.exists() || !d->tab )
192 return;
193 // can't add widget to much
194 if (d->textEdits.keys().contains(info.filePath())) {
195 d->tab->switchFile(filePath);
196 return;
197 }
198
199 d->tab->setFile(filePath);
200
201 newlsp::Client *client = LSPClientKeeper::instance()->get(key);
202 if (!client) {
203 client = LSPClientKeeper::instance()->get(key);
204 }
205
206 // 全局rename操作
207 QObject::connect(client, QOverload<const newlsp::WorkspaceEdit&>::of(&newlsp::Client::renameRes),
208 this, &TextEditTabWidget::doRenameReplace, Qt::UniqueConnection);
209
210 // 使用取出适用的编辑器
211 TextEdit *edit = TextEditKeeper::create(TextEdit::fileLanguage(filePath));
212
213 QObject::connect(edit, &TextEdit::fileChanged, d->tab,
214 &TextEditTabBar::doFileChanged, Qt::UniqueConnection);
215
216 QObject::connect(edit, &TextEdit::fileSaved, d->tab,
217 &TextEditTabBar::doFileSaved, Qt::UniqueConnection);
218
219 QObject::connect(d->tab, &TextEditTabBar::saveFile,
220 this, &TextEditTabWidget::saveEditFile,
221 Qt::UniqueConnection);
222
223 if (edit){
224 edit->setProjectKey(key);
225 edit->setFile(info.filePath());
226 } else {
227 edit = new TextEdit();
228 edit->setProjectKey(key);
229 edit->setFile(info.filePath());
230 }
231
232 QObject::connect(edit, &TextEdit::focusChanged,
233 this, &TextEditTabWidget::selectSelf);
234
235 d->textEdits[filePath] = edit;
236 // 添加监听
237 Inotify::globalInstance()->addPath(info.filePath());
238 // set display textedit
239 d->gridLayout->addWidget(edit);
240
241 if (!d->defaultEdit.isHidden())
242 d->defaultEdit.hide();
243
244 d->tab->switchFile(filePath);
245
246 d->textEditAutoReloadFlags[filePath] = false;
247
248 showFileEdit(filePath);
249 emit sigOpenFile();
250}
251
252void TextEditTabWidget::closeFile(const QString &filePath)
253{
254 Inotify::globalInstance()->removePath(filePath);
255
256 if (!d->tab)
257 return;
258
259 int index = d->tab->fileIndex(filePath);
260 if (index >=0 && index < d->tab->count())
261 emit d->tab->tabCloseRequested(index);
262}
263
264void TextEditTabWidget::jumpToLineWithKey(const newlsp::ProjectKey &key, const QString &filePath, int line)
265{
266 auto edit = switchFileAndToOpen(key, filePath);
267
268 if (edit) {
269 edit->jumpToLine(line);
270 }
271}
272
273void TextEditTabWidget::jumpToLine(const QString &filePath, int line)
274{
275 auto edit = switchFileAndToOpen(filePath);
276
277 if (edit) {
278 edit->jumpToLine(line);
279 }
280}
281
282void TextEditTabWidget::jumpToRange(const QString &filePath, const newlsp::Range &range)
283{
284 auto edit = switchFileAndToOpen(filePath);
285
286 if (edit) {
287 auto styleLsp = edit->getStyleLsp();
288 if (styleLsp) {
289 auto start = styleLsp->getSciPosition(edit->docPointer(), range.start);
290 auto end = styleLsp->getSciPosition(edit->docPointer(), range.end);
291 edit->jumpToRange(start, end);
292 }
293 }
294}
295
296void TextEditTabWidget::runningToLineWithKey(const newlsp::ProjectKey &key, const QString &filePath, int line)
297{
298 auto edit = switchFileAndToOpen(key, filePath);
299
300 if (edit) {
301 edit->jumpToLine(line);
302 edit->runningToLine(line);
303 }
304}
305
306void TextEditTabWidget::runningToLine(const QString &filePath, int line)
307{
308 auto edit = switchFileAndToOpen(filePath);
309
310 if (edit) {
311 edit->jumpToLine(line);
312 edit->runningToLine(line);
313 }
314}
315
316void TextEditTabWidget::runningEnd()
317{
318 for (auto edit : d->textEdits) {
319 edit->runningEnd();
320 }
321}
322
323void TextEditTabWidget::addDebugPoint(const QString &filePath, int line)
324{
325 for (auto edit : d->textEdits) {
326 if (filePath == edit->file()) {
327 edit->addDebugPoint(line);
328 }
329 }
330}
331
332void TextEditTabWidget::removeDebugPoint(const QString &filePath, int line)
333{
334 for (auto edit : d->textEdits) {
335 if (filePath == edit->file()) {
336 edit->removeDebugPoint(line);
337 }
338 }
339}
340
341void TextEditTabWidget::debugPointClean()
342{
343 for (auto edit : d->textEdits) {
344 edit->debugPointAllDelete();
345 }
346}
347
348void TextEditTabWidget::replaceRange(const QString &filePath, const newlsp::Range &range, const QString &text)
349{
350 auto edit = d->textEdits.value(filePath);
351 if (edit) {
352 auto styleLsp = edit->getStyleLsp();
353 if (styleLsp) {
354 auto start = styleLsp->getSciPosition(edit->docPointer(), range.start);
355 auto end = styleLsp->getSciPosition(edit->docPointer(), range.end);
356 edit->replaceRange(start, end, text);
357 }
358 } else { //直接更改磁盘数据
359 if (range.start.line != range.end.line) {
360 qCritical() << "Failed, Unknown error";
361 abort();
362 }
363 QFile changeFile(filePath);
364 QString cacheData;
365 if (changeFile.open(QFile::ReadOnly)) {
366 int i = 0;
367 while (i != range.start.line) {
368 cacheData += changeFile.readLine();
369 i++;
370 }
371 QString changeLine = changeFile.readLine();
372 int removeLength = range.end.character - range.start.character;
373 changeLine = changeLine.replace(range.start.character, removeLength, text);
374 cacheData += changeLine;
375 QByteArray array = changeFile.readLine();
376 while (!array.isEmpty()) {
377 cacheData += array;
378 array = changeFile.readLine();
379 }
380 changeFile.close();
381 }
382
383 if (changeFile.open(QFile::WriteOnly | QFile::Truncate)) {
384 int writeCount = changeFile.write(cacheData.toLatin1());
385 if (writeCount != cacheData.size()) {
386 qCritical() << "Failed, Unknown error";
387 abort();
388 }
389 changeFile.close();
390 }
391 }
392}
393
394void TextEditTabWidget::setLineBackground(const QString &filePath, int line, const QColor &color)
395{
396 if (!d->gridLayout)
397 return;
398
399 auto edit = d->textEdits.value(filePath);
400
401 if (!edit)
402 return;
403
404 edit->setLineBackground(line, color);
405}
406
407void TextEditTabWidget::delLineBackground(const QString &filePath, int line)
408{
409 if (!d->gridLayout)
410 return;
411
412 auto edit = d->textEdits.value(filePath);
413
414 if (!edit)
415 return;
416
417 edit->delLineBackground(line);
418}
419
420void TextEditTabWidget::cleanLineBackground(const QString &filePath)
421{
422 if (!d->gridLayout)
423 return;
424
425 auto edit = d->textEdits.value(filePath);
426
427 if (!edit)
428 return;
429
430 edit->cleanLineBackground();
431}
432
433void TextEditTabWidget::setAnnotation(const QString &filePath, int line,
434 const QString &title, const AnnotationInfo &info)
435{
436 if (!d->gridLayout)
437 return;
438
439 auto edit = d->textEdits.value(filePath);
440
441 if (!edit)
442 return;
443
444 edit->setAnnotation(line, title, info);
445}
446
447void TextEditTabWidget::cleanAnnotation(const QString &filePath, const QString &title)
448{
449 if (!d->gridLayout)
450 return;
451
452 auto edit = d->textEdits.value(filePath);
453
454 if (!edit)
455 return;
456
457 edit->cleanAnnotation(title);
458}
459
460void TextEditTabWidget::cleanAllAnnotation(const QString &title)
461{
462 for (auto filePath : d->textEdits.keys()) {
463 cleanAnnotation(filePath, title);
464 }
465}
466
467void TextEditTabWidget::selectSelf(bool state)
468{
469 d->selFlag = state;
470 emit selected(state);
471 update();
472}
473
474void TextEditTabWidget::setModifiedAutoReload(const QString &filePath, bool flag)
475{
476 d->textEditAutoReloadFlags[filePath] = flag;
477}
478
479void TextEditTabWidget::setDefaultFileEdit()
480{
481 if (!d || !d->gridLayout)
482 return;
483
484 d->gridLayout->addWidget(&d->defaultEdit);
485 d->defaultEdit.setEnabled(false);
486 d->defaultEdit.show();
487}
488
489void TextEditTabWidget::hideFileEdit(const QString &file)
490{
491 if (!d->gridLayout)
492 return;
493
494 auto edit = d->textEdits.value(file);
495
496 if (!edit)
497 return;
498
499 edit->hide();
500}
501
502void TextEditTabWidget::showFileEdit(const QString &file)
503{
504 if (!d->gridLayout)
505 return;
506
507 auto edit = d->textEdits.value(file);
508
509 if (!edit)
510 return;
511
512 auto itera = d->textEdits.begin();
513 while (itera != d->textEdits.end()){
514 if (itera.key() != file && itera.value()){
515 itera.value()->hide(); // hide other;
516 }
517 itera ++;
518 }
519
520 edit->show();
521}
522
523void TextEditTabWidget::hideFileStatusBar(const QString &file)
524{
525 auto statusBar = d->titleBars.value(file);
526 statusBar->hide();
527}
528
529void TextEditTabWidget::showFileStatusBar(const QString &file)
530{
531 if (d->titleBars.contains(file)) {
532 auto statusBar = d->titleBars.value(file);
533 if (statusBar)
534 statusBar->show();
535 }
536}
537
538void TextEditTabWidget::removeFileStatusBar(const QString &file)
539{
540 if (d->textEditAutoReloadFlags.contains(file))
541 d->textEditAutoReloadFlags.remove(file);
542
543 auto statusBar = d->titleBars.value(file);
544 if (!statusBar)
545 return;
546
547 delete statusBar;
548 d->titleBars.remove(file);
549}
550
551void TextEditTabWidget::removeFileEdit(const QString &file)
552{
553 auto edit = d->textEdits.value(file);
554 if (!edit)
555 return;
556
557 edit->fileClosed(file);
558 edit->deleteLater();
559 d->textEdits.remove(file);
560
561 if (d->textEdits.size() == 0) {
562 setDefaultFileEdit();
563 emit closeWidget();
564 }
565
566}
567
568void TextEditTabWidget::removeFileTab(const QString &file)
569{
570 d->tab->removeTab(file);
571}
572
573void TextEditTabWidget::fileModifyed(const QString &file)
574{
575 auto edit = d->textEdits[file];
576 if (edit && !edit->isHidden() && !edit->isSaveText()) {
577
578 if (!d->titleBars[file]) {
579 d->titleBars[file] = TextEditTitleBar::changedReload(file);
580 QObject::connect(d->titleBars[file], &TextEditTitleBar::reloadfile, [=](){
581 if(d->titleBars.contains(file) && d->textEdits.contains(file)) {
582 d->textEdits[file]->updateFile();
583 }
584 });
585 }
586
587 if (d->textEditAutoReloadFlags.contains(file) && d->textEditAutoReloadFlags[file]) {
588 d->titleBars[file]->reloadfile();
589 } else {
590 d->gridLayout->addWidget(d->titleBars[file], 1, 0);
591 d->titleBars[file]->show();
592 }
593 }
594
595 // 100 ms 内多次出发变动将忽略
596 QTimer::singleShot(100, [=](){edit->cleanIsSaveText();});
597}
598
599void TextEditTabWidget::fileDeleted(const QString &file)
600{
601 detectFile(file);
602}
603
604void TextEditTabWidget::fileMoved(const QString &file)
605{
606 detectFile(file);
607}
608
609void TextEditTabWidget::detectFile(const QString &file)
610{
611 QFileInfo info(file);
612 if (info.exists()) {
613 fileModifyed(file);
614 Inotify::globalInstance()->addPath(file);
615 } else {
616 Inotify::globalInstance()->removePath(file);
617 handleDeletedFile(file);
618 }
619}
620
621void TextEditTabWidget::setCloseButtonVisible(bool flag)
622{
623 d->tab->setCloseButtonVisible(flag);
624}
625
626void TextEditTabWidget::setSplitButtonVisible(bool flag)
627{
628 d->tab->setSplitButtonVisible(flag);
629}
630
631void TextEditTabWidget::handleDeletedFile(const QString &file)
632{
633 int ret = QMessageBox::question(this, QMessageBox::tr("File Has Been Removed"),
634 QMessageBox::tr("The file has been removed, Do you want to save it?"),
635 QMessageBox::Save | QMessageBox::Discard, QMessageBox::Discard);
636 if (QMessageBox::Save == ret) {
637 TextEdit* edit = d->textEdits.value(file);
638 if (edit) {
639 edit->saveAsText();
640 Inotify::globalInstance()->addPath(file);
641 }
642 } else {
643 closeFile(file);
644 }
645}
646
647void TextEditTabWidget::doRenameReplace(const newlsp::WorkspaceEdit &renameResult)
648{
649 if (renameResult.changes) {
650 auto changes = renameResult.changes;
651 auto itera = changes->begin();
652 while (itera != changes->end()) {
653 for (auto edit : itera->second) {
654 QString filePath = QUrl(QString::fromStdString(itera->first)).toLocalFile();
655 QString newText = QString::fromStdString(edit.newText);
656 replaceRange(filePath, edit.range, newText);
657 }
658 itera ++;
659 }
660 }
661 if (renameResult.documentChanges) {
662 if (newlsp::any_contrast<std::vector<newlsp::TextDocumentEdit>>(renameResult.documentChanges.value())) {
663 std::vector<newlsp::TextDocumentEdit> documentChanges
664 = std::any_cast<std::vector<newlsp::TextDocumentEdit>>(renameResult.documentChanges.value());
665 for (auto documentChange : documentChanges) {
666 QString filePath = QUrl(QString::fromStdString(documentChange.textDocument.uri)).toLocalFile();
667 if (!std::vector<newlsp::TextEdit>(documentChange.edits).empty()) {
668 auto edits = std::vector<newlsp::TextEdit>(documentChange.edits);
669 for (auto edit : edits) {
670 QString newText = QString::fromStdString(edit.newText);
671 replaceRange(filePath, edit.range, newText);
672 }
673 } else if (!std::vector<newlsp::AnnotatedTextEdit>(documentChange.edits).empty()) {
674 auto edits = std::vector<newlsp::AnnotatedTextEdit>(documentChange.edits);
675 for (auto edit : edits) {
676 QString newText = QString::fromStdString(edit.newText);
677 replaceRange(filePath, edit.range, newText);
678 }
679 }
680 }
681 }
682 }
683}
684
685TextEdit* TextEditTabWidget::switchFileAndToOpen(const newlsp::ProjectKey &key, const QString &filePath)
686{
687 auto edit = d->textEdits.value(filePath);
688 if (edit) {
689 d->tab->switchFile(filePath);
690 showFileEdit(filePath);
691 } else {
692 openFileWithKey(key, filePath);
693 for (auto textEdit : d->textEdits.values()) {
694 textEdit->runningEnd();
695 if (textEdit->file() == filePath) {
696 showFileEdit(filePath);
697 edit = textEdit;
698 }
699 }
700 }
701 return edit;
702}
703
704TextEdit* TextEditTabWidget::switchFileAndToOpen(const QString &filePath)
705{
706 auto edit = d->textEdits.value(filePath);
707 if (edit) {
708 d->tab->switchFile(filePath);
709 showFileEdit(filePath);
710 } else {
711 openFile(filePath);
712 for (auto textEdit : d->textEdits.values()) {
713 textEdit->runningEnd();
714 if (textEdit->file() == filePath) {
715 showFileEdit(filePath);
716 edit = textEdit;
717 }
718 }
719 }
720
721 showFileStatusBar(filePath);
722 return edit;
723}
724
725void TextEditTabWidget::saveEditFile(const QString &file)
726{
727 TextEdit* edit = d->textEdits.value(file);
728 if (edit) {
729 edit->saveText();
730 }
731}
732
733void TextEditTabWidget::keyPressEvent(QKeyEvent *event)
734{
735 if (event->modifiers() == Qt::AltModifier) {
736 int idx = d->tab->currentIndex();
737 int count = d->tab->count();
738 if (count > 0 && idx > -1) {
739 if (event->key() == Qt::Key_Left) {
740 d->tab->setCurrentIndex((idx - 1 + count) % count);
741 setFocus();
742 } else if (event->key() == Qt::Key_Right) {
743 d->tab->setCurrentIndex((idx + 1) % count);
744 setFocus();
745 }
746 }
747 }
748 return QWidget::keyPressEvent(event);
749}
750
751void TextEditTabWidget::focusInEvent(QFocusEvent *event)
752{
753 QWidget::focusInEvent(event);
754 this->selectSelf(true);
755}
756
757void TextEditTabWidget::focusOutEvent(QFocusEvent *event)
758{
759 QWidget::focusOutEvent(event);
760 this->selectSelf(false);
761}
762
763void TextEditTabWidget::paintEvent(QPaintEvent *event)
764{
765 if (d->selFlag) {
766 QPainter painter(this);
767 painter.save();
768 painter.setPen(d->selColor);
769 painter.drawRect(this->rect());
770 painter.restore();
771 } else {
772 if (!d->defColor.isValid()) {
773 d->defColor = palette().window().color();
774 d->selColor = QColor(d->defColor.red() + 20, d->defColor.green() + 20, d->defColor.blue() + 20, d->defColor.alpha());
775 } else {
776 QPainter painter(this);
777 painter.save();
778 painter.setPen(d->defColor);
779 painter.drawRect(this->rect());
780 painter.restore();
781 }
782 }
783}
784
785void TextEditTabWidget::dragEnterEvent(QDragEnterEvent *event)
786{
787 if (event->mimeData()->hasUrls()) {
788 event->acceptProposedAction();
789 } else {
790 event->ignore();
791 }
792}
793
794void TextEditTabWidget::dropEvent(QDropEvent *event)
795{
796 const QMimeData* mimeData = event->mimeData();
797 if(mimeData->hasUrls()) {
798 QList<QUrl>urlList = mimeData->urls();
799 QString fileName = urlList.at(0).toLocalFile();
800 if(!fileName.isEmpty()) {
801 editor.openFile(fileName);
802 }
803 }
804}
805