| 1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
| 2 | // |
| 3 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 4 | |
| 5 | #include "scintillaeditextern.h" |
| 6 | #include "style/stylecolor.h" |
| 7 | #include "transceiver/codeeditorreceiver.h" |
| 8 | |
| 9 | #include "common/common.h" |
| 10 | #include "framework/framework.h" |
| 11 | |
| 12 | #include <QApplication> |
| 13 | #include <QFile> |
| 14 | #include <QPoint> |
| 15 | #include <QRegularExpression> |
| 16 | #include <QScrollBar> |
| 17 | |
| 18 | #include <bitset> |
| 19 | |
| 20 | class ScintillaEditExternPrivate |
| 21 | { |
| 22 | friend class ScintillaEditExtern; |
| 23 | ScintillaEditExternPrivate() {} |
| 24 | bool isCtrlKeyPressed; |
| 25 | bool isLeave; |
| 26 | bool isSaveText = false; |
| 27 | Scintilla::Position hoverPos = -1; |
| 28 | QTimer hoverTimer; |
| 29 | QTimer definitionHoverTimer; |
| 30 | QString filePath; |
| 31 | QString language; |
| 32 | newlsp::ProjectKey proKey; |
| 33 | Scintilla::Position editInsertPostion = -1; |
| 34 | int editInsertCount = 0; |
| 35 | QHash<int, QList<AnnotationInfo>> lineAnnotations; |
| 36 | QHash<QString, decltype (lineAnnotations)> moduleAnnotations; |
| 37 | }; |
| 38 | |
| 39 | ScintillaEditExtern::ScintillaEditExtern(QWidget *parent) |
| 40 | : ScintillaEdit (parent) |
| 41 | , d(new ScintillaEditExternPrivate) |
| 42 | { |
| 43 | setTabWidth(4); |
| 44 | setIndentationGuides(SC_IV_LOOKBOTH); |
| 45 | styleSetBack(STYLE_DEFAULT, StyleColor::color(QColor(43,43,43))); |
| 46 | for (int i = 0; i < KEYWORDSET_MAX; i ++) { |
| 47 | styleSetFore(i, StyleColor::color(QColor(0xdd, 0xdd, 0xdd))); |
| 48 | styleSetBack(i, StyleColor::color(QColor(43,43,43))); |
| 49 | } |
| 50 | setCaretFore(StyleColor::color(QColor(255,255,255))); |
| 51 | horizontalScrollBar()->setVisible(false); |
| 52 | } |
| 53 | |
| 54 | ScintillaEditExtern::~ScintillaEditExtern() |
| 55 | { |
| 56 | if (d) { |
| 57 | delete d; |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | QString ScintillaEditExtern::fileLanguage(const QString &path) |
| 62 | { |
| 63 | using namespace support_file; |
| 64 | return Language::id(path); |
| 65 | } |
| 66 | |
| 67 | void ScintillaEditExtern::setFile(const QString &filePath) |
| 68 | { |
| 69 | if (d->filePath == filePath) { |
| 70 | return; |
| 71 | } else { |
| 72 | d->filePath = filePath; |
| 73 | } |
| 74 | |
| 75 | QString text; |
| 76 | QFile file(d->filePath); |
| 77 | if (file.open(QFile::OpenModeFlag::ReadOnly)) { |
| 78 | text = file.readAll(); |
| 79 | file.close(); |
| 80 | } |
| 81 | setText(text.toUtf8()); |
| 82 | emptyUndoBuffer(); |
| 83 | setSavePoint(); |
| 84 | |
| 85 | setMouseDwellTime(0); |
| 86 | QObject::connect(this, &ScintillaEditExtern::marginClicked, this, &ScintillaEditExtern::sciMarginClicked, Qt::UniqueConnection); |
| 87 | QObject::connect(this, &ScintillaEditExtern::modified, this, &ScintillaEditExtern::sciModified, Qt::UniqueConnection); |
| 88 | QObject::connect(this, &ScintillaEditExtern::dwellStart, this, &ScintillaEditExtern::sciDwellStart, Qt::UniqueConnection); |
| 89 | QObject::connect(this, &ScintillaEditExtern::dwellEnd, this, &ScintillaEditExtern::sciDwellEnd, Qt::UniqueConnection); |
| 90 | QObject::connect(this, &ScintillaEditExtern::notify, this, &ScintillaEditExtern::sciNotify, Qt::UniqueConnection); |
| 91 | QObject::connect(this, &ScintillaEditExtern::updateUi, this, &ScintillaEditExtern::sciUpdateUi, Qt::UniqueConnection); |
| 92 | |
| 93 | QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toSearchText, this, &ScintillaEditExtern::find); |
| 94 | QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toReplaceText, this, &ScintillaEditExtern::replace); |
| 95 | |
| 96 | QObject::connect(&d->hoverTimer, &QTimer::timeout, &d->hoverTimer, [=](){ |
| 97 | emit this->hovered(d->hoverPos); |
| 98 | d->hoverTimer.stop(); |
| 99 | }, Qt::UniqueConnection); |
| 100 | |
| 101 | QObject::connect(&d->definitionHoverTimer, &QTimer::timeout, &d->definitionHoverTimer, [=](){ |
| 102 | emit this->definitionHover(d->hoverPos); |
| 103 | d->definitionHoverTimer.stop(); |
| 104 | }, Qt::UniqueConnection); |
| 105 | horizontalScrollBar()->setVisible(true); |
| 106 | } |
| 107 | |
| 108 | void ScintillaEditExtern::updateFile() |
| 109 | { |
| 110 | QString text; |
| 111 | QFile file(d->filePath); |
| 112 | if (file.open(QFile::OpenModeFlag::ReadOnly)) { |
| 113 | text = file.readAll(); |
| 114 | file.close(); |
| 115 | } |
| 116 | setText(text.toUtf8()); |
| 117 | emptyUndoBuffer(); |
| 118 | setSavePoint(); |
| 119 | } |
| 120 | |
| 121 | QString ScintillaEditExtern::file() const |
| 122 | { |
| 123 | return d->filePath; |
| 124 | } |
| 125 | |
| 126 | void ScintillaEditExtern::setProjectKey(const newlsp::ProjectKey &key) |
| 127 | { |
| 128 | d->proKey = key; |
| 129 | } |
| 130 | |
| 131 | QString ScintillaEditExtern::workspace() const |
| 132 | { |
| 133 | return QString::fromStdString(d->proKey.workspace); |
| 134 | } |
| 135 | |
| 136 | void ScintillaEditExtern::addDebugPoint(int line) |
| 137 | { |
| 138 | markerAdd(line, StyleSci::Debug); |
| 139 | } |
| 140 | |
| 141 | void ScintillaEditExtern::removeDebugPoint(int line) |
| 142 | { |
| 143 | markerDelete(line, StyleSci::Debug); |
| 144 | } |
| 145 | |
| 146 | newlsp::ProjectKey ScintillaEditExtern::projectKey() const |
| 147 | { |
| 148 | return d->proKey; |
| 149 | } |
| 150 | |
| 151 | QString ScintillaEditExtern::language() const |
| 152 | { |
| 153 | return QString::fromStdString(d->proKey.language); |
| 154 | } |
| 155 | |
| 156 | void ScintillaEditExtern::debugPointAllDelete() |
| 157 | { |
| 158 | markerDeleteAll(StyleSci::Debug); |
| 159 | } |
| 160 | |
| 161 | void ScintillaEditExtern::jumpToLine(int line) |
| 162 | { |
| 163 | int lineOffSet = line - 1; |
| 164 | int displayLines = linesOnScreen(); |
| 165 | setFocus(true); |
| 166 | gotoPos(lineEndPosition(lineOffSet)); |
| 167 | if (displayLines > 0) { |
| 168 | int offsetLines = displayLines / 2; |
| 169 | setFirstVisibleLine(qMax(0, lineOffSet - offsetLines)); |
| 170 | } |
| 171 | cancel(); |
| 172 | } |
| 173 | |
| 174 | void ScintillaEditExtern::jumpToRange(Scintilla::Position start, Scintilla::Position end) |
| 175 | { |
| 176 | jumpToLine(lineFromPosition(end)); |
| 177 | setSelectionStart(start); |
| 178 | setSelectionEnd(end); |
| 179 | } |
| 180 | |
| 181 | void ScintillaEditExtern::runningToLine(int line) |
| 182 | { |
| 183 | int lineOffSet = line - 1; |
| 184 | |
| 185 | markerDeleteAll(StyleSci::Running); |
| 186 | markerDeleteAll(StyleSci::RunningLineBackground); |
| 187 | |
| 188 | markerAdd(lineOffSet, StyleSci::Running); |
| 189 | markerAdd(lineOffSet, StyleSci::RunningLineBackground); |
| 190 | } |
| 191 | |
| 192 | void ScintillaEditExtern::runningEnd() |
| 193 | { |
| 194 | markerDeleteAll(StyleSci::Running); |
| 195 | markerDeleteAll(StyleSci::RunningLineBackground); |
| 196 | } |
| 197 | |
| 198 | void ScintillaEditExtern::saveText() |
| 199 | { |
| 200 | QFile file(d->filePath); |
| 201 | if (!file.exists()) |
| 202 | return; |
| 203 | |
| 204 | if (!file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate)) { |
| 205 | return; |
| 206 | } |
| 207 | d->isSaveText = true; |
| 208 | file.write(textRange(0, length())); |
| 209 | emit saved(d->filePath); |
| 210 | file.close(); |
| 211 | } |
| 212 | |
| 213 | |
| 214 | void ScintillaEditExtern::saveAsText() |
| 215 | { |
| 216 | QFile file(d->filePath); |
| 217 | if (!file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate)) { |
| 218 | ContextDialog::ok("Can't save current: " + file.errorString()); |
| 219 | return; |
| 220 | } |
| 221 | d->isSaveText = true; |
| 222 | file.write(textRange(0, length())); |
| 223 | emit saved(d->filePath); |
| 224 | file.close(); |
| 225 | } |
| 226 | |
| 227 | bool ScintillaEditExtern::isSaveText() |
| 228 | { |
| 229 | return d->isSaveText; |
| 230 | } |
| 231 | |
| 232 | void ScintillaEditExtern::cleanIsSaveText() |
| 233 | { |
| 234 | d->isSaveText = false; |
| 235 | } |
| 236 | |
| 237 | bool ScintillaEditExtern::isLeave() |
| 238 | { |
| 239 | return d->isLeave; |
| 240 | } |
| 241 | |
| 242 | void ScintillaEditExtern::replaceRange(Scintilla::Position start, |
| 243 | Scintilla::Position end, const QString &text) |
| 244 | { |
| 245 | clearSelections(); |
| 246 | setSelectionStart(start); |
| 247 | setSelectionEnd(end); |
| 248 | replaceSel(text.toLatin1()); |
| 249 | emit replaceed(file(), start, end, text); |
| 250 | } |
| 251 | |
| 252 | QPair<long int, long int> ScintillaEditExtern::findText(long int start, long int end, const QString &text) |
| 253 | { |
| 254 | return ScintillaEdit::findText(SCFIND_NONE, text.toLatin1().data(), start, end); |
| 255 | } |
| 256 | |
| 257 | void ScintillaEditExtern::findText(const QString &srcText, bool reverse) |
| 258 | { |
| 259 | long int currentPos = ScintillaEditExtern::currentPos(); |
| 260 | long int maxPos = length(); |
| 261 | long int startPos = reverse ? (currentPos - srcText.length()) : currentPos; |
| 262 | long int endPos = reverse ? 0 : maxPos; |
| 263 | QPair<int, int> position = ScintillaEditExtern::findText(startPos, endPos, srcText.toLatin1().data()); |
| 264 | if (position.first >= 0) { |
| 265 | ScintillaEditExtern::jumpToRange(position.first, position.second); |
| 266 | } else { |
| 267 | if (reverse) { |
| 268 | if (position.second == 0) { |
| 269 | findText(srcText, maxPos, 0); |
| 270 | } |
| 271 | } else { |
| 272 | if (position.second == maxPos) { |
| 273 | findText(srcText, 0, maxPos); |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | void ScintillaEditExtern::findText(const QString &srcText, long int startPos, long int endPos) |
| 280 | { |
| 281 | QPair<int, int> position = ScintillaEditExtern::findText(startPos, endPos, srcText.toLatin1().data()); |
| 282 | if (position.first >= 0) { |
| 283 | ScintillaEditExtern::jumpToRange(position.first, position.second); |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | void ScintillaEditExtern::replaceAll(const QString &srcText, const QString &destText) |
| 288 | { |
| 289 | ScintillaEdit::searchAnchor(); |
| 290 | long int textLength = length(); |
| 291 | for (long int index = 0; index < textLength;) { |
| 292 | QPair<int, int> position = ScintillaEditExtern::findText(index, textLength, srcText.toLatin1().data()); |
| 293 | if (position.first > -1 && position.first != position.second) { |
| 294 | index = position.second; |
| 295 | replaceRange(position.first, position.second, destText); |
| 296 | } |
| 297 | |
| 298 | if (position.second >= textLength || index < 0) |
| 299 | return; |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | void ScintillaEditExtern::setLineBackground(int line, const QColor &color) |
| 304 | { |
| 305 | int lineOffSet = line - 1; |
| 306 | markerAdd(lineOffSet, StyleSci::CustomLineBackground); |
| 307 | markerSetBack(StyleSci::CustomLineBackground, StyleColor::color(color)); |
| 308 | markerSetAlpha(StyleSci::CustomLineBackground, color.alpha()); |
| 309 | } |
| 310 | |
| 311 | void ScintillaEditExtern::delLineBackground(int line) |
| 312 | { |
| 313 | int lineOffSet = line - 1; |
| 314 | markerDelete(lineOffSet, StyleSci::CustomLineBackground); |
| 315 | } |
| 316 | |
| 317 | void ScintillaEditExtern::cleanLineBackground() |
| 318 | { |
| 319 | markerDeleteAll(StyleSci::CustomLineBackground); |
| 320 | } |
| 321 | |
| 322 | void ScintillaEditExtern::setAnnotation(int line, const QString &title, const AnnotationInfo &info) |
| 323 | { |
| 324 | int lineOffset = line - 1; |
| 325 | if (title.isEmpty()) { |
| 326 | if (d->lineAnnotations.keys().contains(lineOffset)) { |
| 327 | auto anns = d->lineAnnotations.value(lineOffset); |
| 328 | if (anns.contains(info)) { |
| 329 | return; |
| 330 | } else { |
| 331 | anns.insert(0, info); |
| 332 | d->lineAnnotations[lineOffset] = anns; |
| 333 | } |
| 334 | } else { |
| 335 | d->lineAnnotations[lineOffset] = {info}; |
| 336 | } |
| 337 | } else { |
| 338 | if (d->moduleAnnotations.keys().contains(title)) { |
| 339 | auto lineAnns = d->moduleAnnotations.value(title); |
| 340 | if(lineAnns.keys().contains(lineOffset)) { |
| 341 | auto anns = lineAnns.value(lineOffset); |
| 342 | if (anns.contains(info)) |
| 343 | return; |
| 344 | else { |
| 345 | anns.insert(0, info); |
| 346 | lineAnns[lineOffset] = anns; |
| 347 | d->moduleAnnotations[title] = lineAnns; |
| 348 | } |
| 349 | } else { |
| 350 | lineAnns[lineOffset] = {info}; |
| 351 | d->moduleAnnotations[title] = lineAnns; |
| 352 | } |
| 353 | } else { |
| 354 | decltype (d->lineAnnotations) lineAnns; |
| 355 | lineAnns[lineOffset] = {info}; |
| 356 | d->moduleAnnotations[title] = lineAnns; |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | sciUpdateAnnotation(); |
| 361 | } |
| 362 | |
| 363 | void ScintillaEditExtern::cleanAnnotation(const QString &title) |
| 364 | { |
| 365 | if (title.isEmpty()) { |
| 366 | d->lineAnnotations.clear(); |
| 367 | } else { |
| 368 | d->moduleAnnotations.remove(title); |
| 369 | } |
| 370 | |
| 371 | sciUpdateAnnotation(); |
| 372 | } |
| 373 | |
| 374 | void ScintillaEditExtern::sciModified(Scintilla::ModificationFlags type, Scintilla::Position position, |
| 375 | Scintilla::Position length, Scintilla::Position linesAdded, |
| 376 | const QByteArray &text, Scintilla::Position line, |
| 377 | Scintilla::FoldLevel foldNow, Scintilla::FoldLevel foldPrev) |
| 378 | { |
| 379 | Q_UNUSED(position) |
| 380 | Q_UNUSED(length) |
| 381 | Q_UNUSED(linesAdded) |
| 382 | Q_UNUSED(text) |
| 383 | Q_UNUSED(line) |
| 384 | Q_UNUSED(foldNow) |
| 385 | Q_UNUSED(foldPrev) |
| 386 | |
| 387 | if (file().isEmpty()|| !QFile(file()).exists()) |
| 388 | return; |
| 389 | |
| 390 | if (bool(type & Scintilla::ModificationFlags::InsertText)) { |
| 391 | textInserted(position, length, linesAdded, text, line); |
| 392 | } |
| 393 | |
| 394 | if (bool(type & Scintilla::ModificationFlags::DeleteText)) { |
| 395 | textDeleted(position, length, linesAdded, text, line); |
| 396 | } |
| 397 | } |
| 398 | |
| 399 | void ScintillaEditExtern::sciNotify(Scintilla::NotificationData *data) |
| 400 | { |
| 401 | switch (data->nmhdr.code) { |
| 402 | case Scintilla::Notification::IndicatorClick : |
| 403 | emit indicClicked(data->position); |
| 404 | break; |
| 405 | case Scintilla::Notification::IndicatorRelease: |
| 406 | emit indicReleased(data->position); |
| 407 | break; |
| 408 | default: |
| 409 | break; |
| 410 | } |
| 411 | } |
| 412 | |
| 413 | void ScintillaEditExtern::sciUpdateUi(Scintilla::Update update) |
| 414 | { |
| 415 | Q_UNUSED(update); |
| 416 | if (d->hoverTimer.isActive()) { |
| 417 | d->hoverTimer.stop(); |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | void ScintillaEditExtern::sciDwellStart(int x, int y) |
| 422 | { |
| 423 | if (d->hoverPos == -1) { |
| 424 | d->hoverPos = positionFromPoint(x, y); // cache position |
| 425 | bool isKeyCtrl = QApplication::keyboardModifiers().testFlag(Qt::ControlModifier); |
| 426 | if (isKeyCtrl) { |
| 427 | d->definitionHoverTimer.start(20); |
| 428 | } else { |
| 429 | d->hoverTimer.start(500); // 如果间隔较小,导致收发管道溢出最终程序崩溃 |
| 430 | } |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | void ScintillaEditExtern::sciDwellEnd(int x, int y) |
| 435 | { |
| 436 | Q_UNUSED(x) |
| 437 | Q_UNUSED(y) |
| 438 | if (d->hoverPos != -1) { |
| 439 | if (d->definitionHoverTimer.isActive()) { |
| 440 | d->definitionHoverTimer.stop(); |
| 441 | } |
| 442 | emit definitionHoverCleaned(d->hoverPos); |
| 443 | if (d->hoverTimer.isActive()) { |
| 444 | d->hoverTimer.stop(); |
| 445 | } |
| 446 | emit hoverCleaned(d->hoverPos); |
| 447 | d->hoverPos = -1; // clean cache postion |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | void ScintillaEditExtern::sciUpdateAnnotation() |
| 452 | { |
| 453 | annotationClearAll(); |
| 454 | |
| 455 | auto getAnnotationStyles = [=](int roleCode, const QString &srcText) -> QString |
| 456 | { |
| 457 | QString styles; |
| 458 | int styleCode = roleCode - annotationStyleOffset(); |
| 459 | styles.resize(srcText.size(), styleCode); |
| 460 | return styles; |
| 461 | }; |
| 462 | |
| 463 | auto doSetAnnotation = [=] (const QHash<int, QList<AnnotationInfo>> &lineAnns, const QString &title = "" ) |
| 464 | { |
| 465 | QString annHead = "" ; |
| 466 | if (!title.isEmpty()) { |
| 467 | annHead += " " ; |
| 468 | } |
| 469 | |
| 470 | auto lines = lineAnns.keys(); |
| 471 | for (auto line : lines) { |
| 472 | auto anns = lineAnns.value(line); |
| 473 | QHash<QString, QStringList> roleAnns; |
| 474 | for (int i = 0; i < AnnotationInfo::Role::count(); i++) { |
| 475 | QString currRoleDisplay = AnnotationInfo::Role::get()->value(i).display; |
| 476 | auto itera = anns.begin(); |
| 477 | while (itera != anns.end()) { |
| 478 | if (itera->role.display == currRoleDisplay) { |
| 479 | QStringList annLines; |
| 480 | if (roleAnns.keys().contains(itera->role.display)) { |
| 481 | annLines = roleAnns.value(itera->role.display); |
| 482 | } |
| 483 | annLines.push_front(annHead + " " + itera->text); |
| 484 | roleAnns[itera->role.display] = annLines; |
| 485 | } |
| 486 | itera ++; |
| 487 | } |
| 488 | } |
| 489 | auto roleAnnsItera = roleAnns.begin(); |
| 490 | while (roleAnnsItera != roleAnns.end()) { |
| 491 | AnnotationInfo::Role::type_value roleElem; |
| 492 | for (auto idx = 0; idx < AnnotationInfo::Role::count(); idx ++) { |
| 493 | auto roleVal = AnnotationInfo::Role::value(idx); |
| 494 | if (roleVal.display == roleAnnsItera.key()) { |
| 495 | roleElem = roleVal; |
| 496 | break; |
| 497 | } |
| 498 | } |
| 499 | |
| 500 | QString lineAnnsText = annHead + roleAnnsItera.key() + ":\n" + roleAnnsItera.value().join("\n" ); |
| 501 | if (!title.isEmpty()) { |
| 502 | lineAnnsText = title + ":\n" + lineAnnsText; |
| 503 | } |
| 504 | QString lineAnnsTextStyles = getAnnotationStyles(roleElem.code, lineAnnsText); |
| 505 | |
| 506 | QString srcAnnsText = annotationText(line); |
| 507 | QString srcAnnsTextStyles = annotationStyles(line); |
| 508 | if (!srcAnnsText.isEmpty()) { |
| 509 | srcAnnsText += "\n" ; |
| 510 | srcAnnsTextStyles.resize(srcAnnsText.size(), srcAnnsTextStyles[srcAnnsText.size() -1]); |
| 511 | } |
| 512 | QString dstLineAnnsText = srcAnnsText + lineAnnsText; |
| 513 | QString dstLineAnnsTextStyles = srcAnnsTextStyles + lineAnnsTextStyles; |
| 514 | annotationSetText(line, dstLineAnnsText.toStdString().c_str()); |
| 515 | annotationSetStyles(line, dstLineAnnsTextStyles.toStdString().c_str()); |
| 516 | roleAnnsItera ++; |
| 517 | } |
| 518 | } |
| 519 | }; |
| 520 | |
| 521 | // global |
| 522 | doSetAnnotation(d->lineAnnotations); |
| 523 | |
| 524 | // moduel |
| 525 | auto itera = d->moduleAnnotations.begin(); |
| 526 | while (itera != d->moduleAnnotations.end()) { |
| 527 | doSetAnnotation(d->moduleAnnotations.value(itera.key()), itera.key()); |
| 528 | itera ++; |
| 529 | } |
| 530 | } |
| 531 | |
| 532 | void ScintillaEditExtern::keyReleaseEvent(QKeyEvent *event) |
| 533 | { |
| 534 | return ScintillaEdit::keyReleaseEvent(event); |
| 535 | } |
| 536 | |
| 537 | void ScintillaEditExtern::keyPressEvent(QKeyEvent *event) |
| 538 | { |
| 539 | bool isKeyCtrl = QApplication::keyboardModifiers().testFlag(Qt::ControlModifier); |
| 540 | bool isKeyS = event->key() == Qt::Key_S; |
| 541 | if (isKeyCtrl && isKeyS) { |
| 542 | saveText(); |
| 543 | } |
| 544 | return ScintillaEdit::keyPressEvent(event); |
| 545 | } |
| 546 | |
| 547 | void ScintillaEditExtern::sciMarginClicked(Scintilla::Position position, Scintilla::KeyMod modifiers, int margin) |
| 548 | { |
| 549 | Q_UNUSED(modifiers); |
| 550 | |
| 551 | sptr_t line = lineFromPosition(position); |
| 552 | if (margin == StyleSci::Margin::LineNumber || margin == StyleSci::Margin::Runtime) { |
| 553 | std::bitset<32> flags(markerGet(line)); |
| 554 | if (!flags[StyleSci::Debug]) { |
| 555 | markerAdd(line, StyleSci::Debug); |
| 556 | editor.addadDebugPoint(file(), qint64(line + 1)); //line begin 1 from debug point setting |
| 557 | editor.addDebugPoint(file(), qint64(line + 1)); |
| 558 | } else { |
| 559 | markerDelete(line, StyleSci::Debug); |
| 560 | editor.removedDebugPoint(file(), qint64(line + 1)); //line begin 1 from debug point setting |
| 561 | editor.removeDebugPoint(file(), qint64(line + 1)); |
| 562 | } |
| 563 | } |
| 564 | } |
| 565 | |
| 566 | void ScintillaEditExtern::focusInEvent(QFocusEvent *event) |
| 567 | { |
| 568 | focusChanged(true); |
| 569 | return ScintillaEdit::focusInEvent(event); |
| 570 | } |
| 571 | |
| 572 | void ScintillaEditExtern::focusOutEvent(QFocusEvent *event) |
| 573 | { |
| 574 | focusChanged(false); |
| 575 | callTipCancel(); |
| 576 | return ScintillaEdit::focusOutEvent(event); |
| 577 | } |
| 578 | |
| 579 | void ScintillaEditExtern::(QContextMenuEvent *event) |
| 580 | { |
| 581 | if (selectionStart() == selectionEnd()) { |
| 582 | ScintillaEdit::contextMenuEvent(event); |
| 583 | } else { |
| 584 | emit selectionMenu(event); |
| 585 | } |
| 586 | } |
| 587 | |
| 588 | void ScintillaEditExtern::enterEvent(QEvent *event) |
| 589 | { |
| 590 | d->isLeave = false; |
| 591 | ScintillaEdit::enterEvent(event); |
| 592 | } |
| 593 | |
| 594 | void ScintillaEditExtern::leaveEvent(QEvent *event) |
| 595 | { |
| 596 | d->isLeave = true; |
| 597 | ScintillaEdit::leaveEvent(event); |
| 598 | } |
| 599 | |
| 600 | void ScintillaEditExtern::find(const QString &srcText, int operateType) |
| 601 | { |
| 602 | switch (operateType) { |
| 603 | case FindType::Previous: |
| 604 | { |
| 605 | searchAnchor(); |
| 606 | findText(srcText, true); |
| 607 | break; |
| 608 | } |
| 609 | case FindType::Next: |
| 610 | { |
| 611 | searchAnchor(); |
| 612 | findText(srcText, false); |
| 613 | break; |
| 614 | } |
| 615 | default: |
| 616 | break; |
| 617 | } |
| 618 | } |
| 619 | |
| 620 | void ScintillaEditExtern::replace(const QString &srcText, const QString &destText, int operateType) |
| 621 | { |
| 622 | switch (operateType) { |
| 623 | case RepalceType::Repalce: |
| 624 | { |
| 625 | QByteArray byteArray = getSelText(); |
| 626 | if (0 == QString(byteArray).compare(srcText, Qt::CaseInsensitive)) { |
| 627 | replaceSel(destText.toLatin1().data()); |
| 628 | } |
| 629 | |
| 630 | break; |
| 631 | } |
| 632 | case RepalceType::FindAndReplace: |
| 633 | { |
| 634 | QByteArray byteArray = getSelText(); |
| 635 | if (0 == QString(byteArray).compare(srcText, Qt::CaseInsensitive)) { |
| 636 | replaceSel(destText.toLatin1().data()); |
| 637 | } |
| 638 | |
| 639 | searchAnchor(); |
| 640 | findText(srcText, false); |
| 641 | break; |
| 642 | } |
| 643 | case RepalceType::RepalceAll: |
| 644 | { |
| 645 | replaceAll(srcText, destText); |
| 646 | break; |
| 647 | } |
| 648 | default: |
| 649 | break; |
| 650 | } |
| 651 | } |
| 652 | |