Changeset View
Standalone View
addons/katebuild-plugin/plugin_katebuild.cpp
Show All 38 Lines | |||||
39 | #include <QDir> | 39 | #include <QDir> | ||
40 | #include <QFileDialog> | 40 | #include <QFileDialog> | ||
41 | 41 | | |||
42 | #include <QAction> | 42 | #include <QAction> | ||
43 | 43 | | |||
44 | #include <KTextEditor/Application> | 44 | #include <KTextEditor/Application> | ||
45 | #include <KXMLGUIFactory> | 45 | #include <KXMLGUIFactory> | ||
46 | #include <KActionCollection> | 46 | #include <KActionCollection> | ||
47 | #include <KConfigGroup> | ||||
48 | #include <KSharedConfig> | ||||
47 | 49 | | |||
48 | #include <kmessagebox.h> | 50 | #include <kmessagebox.h> | ||
49 | 51 | | |||
50 | #include <klocalizedstring.h> | 52 | #include <klocalizedstring.h> | ||
51 | #include <kpluginfactory.h> | 53 | #include <kpluginfactory.h> | ||
52 | #include <kpluginloader.h> | 54 | #include <kpluginloader.h> | ||
53 | #include <kaboutdata.h> | 55 | #include <kaboutdata.h> | ||
54 | 56 | | |||
55 | | ||||
56 | #include "SelectTargetView.h" | 57 | #include "SelectTargetView.h" | ||
57 | 58 | | |||
59 | | ||||
58 | K_PLUGIN_FACTORY_WITH_JSON (KateBuildPluginFactory, "katebuildplugin.json", registerPlugin<KateBuildPlugin>();) | 60 | K_PLUGIN_FACTORY_WITH_JSON (KateBuildPluginFactory, "katebuildplugin.json", registerPlugin<KateBuildPlugin>();) | ||
59 | 61 | | |||
60 | static const QString DefConfigCmd = QStringLiteral("cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr/local ../"); | 62 | static const QString DefConfigCmd = QStringLiteral("cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr/local ../"); | ||
61 | static const QString DefConfClean; | 63 | static const QString DefConfClean; | ||
62 | static const QString DefTargetName = QStringLiteral("all"); | 64 | static const QString DefTargetName = QStringLiteral("all"); | ||
63 | static const QString DefBuildCmd = QStringLiteral("make"); | 65 | static const QString DefBuildCmd = QStringLiteral("make"); | ||
64 | static const QString DefCleanCmd = QStringLiteral("make clean"); | 66 | static const QString DefCleanCmd = QStringLiteral("make clean"); | ||
67 | static const bool OnlyUpdateMessageText = true; | ||||
68 | static const int NeverHide = 60 * 60 * 1000; // 1hour delay, quirk to avoid forced "Close" button | ||||
sars: Please increase the time, in case we have really long builds that progress slowly ;) | |||||
65 | 69 | | |||
66 | 70 | | |||
67 | /******************************************************************/ | 71 | //BEGIN KateBuildPlugin | ||
68 | KateBuildPlugin::KateBuildPlugin(QObject *parent, const VariantList&): | 72 | KateBuildPlugin::KateBuildPlugin(QObject *parent, const VariantList&): | ||
69 | KTextEditor::Plugin(parent) | 73 | KTextEditor::Plugin(parent) | ||
70 | { | 74 | { | ||
71 | // KF5 FIXME KGlobal::locale()->insertCatalog("katebuild-plugin"); | 75 | // KF5 FIXME KGlobal::locale()->insertCatalog("katebuild-plugin"); | ||
72 | } | 76 | } | ||
73 | 77 | | |||
74 | /******************************************************************/ | | |||
75 | QObject *KateBuildPlugin::createView (KTextEditor::MainWindow *mainWindow) | 78 | QObject *KateBuildPlugin::createView (KTextEditor::MainWindow *mainWindow) | ||
76 | { | 79 | { | ||
77 | return new KateBuildView(this, mainWindow); | 80 | auto view = new KateBuildView(this, mainWindow); | ||
81 | | ||||
82 | m_views.append(view); | ||||
83 | | ||||
84 | return view; | ||||
85 | } | ||||
86 | | ||||
87 | int KateBuildPlugin::configPages() const | ||||
88 | { | ||||
89 | return 1; | ||||
90 | } | ||||
91 | | ||||
92 | KTextEditor::ConfigPage *KateBuildPlugin::configPage(int number, QWidget *parent) | ||||
93 | { | ||||
94 | if (number != 0) { | ||||
95 | return nullptr; | ||||
96 | } | ||||
97 | | ||||
98 | return new KateBuildPluginConfigPage(parent, this); | ||||
99 | } | ||||
100 | | ||||
101 | void KateBuildPlugin::readConfig() | ||||
102 | { | ||||
103 | // Be aware that we can have more than one view! | ||||
104 | for (int i = 0; i < m_views.size(); ++i) { | ||||
105 | m_views.at(i)->readConfig(); | ||||
106 | } | ||||
78 | } | 107 | } | ||
79 | 108 | | |||
109 | //END | ||||
110 | | ||||
80 | /******************************************************************/ | 111 | /******************************************************************/ | ||
81 | KateBuildView::KateBuildView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw) | 112 | KateBuildView::KateBuildView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw) | ||
82 | : QObject (mw) | 113 | : QObject (mw) | ||
83 | , m_win(mw) | 114 | , m_win(mw) | ||
84 | , m_buildWidget(nullptr) | 115 | , m_buildWidget(nullptr) | ||
85 | , m_outputWidgetWidth(0) | 116 | , m_outputWidgetWidth(0) | ||
86 | , m_proc(this) | 117 | , m_proc(this) | ||
87 | , m_stdOut() | 118 | , m_stdOut() | ||
88 | , m_stdErr() | 119 | , m_stdErr() | ||
89 | , m_buildCancelled(false) | 120 | , m_buildCancelled(false) | ||
90 | , m_displayModeBeforeBuild(1) | 121 | , m_displayModeBeforeBuild(1) | ||
91 | // NOTE this will not allow spaces in file names. | 122 | // NOTE this will not allow spaces in file names. | ||
92 | // e.g. from gcc: "main.cpp:14: error: cannot convert ‘std::string’ to ‘int’ in return" | 123 | // e.g. from gcc: "main.cpp:14: error: cannot convert ‘std::string’ to ‘int’ in return" | ||
93 | , m_filenameDetector(QStringLiteral("(([a-np-zA-Z]:[\\\\/])?[a-zA-Z0-9_\\.\\-/\\\\]+\\.[a-zA-Z0-9]+):([0-9]+)(.*)")) | 124 | , m_filenameDetector(QStringLiteral("(([a-np-zA-Z]:[\\\\/])?[a-zA-Z0-9_\\.\\-/\\\\]+\\.[a-zA-Z0-9]+):([0-9]+)(.*)")) | ||
94 | // e.g. from icpc: "main.cpp(14): error: no suitable conversion function from "std::string" to "int" exists" | 125 | // e.g. from icpc: "main.cpp(14): error: no suitable conversion function from "std::string" to "int" exists" | ||
95 | , m_filenameDetectorIcpc(QStringLiteral("(([a-np-zA-Z]:[\\\\/])?[a-zA-Z0-9_\\.\\-/\\\\]+\\.[a-zA-Z0-9]+)\\(([0-9]+)\\)(:.*)")) | 126 | , m_filenameDetectorIcpc(QStringLiteral("(([a-np-zA-Z]:[\\\\/])?[a-zA-Z0-9_\\.\\-/\\\\]+\\.[a-zA-Z0-9]+)\\(([0-9]+)\\)(:.*)")) | ||
96 | , m_filenameDetectorGccWorked(false) | 127 | , m_filenameDetectorGccWorked(false) | ||
97 | , m_newDirDetector(QStringLiteral("make\\[.+\\]: .+ `.*'")) | 128 | , m_newDirDetector(QStringLiteral("make\\[.+\\]: .+ `.*'")) | ||
98 | { | 129 | { | ||
99 | KXMLGUIClient::setComponentName (QStringLiteral("katebuild"), i18n ("Kate Build Plugin")); | 130 | KXMLGUIClient::setComponentName (QStringLiteral("katebuild"), i18n ("Kate Build Plugin")); | ||
100 | setXMLFile(QStringLiteral("ui.rc")); | 131 | setXMLFile(QStringLiteral("ui.rc")); | ||
101 | 132 | | |||
102 | m_toolView = mw->createToolView(plugin, QStringLiteral("kate_plugin_katebuildplugin"), | 133 | m_toolView = mw->createToolView(plugin, QStringLiteral("kate_plugin_katebuildplugin"), | ||
103 | KTextEditor::MainWindow::Bottom, | 134 | KTextEditor::MainWindow::Bottom, | ||
104 | QIcon::fromTheme(QStringLiteral("application-x-ms-dos-executable")), | 135 | QIcon::fromTheme(QStringLiteral("run-build")), | ||
105 | i18n("Build Output")); | 136 | i18n("Build Output")); | ||
106 | 137 | | |||
107 | QAction *a = actionCollection()->addAction(QStringLiteral("select_target")); | 138 | QAction *a = actionCollection()->addAction(QStringLiteral("select_target")); | ||
108 | a->setText(i18n("Select Target...")); | 139 | a->setText(i18n("Select Target...")); | ||
109 | a->setIcon(QIcon::fromTheme(QStringLiteral("select"))); | 140 | a->setIcon(QIcon::fromTheme(QStringLiteral("select"))); | ||
110 | connect(a, &QAction::triggered, this, &KateBuildView::slotSelectTarget); | 141 | connect(a, &QAction::triggered, this, &KateBuildView::slotSelectTarget); | ||
111 | a = actionCollection()->addAction(QStringLiteral("build_default_target")); | 142 | a = actionCollection()->addAction(QStringLiteral("build_default_target")); | ||
112 | a->setText(i18n("Build Default Target")); | 143 | a->setText(i18n("Build Default Target")); | ||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Line(s) | |||||
186 | 217 | | |||
187 | // watch for project plugin view creation/deletion | 218 | // watch for project plugin view creation/deletion | ||
188 | connect(m_win, &KTextEditor::MainWindow::pluginViewCreated, this, &KateBuildView::slotPluginViewCreated); | 219 | connect(m_win, &KTextEditor::MainWindow::pluginViewCreated, this, &KateBuildView::slotPluginViewCreated); | ||
189 | connect(m_win, &KTextEditor::MainWindow::pluginViewDeleted, this, &KateBuildView::slotPluginViewDeleted); | 220 | connect(m_win, &KTextEditor::MainWindow::pluginViewDeleted, this, &KateBuildView::slotPluginViewDeleted); | ||
190 | 221 | | |||
191 | // Connect signals from project plugin to our slots | 222 | // Connect signals from project plugin to our slots | ||
192 | m_projectPluginView = m_win->pluginView(QStringLiteral("kateprojectplugin")); | 223 | m_projectPluginView = m_win->pluginView(QStringLiteral("kateprojectplugin")); | ||
193 | slotPluginViewCreated(QStringLiteral("kateprojectplugin"), m_projectPluginView); | 224 | slotPluginViewCreated(QStringLiteral("kateprojectplugin"), m_projectPluginView); | ||
225 | | ||||
226 | m_progressLimiter.setSingleShot(true); | ||||
227 | m_progressLimiter.setInterval(100); | ||||
228 | readConfig(); | ||||
194 | } | 229 | } | ||
195 | 230 | | |||
196 | 231 | | |||
197 | /******************************************************************/ | 232 | /******************************************************************/ | ||
198 | KateBuildView::~KateBuildView() | 233 | KateBuildView::~KateBuildView() | ||
199 | { | 234 | { | ||
200 | m_win->guiFactory()->removeClient( this ); | 235 | m_win->guiFactory()->removeClient( this ); | ||
201 | delete m_toolView; | 236 | delete m_toolView; | ||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Line(s) | 306 | { | |||
304 | 339 | | |||
305 | cg.writeEntry(QStringLiteral("Active Target Index"), set); | 340 | cg.writeEntry(QStringLiteral("Active Target Index"), set); | ||
306 | cg.writeEntry(QStringLiteral("Active Target Command"), setRow); | 341 | cg.writeEntry(QStringLiteral("Active Target Command"), setRow); | ||
307 | 342 | | |||
308 | // Restore project targets, if any | 343 | // Restore project targets, if any | ||
309 | slotAddProjectTarget(); | 344 | slotAddProjectTarget(); | ||
310 | } | 345 | } | ||
311 | 346 | | |||
347 | void KateBuildView::readConfig() | ||||
348 | { | ||||
349 | KConfigGroup config(KSharedConfig::openConfig(), "Build"); | ||||
350 | m_isSetAutoHide = config.readEntry("AutoHide", false); | ||||
351 | m_isSetNoToolTip = config.readEntry("NoToolTips", false); | ||||
352 | m_isSetNoPopUp = config.readEntry("NoPopUp", false); | ||||
353 | } | ||||
312 | 354 | | |||
313 | /******************************************************************/ | 355 | /******************************************************************/ | ||
314 | void KateBuildView::slotNext() | 356 | void KateBuildView::slotNext() | ||
315 | { | 357 | { | ||
316 | const int itemCount = m_buildUi.errTreeWidget->topLevelItemCount(); | 358 | const int itemCount = m_buildUi.errTreeWidget->topLevelItemCount(); | ||
317 | if (itemCount == 0) { | 359 | if (itemCount == 0) { | ||
318 | return; | 360 | return; | ||
319 | } | 361 | } | ||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Line(s) | 444 | { | |||
441 | if (errorCategory == CategoryInfo) { | 483 | if (errorCategory == CategoryInfo) { | ||
442 | item->setHidden(m_buildUi.displayModeSlider->value() > 1); | 484 | item->setHidden(m_buildUi.displayModeSlider->value() > 1); | ||
443 | } | 485 | } | ||
444 | 486 | | |||
445 | item->setData(0, ErrorRole, errorCategory); | 487 | item->setData(0, ErrorRole, errorCategory); | ||
446 | 488 | | |||
447 | // add tooltips in all columns | 489 | // add tooltips in all columns | ||
448 | // The enclosing <qt>...</qt> enables word-wrap for long error messages | 490 | // The enclosing <qt>...</qt> enables word-wrap for long error messages | ||
449 | item->setData(0, Qt::ToolTipRole, filename); | 491 | const int role = m_isSetNoToolTip ? Qt::WhatsThisRole : Qt::ToolTipRole; | ||
Why would we not want to have a tooltip? with really long error messages you would not get the error. The What's this is much harder to find... If we keep this I think the option should be: Use "What's this" for long error messages or something similar. sars: Why would we not want to have a tooltip? with really long error messages you would not get the… | |||||
450 | item->setData(1, Qt::ToolTipRole, QStringLiteral("<qt>%1</qt>").arg(message)); | 492 | item->setData(0, role, filename); | ||
451 | item->setData(2, Qt::ToolTipRole, QStringLiteral("<qt>%1</qt>").arg(message)); | 493 | item->setData(1, role, QStringLiteral("<qt>%1</qt>").arg(message)); | ||
494 | item->setData(2, role, QStringLiteral("<qt>%1</qt>").arg(message)); | ||||
452 | } | 495 | } | ||
453 | 496 | | |||
454 | /******************************************************************/ | 497 | /******************************************************************/ | ||
455 | QUrl KateBuildView::docUrl() | 498 | QUrl KateBuildView::docUrl() | ||
456 | { | 499 | { | ||
457 | KTextEditor::View *kv = m_win->activeView(); | 500 | KTextEditor::View *kv = m_win->activeView(); | ||
458 | if (!kv) { | 501 | if (!kv) { | ||
459 | qDebug() << "no KTextEditor::View" << endl; | 502 | qDebug() << "no KTextEditor::View" << endl; | ||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Line(s) | 541 | { | |||
502 | 545 | | |||
503 | // clear previous runs | 546 | // clear previous runs | ||
504 | clearBuildResults(); | 547 | clearBuildResults(); | ||
505 | 548 | | |||
506 | // activate the output tab | 549 | // activate the output tab | ||
507 | m_buildUi.u_tabWidget->setCurrentIndex(1); | 550 | m_buildUi.u_tabWidget->setCurrentIndex(1); | ||
508 | m_displayModeBeforeBuild = m_buildUi.displayModeSlider->value(); | 551 | m_displayModeBeforeBuild = m_buildUi.displayModeSlider->value(); | ||
509 | m_buildUi.displayModeSlider->setValue(0); | 552 | m_buildUi.displayModeSlider->setValue(0); | ||
510 | m_win->showToolView(m_toolView); | 553 | | ||
554 | if (!m_isSetNoPopUp) { | ||||
555 | m_win->showToolView(m_toolView); | ||||
556 | } | ||||
511 | 557 | | |||
512 | // set working directory | 558 | // set working directory | ||
513 | m_make_dir = dir; | 559 | m_make_dir = dir; | ||
514 | m_make_dir_stack.push(m_make_dir); | 560 | m_make_dir_stack.push(m_make_dir); | ||
515 | 561 | | |||
516 | if (!QFile::exists(m_make_dir)) { | 562 | if (!QFile::exists(m_make_dir)) { | ||
517 | KMessageBox::error(nullptr, i18n("Cannot run command: %1\nWork path does not exist: %2", command, m_make_dir)); | 563 | KMessageBox::error(nullptr, i18n("Cannot run command: %1\nWork path does not exist: %2", command, m_make_dir)); | ||
518 | return false; | 564 | return false; | ||
Show All 16 Lines | |||||
535 | QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); | 581 | QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); | ||
536 | return true; | 582 | return true; | ||
537 | } | 583 | } | ||
538 | 584 | | |||
539 | /******************************************************************/ | 585 | /******************************************************************/ | ||
540 | bool KateBuildView::slotStop() | 586 | bool KateBuildView::slotStop() | ||
541 | { | 587 | { | ||
542 | if (m_proc.state() != QProcess::NotRunning) { | 588 | if (m_proc.state() != QProcess::NotRunning) { | ||
543 | m_buildCancelled = true; | 589 | m_buildCancelled = true; | ||
sars: Why the type change? | |||||
loh.tar: Why not? Nothing happens which may cause trouble. | |||||
544 | QString msg = i18n("Building <b>%1</b> cancelled", m_currentlyBuildingTarget); | | |||
545 | m_buildUi.buildStatusLabel->setText(msg); | | |||
546 | m_buildUi.buildStatusLabel2->setText(msg); | | |||
547 | m_proc.terminate(); | 590 | m_proc.terminate(); | ||
548 | return true; | 591 | return true; | ||
549 | } | 592 | } | ||
550 | return false; | 593 | return false; | ||
551 | } | 594 | } | ||
552 | 595 | | |||
553 | /******************************************************************/ | 596 | /******************************************************************/ | ||
554 | void KateBuildView::slotBuildActiveTarget() { | 597 | void KateBuildView::slotBuildActiveTarget() { | ||
Show All 16 Lines | 607 | void KateBuildView::slotBuildPreviousTarget() { | |||
571 | } | 614 | } | ||
572 | } | 615 | } | ||
573 | 616 | | |||
574 | 617 | | |||
575 | /******************************************************************/ | 618 | /******************************************************************/ | ||
576 | void KateBuildView::slotBuildDefaultTarget() { | 619 | void KateBuildView::slotBuildDefaultTarget() { | ||
577 | QModelIndex defaultTarget = m_targetsUi->targetsModel.defaultTarget(m_targetsUi->targetsView->currentIndex()); | 620 | QModelIndex defaultTarget = m_targetsUi->targetsModel.defaultTarget(m_targetsUi->targetsView->currentIndex()); | ||
578 | m_targetsUi->targetsView->setCurrentIndex(defaultTarget); | 621 | m_targetsUi->targetsView->setCurrentIndex(defaultTarget); | ||
622 | m_hideViewOnSuccess = 2; | ||||
This would work differently for building: default, previous and active target. How the build is invoked should not affect the behavior. sars: This would work differently for building: default, previous and active target.
How the build… | |||||
579 | buildCurrentTarget(); | 623 | buildCurrentTarget(); | ||
580 | } | 624 | } | ||
581 | 625 | | |||
582 | 626 | | |||
583 | /******************************************************************/ | 627 | /******************************************************************/ | ||
584 | void KateBuildView::slotSelectTarget() { | 628 | void KateBuildView::slotSelectTarget() { | ||
585 | SelectTargetView *dialog = new SelectTargetView(&(m_targetsUi->targetsModel)); | 629 | SelectTargetView *dialog = new SelectTargetView(&(m_targetsUi->targetsModel)); | ||
586 | 630 | | |||
587 | dialog->setCurrentIndex(m_targetsUi->targetsView->currentIndex()); | 631 | dialog->setCurrentIndex(m_targetsUi->targetsView->currentIndex()); | ||
588 | 632 | | |||
589 | int result = dialog->exec(); | 633 | int result = dialog->exec(); | ||
590 | if (result == QDialog::Accepted) { | 634 | if (result == QDialog::Accepted) { | ||
591 | m_targetsUi->targetsView->setCurrentIndex(dialog->currentIndex()); | 635 | m_targetsUi->targetsView->setCurrentIndex(dialog->currentIndex()); | ||
592 | buildCurrentTarget(); | 636 | buildCurrentTarget(); | ||
593 | } | 637 | } | ||
594 | delete dialog; | 638 | delete dialog; | ||
595 | dialog = nullptr; | 639 | dialog = nullptr; | ||
596 | } | 640 | } | ||
597 | 641 | | |||
598 | 642 | | |||
599 | /******************************************************************/ | 643 | /******************************************************************/ | ||
600 | bool KateBuildView::buildCurrentTarget() | 644 | bool KateBuildView::buildCurrentTarget() | ||
601 | { | 645 | { | ||
602 | if (m_proc.state() != QProcess::NotRunning) { | 646 | if (m_proc.state() == QProcess::Running) { | ||
The state can also be QProcess::Starting. In some rare situations starting can be slow. I think its better to handle all cases. sars: The state can also be QProcess::Starting. In some rare situations starting can be slow. I think… | |||||
603 | displayBuildResult(i18n("Already building..."), KTextEditor::Message::Warning); | 647 | m_win->showToolView(m_toolView); | ||
604 | return false; | 648 | m_hideViewOnSuccess = 0; | ||
If the toolview is hidden we can open the toolview in stead of showing, the error message, but I would say that trying to start a new build should not effect whether or not the toolview is hidden at the end of the build. I also think we need to show the error message. The user might get the impression that a new build was already started. sars: If the toolview is hidden we can open the toolview in stead of showing, the error message, but… | |||||
649 | return true; | ||||
605 | } | 650 | } | ||
606 | 651 | | |||
607 | QFileInfo docFInfo = docUrl().toLocalFile(); // docUrl() saves the current document | 652 | QFileInfo docFInfo = docUrl().toLocalFile(); // docUrl() saves the current document | ||
608 | 653 | | |||
609 | QModelIndex ind = m_targetsUi->targetsView->currentIndex(); | 654 | QModelIndex ind = m_targetsUi->targetsView->currentIndex(); | ||
610 | m_previousIndex = ind; | 655 | m_previousIndex = ind; | ||
611 | if (!ind.isValid()) { | 656 | if (!ind.isValid()) { | ||
612 | KMessageBox::sorry(nullptr, i18n("No target available for building.")); | 657 | postMessage(i18n("No target available for building."), KTextEditor::Message::Error); | ||
613 | return false; | 658 | return false; | ||
614 | } | 659 | } | ||
615 | 660 | | |||
616 | QString buildCmd = m_targetsUi->targetsModel.command(ind); | 661 | QString buildCmd = m_targetsUi->targetsModel.command(ind); | ||
617 | QString cmdName = m_targetsUi->targetsModel.cmdName(ind); | 662 | QString cmdName = m_targetsUi->targetsModel.cmdName(ind); | ||
618 | QString workDir = m_targetsUi->targetsModel.workDir(ind); | 663 | QString workDir = m_targetsUi->targetsModel.workDir(ind); | ||
619 | QString targetSet = m_targetsUi->targetsModel.targetName(ind); | 664 | QString targetSet = m_targetsUi->targetsModel.targetName(ind); | ||
620 | 665 | | |||
621 | QString dir = workDir; | 666 | QString dir = workDir; | ||
622 | if (workDir.isEmpty()) { | 667 | if (workDir.isEmpty()) { | ||
623 | dir = docFInfo.absolutePath(); | 668 | dir = docFInfo.absolutePath(); | ||
624 | if (dir.isEmpty()) { | 669 | if (dir.isEmpty()) { | ||
625 | KMessageBox::sorry(nullptr, i18n("There is no local file or directory specified for building.")); | 670 | postMessage(i18n("There is no local file or directory specified for building."), KTextEditor::Message::Error); | ||
626 | return false; | 671 | return false; | ||
627 | } | 672 | } | ||
628 | } | 673 | } | ||
629 | 674 | | |||
630 | // Check if the command contains the file name or directory | 675 | // Check if the command contains the file name or directory | ||
631 | if (buildCmd.contains(QStringLiteral("%f")) || | 676 | if (buildCmd.contains(QStringLiteral("%f")) || | ||
632 | buildCmd.contains(QStringLiteral("%d")) || | 677 | buildCmd.contains(QStringLiteral("%d")) || | ||
633 | buildCmd.contains(QStringLiteral("%n"))) | 678 | buildCmd.contains(QStringLiteral("%n"))) | ||
634 | { | 679 | { | ||
635 | 680 | | |||
636 | if (docFInfo.absoluteFilePath().isEmpty()) { | 681 | if (docFInfo.absoluteFilePath().isEmpty()) { | ||
637 | return false; | 682 | return false; | ||
638 | } | 683 | } | ||
639 | 684 | | |||
640 | buildCmd.replace(QStringLiteral("%n"), docFInfo.baseName()); | 685 | buildCmd.replace(QStringLiteral("%n"), docFInfo.baseName()); | ||
641 | buildCmd.replace(QStringLiteral("%f"), docFInfo.absoluteFilePath()); | 686 | buildCmd.replace(QStringLiteral("%f"), docFInfo.absoluteFilePath()); | ||
642 | buildCmd.replace(QStringLiteral("%d"), docFInfo.absolutePath()); | 687 | buildCmd.replace(QStringLiteral("%d"), docFInfo.absolutePath()); | ||
643 | } | 688 | } | ||
689 | | ||||
690 | --m_hideViewOnSuccess; | ||||
644 | m_filenameDetectorGccWorked = false; | 691 | m_filenameDetectorGccWorked = false; | ||
645 | m_currentlyBuildingTarget = QStringLiteral("%1: %2").arg(targetSet, cmdName); | 692 | m_currentlyBuildingTarget = QStringLiteral("%1: %2").arg(targetSet, cmdName); | ||
646 | m_buildCancelled = false; | 693 | m_buildCancelled = false; | ||
647 | QString msg = i18n("Building target <b>%1</b> ...", m_currentlyBuildingTarget); | 694 | QString msg = i18n("Building target <b>%1</b> ...", m_currentlyBuildingTarget); | ||
648 | m_buildUi.buildStatusLabel->setText(msg); | 695 | m_buildUi.buildStatusLabel->setText(msg); | ||
649 | m_buildUi.buildStatusLabel2->setText(msg); | 696 | m_buildUi.buildStatusLabel2->setText(msg); | ||
697 | postMessage(i18n("Building target..."), KTextEditor::Message::Information, NeverHide); | ||||
698 | | ||||
650 | return startProcess(dir, buildCmd); | 699 | return startProcess(dir, buildCmd); | ||
651 | } | 700 | } | ||
652 | 701 | | |||
653 | /******************************************************************/ | 702 | /******************************************************************/ | ||
654 | void KateBuildView::displayBuildResult(const QString &msg, KTextEditor::Message::MessageType level) | 703 | void KateBuildView::postMessage(const QString &msg, KTextEditor::Message::MessageType type, int autoHideDelay/* = 0*/, bool updateOnly/* = false*/) | ||
655 | { | 704 | { | ||
656 | KTextEditor::View *kv = m_win->activeView(); | 705 | KTextEditor::View *kv = m_win->activeView(); | ||
657 | if (!kv) return; | 706 | if (!kv) return; | ||
658 | 707 | | |||
659 | delete m_infoMessage; | 708 | QString msgType; | ||
660 | m_infoMessage = new KTextEditor::Message(xi18nc("@info", "<title>Make Results:</title><nl/>%1", msg), level); | 709 | switch (type) { | ||
661 | m_infoMessage->setWordWrap(true); | 710 | // TODO KF6 How about a function in KTextEditor::Message to get these translated message type names? | ||
Why would this be a KF6 thing? Can't we just add another constructor/functin? Anyways the comment can be removed or moved to KTextEditor::Message sars: Why would this be a KF6 thing? Can't we just add another constructor/functin?
Anyways the… | |||||
662 | m_infoMessage->setPosition(KTextEditor::Message::BottomInView); | 711 | case KTextEditor::Message::Positive: | ||
663 | m_infoMessage->setAutoHide(5000); | 712 | case KTextEditor::Message::Information: | ||
Why the type change? You get a exitCode != 0 also if you only have a warning. sars: Why the type change? You get a exitCode != 0 also if you only have a warning. | |||||
I guess, I have assumed that in case of a warning "m_numWarnings" was set. And on a compile error "m_numErrors", so that we here have some other ugly error. loh.tar: I guess, I have assumed that in case of a warning "m_numWarnings" was set. And on a compile… | |||||
664 | m_infoMessage->setAutoHideMode(KTextEditor::Message::Immediate); | 713 | msgType = i18n("Info"); | ||
665 | m_infoMessage->setView(kv); | 714 | break; | ||
666 | kv->document()->postMessage(m_infoMessage); | 715 | case KTextEditor::Message::Warning: | ||
716 | msgType = i18n("Warning"); | ||||
717 | break; | ||||
718 | case KTextEditor::Message::Error: | ||||
719 | msgType = i18n("Error"); | ||||
720 | break; | ||||
721 | } | ||||
722 | | ||||
723 | if (updateOnly && m_infoMessage) { | ||||
724 | m_infoMessage->setText(xi18nc("@info", "<title>Make %1</title><nl/>%2", msgType, msg)); | ||||
725 | | ||||
726 | } else { | ||||
727 | delete m_infoMessage; | ||||
728 | // FIXME Add a minimum width to the message box, looks sometimes too titchy | ||||
729 | // m_infoMessage->setMinimumWidth(123) will not work, it's only an QOject | ||||
730 | // and attempts to add spaces failed. Update: Since we have the hourglass it looks much better | ||||
731 | // FIXME Sometimes on the change "progress info"->"we are done" the "progress info" | ||||
732 | // becomes the new size of "we are done" which cause an ungly line break. Ideas? | ||||
733 | m_infoMessage = new KTextEditor::Message(xi18nc("@info", "<title>Make %1</title><nl/>%2", msgType, msg), type); | ||||
734 | m_infoMessage->setWordWrap(true); | ||||
735 | m_infoMessage->setPosition(KTextEditor::Message::BottomInView); | ||||
736 | m_infoMessage->setAutoHide(autoHideDelay); | ||||
737 | m_infoMessage->setAutoHideMode(KTextEditor::Message::Immediate); | ||||
738 | m_infoMessage->setView(kv); | ||||
739 | kv->document()->postMessage(m_infoMessage); | ||||
740 | } | ||||
The idea is good, but until it works it is best to not output debug messages. If it would be possible to use the same plasma integrated progress indication as dolphin it would be nice, but if it would be only in the toolview you kinda already have it there. sars: The idea is good, but until it works it is best to not output debug messages.
If it would be… | |||||
667 | } | 741 | } | ||
668 | 742 | | |||
669 | /******************************************************************/ | 743 | /******************************************************************/ | ||
670 | void KateBuildView::slotProcExited(int exitCode, QProcess::ExitStatus) | 744 | void KateBuildView::slotProcExited(int exitCode, QProcess::ExitStatus) | ||
671 | { | 745 | { | ||
672 | QApplication::restoreOverrideCursor(); | 746 | QApplication::restoreOverrideCursor(); | ||
673 | m_buildUi.cancelBuildButton->setEnabled(false); | 747 | m_buildUi.cancelBuildButton->setEnabled(false); | ||
674 | m_buildUi.cancelBuildButton2->setEnabled(false); | 748 | m_buildUi.cancelBuildButton2->setEnabled(false); | ||
yurchor: Typo: progess -> progress | |||||
675 | m_buildUi.buildAgainButton->setEnabled(true); | 749 | m_buildUi.buildAgainButton->setEnabled(true); | ||
676 | m_buildUi.buildAgainButton2->setEnabled(true); | 750 | m_buildUi.buildAgainButton2->setEnabled(true); | ||
677 | 751 | | |||
678 | QString buildStatus = i18n("Building <b>%1</b> completed.", m_currentlyBuildingTarget); | 752 | QString buildStatus = i18n("Building <b>%1</b> completed.", m_currentlyBuildingTarget); | ||
679 | 753 | | |||
680 | // did we get any errors? | 754 | // did we get any errors? | ||
681 | if (m_numErrors || m_numWarnings || (exitCode != 0)) { | 755 | if (m_numErrors || m_numWarnings || (exitCode != 0)) { | ||
682 | m_buildUi.u_tabWidget->setCurrentIndex(1); | 756 | m_buildUi.u_tabWidget->setCurrentIndex(1); | ||
683 | if (m_buildUi.displayModeSlider->value() == 0) { | 757 | if (m_buildUi.displayModeSlider->value() == 0) { | ||
684 | m_buildUi.displayModeSlider->setValue(m_displayModeBeforeBuild > 0 ? m_displayModeBeforeBuild: 1); | 758 | m_buildUi.displayModeSlider->setValue(m_displayModeBeforeBuild > 0 ? m_displayModeBeforeBuild: 1); | ||
685 | } | 759 | } | ||
686 | m_buildUi.errTreeWidget->resizeColumnToContents(0); | 760 | m_buildUi.errTreeWidget->resizeColumnToContents(0); | ||
687 | m_buildUi.errTreeWidget->resizeColumnToContents(1); | 761 | m_buildUi.errTreeWidget->resizeColumnToContents(1); | ||
688 | m_buildUi.errTreeWidget->resizeColumnToContents(2); | 762 | m_buildUi.errTreeWidget->resizeColumnToContents(2); | ||
689 | m_buildUi.errTreeWidget->horizontalScrollBar()->setValue(0); | 763 | m_buildUi.errTreeWidget->horizontalScrollBar()->setValue(0); | ||
690 | //m_buildUi.errTreeWidget->setSortingEnabled(true); | 764 | //m_buildUi.errTreeWidget->setSortingEnabled(true); | ||
691 | m_win->showToolView(m_toolView); | 765 | m_win->showToolView(m_toolView); | ||
692 | } | 766 | } | ||
693 | 767 | | |||
694 | if (m_numErrors || m_numWarnings) { | 768 | if (m_buildCancelled) { | ||
769 | buildStatus = i18n("Building <b>%1</b> cancelled", m_currentlyBuildingTarget); | ||||
770 | postMessage(i18n("Build cancelled"), KTextEditor::Message::Information); | ||||
771 | | ||||
772 | } else if (m_numErrors || m_numWarnings) { | ||||
773 | m_troubleOnLastRun = true; | ||||
695 | QStringList msgs; | 774 | QStringList msgs; | ||
696 | if (m_numErrors) { | 775 | if (m_numErrors) { | ||
697 | msgs << i18np("Found one error.", "Found %1 errors.", m_numErrors); | 776 | msgs << i18np("Found one error.", "Found %1 errors.", m_numErrors); | ||
698 | buildStatus = i18n("Building <b>%1</b> had errors.", m_currentlyBuildingTarget); | 777 | buildStatus = i18n("Building <b>%1</b> had errors.", m_currentlyBuildingTarget); | ||
699 | } | 778 | } | ||
700 | else if (m_numWarnings) { | 779 | else if (m_numWarnings) { | ||
701 | msgs << i18np("Found one warning.", "Found %1 warnings.", m_numWarnings); | 780 | msgs << i18np("Found one warning.", "Found %1 warnings.", m_numWarnings); | ||
702 | buildStatus = i18n("Building <b>%1</b> had warnings.", m_currentlyBuildingTarget); | 781 | buildStatus = i18n("Building <b>%1</b> had warnings.", m_currentlyBuildingTarget); | ||
703 | } | 782 | } | ||
704 | displayBuildResult(msgs.join(QLatin1Char('\n')), m_numErrors ? KTextEditor::Message::Error : KTextEditor::Message::Warning); | 783 | postMessage(msgs.join(QLatin1Char('\n')), m_numErrors ? KTextEditor::Message::Error : KTextEditor::Message::Warning); | ||
705 | } | | |||
706 | else if (exitCode != 0) { | | |||
707 | displayBuildResult(i18n("Build failed."), KTextEditor::Message::Warning); | | |||
708 | } | | |||
709 | else { | | |||
710 | displayBuildResult(i18n("Build completed without problems."), KTextEditor::Message::Positive); | | |||
711 | } | | |||
712 | 784 | | |||
713 | if (!m_buildCancelled) { | 785 | } else if (exitCode != 0) { | ||
714 | m_buildUi.buildStatusLabel->setText(buildStatus); | 786 | postMessage(i18n("Build failed."), KTextEditor::Message::Error); | ||
715 | m_buildUi.buildStatusLabel2->setText(buildStatus); | 787 | | ||
716 | m_buildCancelled = false; | 788 | } else { | ||
789 | postMessage(i18n("Build completed without problems."), KTextEditor::Message::Positive); | ||||
790 | if (m_isSetAutoHide && (m_hideViewOnSuccess > 0) && m_troubleOnLastRun) { | ||||
791 | m_win->hideToolView(m_toolView); | ||||
792 | } | ||||
793 | m_troubleOnLastRun = false; | ||||
717 | } | 794 | } | ||
718 | 795 | | |||
796 | m_buildUi.buildStatusLabel->setText(buildStatus); | ||||
797 | m_buildUi.buildStatusLabel2->setText(buildStatus); | ||||
798 | m_hideViewOnSuccess = 0; | ||||
719 | } | 799 | } | ||
720 | 800 | | |||
721 | 801 | | |||
722 | /******************************************************************/ | 802 | /******************************************************************/ | ||
723 | void KateBuildView::slotReadReadyStdOut() | 803 | void KateBuildView::slotReadReadyStdOut() | ||
724 | { | 804 | { | ||
725 | // read data from procs stdout and add | 805 | // read data from procs stdout and add | ||
726 | // the text to the end of the output | 806 | // the text to the end of the output | ||
727 | // FIXME This works for utf8 but not for all charsets | 807 | // FIXME This works for utf8 but not for all charsets | ||
728 | QString l = QString::fromUtf8(m_proc.readAllStandardOutput()); | 808 | QString l = QString::fromUtf8(m_proc.readAllStandardOutput()); | ||
729 | l.remove(QLatin1Char('\r')); | 809 | l.remove(QLatin1Char('\r')); | ||
730 | m_stdOut += l; | 810 | m_stdOut += l; | ||
731 | 811 | | |||
812 | QRegularExpression regExp = QRegularExpression(QStringLiteral("^\\[\\s*([\\d\\%]+)\\]")); | ||||
813 | QString hourglass(QStringLiteral("--------------")); | ||||
814 | static int hourglassIdx = -1; | ||||
815 | | ||||
732 | // handle one line at a time | 816 | // handle one line at a time | ||
733 | do { | 817 | do { | ||
734 | const int end = m_stdOut.indexOf(QLatin1Char('\n')); | 818 | const int end = m_stdOut.indexOf(QLatin1Char('\n')); | ||
735 | if (end < 0) break; | 819 | if (end < 0) break; | ||
736 | 820 | | |||
737 | const QString line = m_stdOut.mid(0, end); | 821 | const QString line = m_stdOut.mid(0, end); | ||
738 | m_buildUi.plainTextEdit->appendPlainText(line); | 822 | m_buildUi.plainTextEdit->appendPlainText(line); | ||
739 | //qDebug() << line; | 823 | //qDebug() << line; | ||
740 | 824 | | |||
825 | QRegularExpressionMatch match = regExp.match(line); | ||||
826 | if (match.hasMatch() && !m_progressLimiter.isActive()) { | ||||
827 | m_progressLimiter.start(); | ||||
828 | hourglassIdx = (++hourglassIdx > hourglass.size() - 1) ? 0 : hourglassIdx; | ||||
829 | hourglass.replace(hourglassIdx, 1, QLatin1Char('>')); | ||||
830 | postMessage(i18n("Building target\n%1 %2 %1", hourglass, QStringLiteral("%1").arg(match.captured(1), 4, QLatin1Char(' '))) | ||||
831 | , KTextEditor::Message::Information, NeverHide, OnlyUpdateMessageText); | ||||
832 | } | ||||
833 | | ||||
741 | if (m_newDirDetector.match(line).hasMatch()) { | 834 | if (m_newDirDetector.match(line).hasMatch()) { | ||
742 | //qDebug() << "Enter/Exit dir found"; | 835 | //qDebug() << "Enter/Exit dir found"; | ||
743 | int open = line.indexOf(QLatin1Char('`')); | 836 | int open = line.indexOf(QLatin1Char('`')); | ||
744 | int close = line.indexOf(QLatin1Char('\'')); | 837 | int close = line.indexOf(QLatin1Char('\'')); | ||
745 | QString newDir = line.mid(open+1, close-open-1); | 838 | QString newDir = line.mid(open+1, close-open-1); | ||
746 | //qDebug () << "New dir = " << newDir; | 839 | //qDebug () << "New dir = " << newDir; | ||
747 | 840 | | |||
748 | if ((m_make_dir_stack.size() > 1) && (m_make_dir_stack.top() == newDir)) { | 841 | if ((m_make_dir_stack.size() > 1) && (m_make_dir_stack.top() == newDir)) { | ||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Line(s) | 1144 | { | |||
1054 | QKeyEvent *k = static_cast<QKeyEvent *>(e); | 1147 | QKeyEvent *k = static_cast<QKeyEvent *>(e); | ||
1055 | if (k->key() == Qt::Key_Escape && k->modifiers() == Qt::NoModifier) { | 1148 | if (k->key() == Qt::Key_Escape && k->modifiers() == Qt::NoModifier) { | ||
1056 | if (m_toolView->isVisible()) { | 1149 | if (m_toolView->isVisible()) { | ||
1057 | m_win->hideToolView(m_toolView); | 1150 | m_win->hideToolView(m_toolView); | ||
1058 | } | 1151 | } | ||
1059 | } | 1152 | } | ||
1060 | } | 1153 | } | ||
1061 | 1154 | | |||
1155 | //BEGIN ConfigPage | ||||
1156 | KateBuildPluginConfigPage::KateBuildPluginConfigPage(QWidget *parent, KateBuildPlugin *plugin) | ||||
1157 | : KTextEditor::ConfigPage(parent) | ||||
1158 | , m_plugin(plugin) | ||||
1159 | { | ||||
1160 | setupUi(this); | ||||
1161 | loadSettings(); | ||||
1162 | | ||||
1163 | // FIXME Add observeChanges(..) to master class like in KateConfigPage, best may in KTextEditor::ConfigPage | ||||
1164 | connect(autoHide, &QAbstractButton::toggled, this, &KateBuildPluginConfigPage::modified); | ||||
1165 | connect(avoidPopUp, &QAbstractButton::toggled, this, &KateBuildPluginConfigPage::modified); | ||||
1166 | connect(avoidToolTips, &QAbstractButton::toggled, this, &KateBuildPluginConfigPage::modified); | ||||
1167 | } | ||||
1168 | | ||||
1169 | KateBuildPluginConfigPage::~KateBuildPluginConfigPage() | ||||
1170 | {} | ||||
1171 | | ||||
1172 | // FIXME Should be part of master class | ||||
1173 | void KateBuildPluginConfigPage::modified() | ||||
1174 | { | ||||
1175 | m_modified = true; | ||||
1176 | emit changed(); | ||||
1177 | } | ||||
1178 | QString KateBuildPluginConfigPage::name() const | ||||
1179 | { | ||||
1180 | return i18n("Build"); | ||||
1181 | } | ||||
1182 | | ||||
1183 | QString KateBuildPluginConfigPage::fullName() const | ||||
1184 | { | ||||
1185 | return i18n("%1 Settings", name()); | ||||
1186 | } | ||||
1187 | | ||||
1188 | QIcon KateBuildPluginConfigPage::icon() const | ||||
1189 | { | ||||
1190 | return QIcon::fromTheme(QStringLiteral("project_rebuild")); | ||||
1191 | } | ||||
1192 | | ||||
1193 | void KateBuildPluginConfigPage::apply() | ||||
1194 | { | ||||
1195 | if (!m_modified) { | ||||
1196 | return; | ||||
1197 | } | ||||
1198 | | ||||
1199 | m_modified = false; | ||||
1200 | | ||||
1201 | KConfigGroup config(KSharedConfig::openConfig(), "Build"); | ||||
1202 | | ||||
1203 | config.writeEntry("AutoHide", autoHide->isChecked()); | ||||
1204 | config.writeEntry("NoPopUp", avoidPopUp->isChecked()); | ||||
1205 | config.writeEntry("NoToolTips", avoidToolTips->isChecked()); | ||||
1206 | | ||||
1207 | config.sync(); | ||||
1208 | | ||||
1209 | m_plugin->readConfig(); | ||||
1210 | } | ||||
1211 | | ||||
1212 | void KateBuildPluginConfigPage::loadSettings() | ||||
1213 | { | ||||
1214 | KConfigGroup config(KSharedConfig::openConfig(), "Build"); | ||||
1215 | | ||||
1216 | autoHide->setChecked(config.readEntry("AutoHide", false)); | ||||
1217 | avoidPopUp->setChecked(config.readEntry("NoPopUp", false)); | ||||
1218 | avoidToolTips->setChecked(config.readEntry("NoToolTips", false)); | ||||
1219 | | ||||
1220 | // In oposite to the statet WhatsThis help, we don't remove what's not there, but add :-) | ||||
1221 | if (!avoidToolTips->isChecked()) { | ||||
1222 | autoHide->setToolTip(autoHide->whatsThis()); | ||||
1223 | avoidPopUp->setToolTip(avoidPopUp->whatsThis()); | ||||
1224 | avoidToolTips->setToolTip(avoidToolTips->whatsThis()); | ||||
1225 | } | ||||
1226 | } | ||||
1227 | | ||||
1228 | //END ConfigPage | ||||
1062 | 1229 | | |||
1063 | #include "plugin_katebuild.moc" | 1230 | #include "plugin_katebuild.moc" | ||
1064 | 1231 | | |||
1065 | // kate: space-indent on; indent-width 4; replace-tabs on; | 1232 | // kate: space-indent on; indent-width 4; replace-tabs on; | ||
Context not available. |
Please increase the time, in case we have really long builds that progress slowly ;)