#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "settings.h" #include "mdemList.h" #include "trainWindow.h" #include "api.h" #include "parser.h" // Atmiņas bāze. QString currentMbasePath = ""; std::string currentMdemPath = ""; QFileSystemModel *model; QTreeView *mdemList; std::map buffers; MdemBuffer *currentMdemBuffer; // Atmiņas kaartīšu saraksts. std::vector mdems = std::vector(); QVBoxLayout *hMdemScroll; QSpacerItem *mdemSpacer; ErrorView *errorView; Pagination *pagination; int perPage; // Redaktors. QsciScintilla *editor; QMainWindow *editorWindow; Mdem *editMdem; // Augšēja informācija. QLabel *membaseLabel; QLabel *mdemLabel; QLabel *lastPracticeLabel; QMainWindow *trainWindow; /* * Atmiņas kartītei parāda visus slēptos elementus. * */ void showBacklabels(Mdem *mdem) { for (size_t i = 0; i < mdem->backLabels.size(); ++i) { if (i < mdem->labelCount) { if (!mdem->backLabels[i]->isVisible()) { mdem->backLabels[i]->show(); } } else { if (mdem->backLabels[i]->isVisible()) { mdem->backLabels[i]->hide(); } } } } /* * Izveido jautājuma kartīšu pirmkodu ar norādītu trenešanas laiku. * Papildus konfigurācijai var norādīt platumu pirms jaunas rindas un laika zonu. */ std::string outputMdem( std::vector questions, time_t time = 0, const int wrapWidth = 80, const int timezoneOffset = 0 ) { std::stringstream ss; // Ja ir saistīts laiks, ja tāds ir. if (time > 0) { std::tm* tm = std::localtime(&time); char buffer[100]; std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H\\:%M", tm); auto time = std::string(buffer); ss << time << std::endl; } // Detranspilē katru jautājumu. for (auto question: questions) { // Pārtraukums. ss << std::endl; std::string cooldownPart; if (question->cooldown != 0) { cooldownPart = std::format(" [{:.2f}]", question->cooldown); } // Jautājuma teksts. ss << wrapLine( std::format("-{}{} >\n", cooldownPart, " " + escapeText(question->questionText)), wrapWidth ); // Detranspilē atbilstoši veidam. if (MultiElementQuestion* mw = dynamic_cast(question)) { for (auto choice: mw->choices) { char opener; if (choice.isCorrect) { opener = '+'; } else { opener = '-'; } std::string orderModifier; if (mw->type == MultiElementType::Order) { orderModifier = "^"; } ss << wrapLine( std::format( "\t{}{} {}\n", opener, orderModifier, escapeText(choice.answer) ) , wrapWidth); } } else if (GroupQuestion* gq = dynamic_cast(question)) { for (auto group: gq->groups) { ss << wrapLine( std::format( "\t- {}:\n", escapeText(group.name) ) , wrapWidth); for (auto element: group.elements) { ss << wrapLine( std::format( "\t\t- {}\n", escapeText(element) ) , wrapWidth); } } } } return ss.str(); } /* * Izveido lappušu objektus atbilstoši jautājumu skaitam vienā lapā. * */ void makePages() { pagination->pages.clear(); auto len = currentMdemBuffer->questions.size(); perPage = settings->value(SETTING_PER_PAGE).toInt(); auto pageAmount = len / perPage; // Papildus lapa, ja objektu skaits nedalās tieši un paliek papildus kartītes. if (len % perPage != 0) { pageAmount += 1; } // Veido lappuses objektus. for (size_t i = 0; i < pageAmount; i++) { size_t startingIndex = perPage * i ; size_t amount = perPage; if (i == currentMdemBuffer->questions.size() / perPage) { amount = currentMdemBuffer->questions.size() % perPage; } pagination->pages.push_back( Page{startingIndex, startingIndex + amount} ); } // Ja tiek noņemts pēdējais lappuses elements, pārliek lappusi uz iepriekšējo. if (pagination->pages.size() > 1 && pagination->currentPage >= pagination->pages.size()) { --pagination->currentPage; } } /* * Uzstāda atmiņas kartīti ar jebkura veida jautājuma. * Uzstāda jautājuma tekstu un pievieno/uzstāda atbildes elementus. * */ void setupMdem(Mdem *mdem, Question *question) { // Priekšas teksts. std::stringstream ss; if (question->cooldown > 0) { ss << std::format("[{:.2f}] ", question->cooldown); } ss << question->questionText; mdem->wFrontText.setText( QString::fromStdString(ss.str()) ); if (MultiElementQuestion* mw = dynamic_cast(question)) { auto choices = mw->choices; // Pievieno vairākus elementus atbilstoši veidam. for (size_t k = 0; k < choices.size(); ++k) { auto answer = choices[k].answer; // Sagatavo elementu. switch (mw->type) { case MultiElementType::Order: answer = std::format("{}. {}", k + 1, answer); break; case MultiElementType::MultiChoice: if (choices[k].isCorrect) { answer = std::format("+ {}", answer); } else { answer = std::format("- {}", answer); } break; case MultiElementType::Regular: answer = std::format("- {}", answer); break; } // Pievieno elementu. if (k < mdem->backLabels.size()) { mdem->backLabels[k]->setText(QString::fromStdString(answer)); } else { auto label = new QLabel(); label->setText(QString::fromStdString(answer)); mdem->backLabels.push_back(label); mdem->wBack.layout()->addWidget(label); } } mdem->labelCount = choices.size(); } else if (GroupQuestion* mw = dynamic_cast(question)) { auto groups = mw->groups; std::vector elements; // Sagatovo grupas un elementus. for (size_t k = 0; k < groups.size(); ++k) { auto answer = groups[k].name; elements.push_back(std::format("- {}:", answer)); for (size_t l = 0; l < groups[k].elements.size(); ++l) { elements.push_back(std::format(" - {}", groups[k].elements[l])); } } // Pievieno grupas un elementus. for (size_t k = 0; k < elements.size(); ++k) { if (k < mdem->backLabels.size()) { mdem->backLabels[k]->setText(QString::fromStdString(elements[k])); } else { auto label = new QLabel(); label->setText(QString::fromStdString(elements[k])); mdem->backLabels.push_back(label); mdem->wBack.layout()->addWidget(label); } } mdem->labelCount = elements.size(); } } void switchPage(int pageIdx); /* * Iegūst faila nosaukumu no faila ceļa. */ std::string getFilename(std::string path) { static const std::regex lastPathElementExp = std::regex("(.+\\/)*(.+)"); std::smatch matches; std::regex_search(path, matches, lastPathElementExp); return matches[2].str(); } /* * Atjauno atmiņas kartīšu faila augšējo informāciju. * */ void updateMdemInfo(std::string filename, bool isChanged) { currentMdemBuffer->isModified = isChanged; if (filename.length() > 0) { std::stringstream ss; ss << std::format("Atmiņas kartīšu fails: {}", filename); if (isChanged) { ss << "*"; } mdemLabel->setText(QString::fromStdString(ss.str())); ss.str(""); if (currentMdemBuffer->trainedAt > 0) { std::tm* tm = std::localtime(¤tMdemBuffer->trainedAt); char buffer[100]; std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H:%M", tm); ss << "Pēdējā mācīšanās reize: " << std::string(buffer); } lastPracticeLabel->setText(QString::fromStdString(ss.str())); } else { mdemLabel->setText(""); lastPracticeLabel->setText(""); } } /* * Izveido atmiņas kartīti un visus tās elementus. * */ Mdem* makeMdem() { auto mdem = new Mdem; mdem->wMdem.setLayout(&mdem->vMdem); // Priekša. QString id = QString("mdem_%1").arg(1); mdem->wMdem.setObjectName(id); mdem->wFront.setMinimumHeight(70); mdem->wFront.setLayout(&mdem->hFront); mdem->wFront.setProperty("first", "true"); mdem->wMdem.setStyleSheet(QString( "QWidget#%1 > QWidget {" "border-right: 1px solid gray;" "border-bottom: 1px solid gray;" "border-left: 1px solid gray;" "background: %2;" "} " "QWidget#%1 > QWidget[first=\"true\"] {" "border-top: 1px solid gray;" "}" ).arg(id, MDEM_BACKGROUND)); // Saturs. mdem->wFrontText.setWordWrap(true); mdem->wFrontText.setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ); mdem->hFront.addWidget(&mdem->wFrontText); // Rediģēšanas poga. mdem->editButton.setText("Rediģēt"); QObject::connect( &mdem->editButton, &QToolButton::clicked, [mdem]() { editMdem = mdem; if (mdem->question) { int wrap_width = 80; if (settings->contains(SETTING_CHARACTER_WRAP)) { wrap_width = settings->value(SETTING_CHARACTER_WRAP).toInt(); } editor->setText( QString::fromStdString( outputMdem(std::vector{mdem->question}, 0, wrap_width) ) ); editorWindow->show(); editor->setCursorPosition(1, 2); } } ); mdem->hFront.addWidget(&mdem->editButton); // Dzēšanas poga. mdem->deleteButton.setText("Dzēst"); QObject::connect( &mdem->deleteButton, &QToolButton::clicked, [mdem]() { if (mdem->question) { Question* deleted = nullptr; for (size_t i = 0; i < currentMdemBuffer->questions.size(); ++i) { if (currentMdemBuffer->questions[i] == mdem->question) { currentMdemBuffer->questions.erase(currentMdemBuffer->questions.begin() + i); delete mdem->question; mdem->question = nullptr; updateMdemInfo(getFilename(currentMdemPath), true); break; } } makePages(); switchPage(pagination->currentPage); } if (editMdem == mdem) { editorWindow->hide(); } } ); mdem->hFront.addWidget(&mdem->deleteButton); // Aizmugura. mdem->wBack.setLayout(&mdem->hBack); mdem->vMdem.addWidget(&mdem->wBack); // Aizmuguras saturs. for (size_t i = 0; i < 20; ++i) { // @Improve: back label pooling QLabel *elBackText = new QLabel(); mdem->hBack.addWidget(elBackText); mdem->backLabels.push_back(elBackText); } mdem->vMdem.addWidget(&mdem->wFront); mdem->vMdem.addWidget(&mdem->wBack); mdem->vMdem.setContentsMargins(0, 0, 0, 0); mdem->vMdem.setSpacing(0); mdem->wBack.hide(); mdem->wMdem.hide(); // Atbildes parādīšanas poga. mdem->toggleVisibility.setText("Parādīt"); mdem->hFront.addWidget(&mdem->toggleVisibility); QObject::connect(&mdem->toggleVisibility, &QToolButton::clicked, [mdem]() { if (mdem->wBack.isVisible()) { mdem->wBack.hide(); mdem->toggleVisibility.setText("Parādīt"); } else { mdem->wBack.show(); mdem->toggleVisibility.setText("Slēpt"); } showBacklabels(mdem); }); return mdem; } /* * Izveido rādāmās kartītes (argumentam nedrīkst pārniegt maksimāli iespējamo daudzumu lapā). * */ void createMdems(std::vector& questions) { hMdemScroll->removeItem(mdemSpacer); // Paslēp visas atmiņas kartītes. for (Mdem *mdem : mdems) { if (mdem->wMdem.isVisible()) { mdem->wMdem.hide(); } } // Pievieno atmiņas kartītes, ja nepieciešamais daudzums pārsniedz esošo. perPage = settings->value(SETTING_PER_PAGE).toInt(); if (perPage > mdems.size()) { for (size_t i = mdems.size(); i < perPage; i++) { if (i >= mdems.size()) { auto mdem = makeMdem(); mdems.push_back(mdem); hMdemScroll->addWidget(&mdem->wMdem); } } } // Parāda nepieciešamās atmiņas kartītes. for (size_t i = 0; i < questions.size(); ++i) { mdems[i]->question = questions[i]; setupMdem(mdems[i], questions[i]); if (!mdems[i]->wMdem.isVisible()) { mdems[i]->wMdem.show(); } } hMdemScroll->addItem(mdemSpacer); } /* * Atjauno sarakstu un tā informāciju. */ void update(bool isChanged) { if (pagination->currentPage > -1) { switchPage(pagination->currentPage); } if (currentMdemPath.length() > 0) { updateMdemInfo(getFilename(currentMdemPath), isChanged); } } void switchPage(int pageIdx) { pagination->currentPage = pageIdx; // Paslēp visas lappušu pogas. for (auto& button : pagination->paginationButtons) { button->hide(); } int l = 0; char buffer[50]; snprintf(buffer, sizeof(buffer), "Lappuse: %d", pageIdx + 1); pagination->paginationLabel.setText(buffer); // Paslēp atbilžu elementus. for (auto& mdem : mdems) { if (mdem->wBack.isVisible()) { mdem->wBack.hide(); mdem->toggleVisibility.setText("Parādīt"); } } // Atjauno lappušu pogas. for (int k = -DISTANCE; k <= DISTANCE; ++k) { if (pageIdx + k >= 0 && pageIdx + k < pagination->pages.size()) { auto button = pagination->paginationButtons[l]; snprintf(buffer, sizeof(buffer), "%d", pageIdx + k + 1); button->setText(buffer); if (pageIdx + k != pageIdx) { button->show(); } else { button->hide(); } ++l; } } // Pirmās un pēdējās pogas redzamība. if (pageIdx > 0 && pagination->pages.size() > 1) { pagination->firstButton.show(); } else { pagination->firstButton.hide(); } if (pageIdx < pagination->pages.size() - 1 && pagination->pages.size() > 1) { pagination->lastButton.show(); } else { pagination->lastButton.hide(); } // Iepriekšējās pogas redzamība. if (!pagination->pages.empty() && pagination->currentPage >= 1) { pagination->prevButton.show(); } else { pagination->prevButton.hide(); } // Nākamās pogas redzamība. if (!pagination->pages.empty() && pagination->currentPage < pagination->pages.size() - 1) { pagination->nextButton.show(); } else { pagination->nextButton.hide(); } Page page; // Samazina lappuses numuru, ja pēdējai lappusei nepietiek atmiņas kartīšu. if (pagination->pages.size() <= 0) { // Nav lapu -> veidojam tukšu lapu. page = Page(); } else if (pageIdx < pagination->pages.size()){ // Pieprasītā lapa eksistē -> atgriežam to. page = pagination->pages[pageIdx]; } else { // Pieprasītā lapa eksistē -> atgriežam iepriekšējo. page = pagination->pages[pageIdx - 1]; } // Izveido lappusi. std::vector pageSlice( currentMdemBuffer->questions.begin() + page.start, currentMdemBuffer->questions.begin() + page.end ); createMdems(pageSlice); } void reloadMdem(std::string path) { if (path == "") { return; } auto toRemove = std::vector(); for (auto it = buffers.begin(); it != buffers.end(); ++it) { auto pair = *it; if (currentMdemPath.compare(path) != 0 && (!pair.second->isModified || pair.second->error)) { toRemove.push_back(pair.first); } } for (auto key: toRemove) { buffers.erase(key); } MdemBuffer *buffer; auto filename = getFilename(path); if (currentMdemPath.compare(path) == 0) { currentMdemPath = path; if (buffers.contains(path)) { buffers.erase(path); } } else if (!buffers.contains(path)) { buffer = new MdemBuffer; buffers[path] = buffer; currentMdemBuffer = buffer; currentMdemPath = path; } else { buffer = buffers[path]; currentMdemBuffer = buffer; makePages(); switchPage(0); updateMdemInfo(getFilename(filename), buffer->isModified); currentMdemPath = path; errorView->box.hide(); return; } start = std::chrono::high_resolution_clock::now(); auto file = std::ifstream(path); std::string content; // Atiestata atmiņas kartīšu sarakstu. for (auto mdem: mdems) { mdem->wMdem.hide(); } for (auto question: currentMdemBuffer->questions) { delete question; } currentMdemBuffer->questions.clear(); if (file) { std::stringstream buffer; buffer << file.rdbuf(); content = buffer.str(); end = std::chrono::high_resolution_clock::now(); showTimes = settings->value(SETTING_SHOW_TIMES).toBool(); if (showTimes) { std::cout << showTime("I/O laiks") << std::endl; } debug = settings->value(SETTING_DEBUG).toBool(); auto res = transpile(content); currentMdemBuffer->error = res.error.length() > 0; if (res.error == "") { if (res.value.lastTrainedAt == 0) { currentMdemBuffer->trainedAt = 0; } else { auto timezoneOffset = settings->value("timezone").toInt(); currentMdemBuffer->trainedAt = res.value.lastTrainedAt - 3600 * timezoneOffset; } if (settings->value(SETTING_DEBUG).toBool()) { std::cout << std::format("Pēdējās mācīšanās reize: {}", currentMdemBuffer->trainedAt) << std::endl; } currentMdemBuffer->questions = res.value.questions; errorView->box.hide(); } else { currentMdemBuffer->trainedAt = 0; std::cout << std::format("Transpilācijas kļūda: {}", res.error) << std::endl; for (auto question: res.value.questions) { delete question; } // Parāda kļūdu. hMdemScroll->removeItem(mdemSpacer); errorView->label.setText( QString::fromStdString( std::format( "Kļūda, transpilējot {}: {} ({}:{})", filename, res.error, res.row, res.column ) ) ); errorView->box.show(); hMdemScroll->addWidget(&errorView->box); hMdemScroll->addItem(mdemSpacer); } makePages(); switchPage(0); updateMdemInfo(filename, false); } else { std::cout << std::format("Nevar atvert failu: {}", currentMbasePath.toStdString()) << std::endl; } for (auto mdem: mdems) { mdem->wBack.hide(); mdem->toggleVisibility.setText("Parādīt"); } hideQuestionElements(); } void pickDirectory(QString directory) { auto path = std::filesystem::path(directory.toStdString()); if ( !std::filesystem::exists(directory.toStdString()) || !std::filesystem::is_directory(directory.toStdString()) ) { QMessageBox::information( nullptr, "Kļūda", "Direktorijs, kas ir norādīts kā noklusētais, neeksistē." ); return; } // Pārbauda direktorija lasāmību try { auto tempFile = path.concat("/.writetest.tmp").string(); std::ofstream file(tempFile); if (file) { file.close(); std::filesystem::remove(tempFile); } else { QMessageBox::information( nullptr, "Atveršanas kļūda", "Izvēlētajā direktorijā nav iespējams rakstīt." ); currentMbasePath = ""; return; } } catch (const std::exception& e) { QMessageBox::information( nullptr, "Atveršanas kļūda", "Neizdevās pārbaudīt izvēlētā direktorija rakstāmību." ); currentMbasePath = ""; return; } currentMbasePath = directory; // Atjauno failu sarakstu. if (directory.length() <= 0) { membaseLabel->setText(directory); return; } mdemList->setRootIndex(model->setRootPath(directory)); std::smatch matches; // Atjauno teksta elementu. membaseLabel->setText(QString::fromStdString( std::format( "Atmiņas bāze: {}", getFilename(currentMbasePath.toStdString()) ) )); reloadMdem(""); } void setupEditorSave() { const QString title = editMdem ? "Rediģēšanas kļūda" : "Pievienošanas kļūda"; debug = settings->value(SETTING_DEBUG).toBool(); showTimes = settings->value(SETTING_SHOW_TIMES).toBool(); auto res = transpile(editor->text().toStdString()); if (res.error.length() > 0) { currentMdemBuffer->trainedAt = 0; for (auto question: res.value.questions) { delete question; } QMessageBox::information( nullptr, title, QString::fromStdString(res.error) ); } else { if (editMdem) { if (res.value.questions.size() <= 0) { QMessageBox::information( nullptr, title, "Jūsu ievadē nav jautājumu." ); } else if (res.value.questions.size() == 1) { auto oldQuestion = editMdem->question; editMdem->question = res.value.questions[0]; for (size_t i = 0; i < currentMdemBuffer->questions.size(); ++i) { if (currentMdemBuffer->questions[i] == oldQuestion) { currentMdemBuffer->questions.erase(currentMdemBuffer->questions.begin() + i); delete oldQuestion; currentMdemBuffer->questions.insert(currentMdemBuffer->questions.begin() + i, res.value.questions[0]); break; } } setupMdem(editMdem, res.value.questions[0]); showBacklabels(editMdem); editorWindow->hide(); updateMdemInfo(getFilename(currentMdemPath), true); } else { QMessageBox::information( nullptr, title, "Jūsu ievadē ir vairāki jautājumi. Lūdzu ievadiet vienu!" ); } } else { if (res.value.questions.size() <= 0) { QMessageBox::information( nullptr, title, "Jūsu ievadē nav jautājumu." ); } else { currentMdemBuffer->questions.insert( currentMdemBuffer->questions.begin(), res.value.questions.begin(), res.value.questions.end() ); makePages(); switchPage(0); editorWindow->hide(); updateMdemInfo(getFilename(currentMdemPath), true); } } } }; void saveMdem() { start = std::chrono::high_resolution_clock::now(); std::filesystem::path dir(currentMdemPath); auto parentPath = dir.parent_path(); if (!parentPath.empty() && !std::filesystem::exists(parentPath)) { if (!std::filesystem::create_directories(parentPath)) { QMessageBox::information( nullptr, "Kļūda", "Neizdevās izveidot direktorijus faila saglabāšanai." ); } } auto filename = getFilename(currentMdemPath); std::ofstream out(currentMdemPath); int wrap_width = 80; if (settings->contains(SETTING_CHARACTER_WRAP)) { wrap_width = settings->value(SETTING_CHARACTER_WRAP).toInt(); } int timezoneOffset = 0; if (settings->contains(SETTING_TIMEZONE)) { timezoneOffset = settings->value(SETTING_TIMEZONE).toInt(); } out << outputMdem( currentMdemBuffer->questions, currentMdemBuffer->trainedAt, wrap_width, timezoneOffset ); updateMdemInfo(getFilename(currentMdemPath), false); end = std::chrono::high_resolution_clock::now(); showTimes = settings->value(SETTING_SHOW_TIMES).toBool(); if (showTimes) { std::cout << showTime("Saglabāšanas laiks") << std::endl; } } /* * Inicializē visus atmiņas kartīšu saraksta elementus un izvēlni. */ QMainWindow *initMdemListWindow() { QMainWindow* window = new QMainWindow; pagination = new Pagination; auto *toolbar = new Toolbar(); // Saistīti logi. auto *settingsWindow = initSettings(); trainWindow = initTrainWindow(); trainWindow->resize(800, 600); QMainWindow *guideWindow = new QMainWindow; { // Apmācības logs. auto guideWidget = new QWidget; auto *layout = new QVBoxLayout; auto *textBrowser = new QTextBrowser; textBrowser->setSource(QUrl("qrc:/html/help.html")); textBrowser->zoomIn(2); layout->addWidget(textBrowser); guideWidget->setLayout(layout); guideWindow->setCentralWidget(guideWidget); guideWindow->resize(800, 600); } QAction *actionOpen; QAction *revealMbase; QAction *openSettings; QAction *actionHelp; { // Izvēlne. QMenuBar *menuBar = new QMenuBar; QFileDialog *fileDialog = new QFileDialog; QMenu *menu = new QMenu("Darbības"); menu->setStyleSheet("font-size: 15px;"); actionOpen = menu->addAction("Atvērt atmiņas bāzi (Ctrl+O)"); QObject::connect( actionOpen, &QAction::triggered, [fileDialog]() { fileDialog->setDirectory(QDir::homePath()); fileDialog->setFileMode(QFileDialog::FileMode::Directory); if ( !currentMbasePath.isEmpty() && std::filesystem::exists(currentMbasePath.toStdString()) ) { fileDialog->setDirectory(currentMbasePath); } fileDialog->open(); QObject::disconnect(fileDialog, 0, 0, 0); fileDialog->connect( fileDialog, &QFileDialog::fileSelected, pickDirectory ); } ); revealMbase = menu->addAction("Atvērt atmiņas bāzi failu pārlūkā (Ctrl+M)"); QObject::connect( revealMbase, &QAction::triggered, []() { auto directoryUrl = QUrl::fromLocalFile( QDir(currentMbasePath).absolutePath() ); if (!QDesktopServices::openUrl(directoryUrl)) { QMessageBox::information( nullptr, "Kļūda", "Neizdevās atvērt atmiņas bāzi failu pārlūkā." ); } } ); openSettings = menu->addAction("Iestatījumi (Ctrl+,)"); QObject::connect( openSettings, &QAction::triggered, [settingsWindow]() { settingsWindow->show(); }); actionHelp = menu->addAction("Palīdzība (Ctrl+H)"); QObject::connect( actionHelp, &QAction::triggered, [guideWindow]() { guideWindow->show(); } ); menuBar->addMenu(menu); window->setMenuBar(menuBar); } { // Redaktors. editorWindow = new QMainWindow; editorWindow->setWindowTitle("Jautājumu redaktors"); editorWindow->resize(800, 600); QWidget *wEditor = new QWidget; QVBoxLayout *vlEditor = new QVBoxLayout; wEditor->setLayout(vlEditor); QsciLexerCPP *lexer = new QsciLexerCPP; editor = new QsciScintilla; editor->setLexer(lexer); editor->setUtf8(true); editor->setMarginWidth(0, 15); editor->zoomIn(2); QHBoxLayout *buttonLayout = new QHBoxLayout; QWidget *editorButtons = new QWidget; auto btnSaveEditor = new QPushButton; editorButtons->setLayout(buttonLayout); btnSaveEditor->setText(QString::fromStdString("Saglabāt")); QObject::connect( btnSaveEditor, &QToolButton::clicked, setupEditorSave ); buttonLayout->addWidget(btnSaveEditor); vlEditor->addWidget(editor); vlEditor->addWidget(editorButtons); QShortcut* shortcutSave = new QShortcut(QKeySequence("Ctrl+S"), editorWindow); QObject::connect(shortcutSave, &QShortcut::activated, []() { if (editor->isVisible()) { setupEditorSave(); } }); editorWindow->setCentralWidget(wEditor); } auto *wTop = new QWidget(); { // Augša. // Pamata augšējais izklājums. QHBoxLayout *hlTop = new QHBoxLayout(); wTop->setLayout(hlTop); // Teksta elementi. auto *wLabels = new QWidget(); auto *vlLeftTop = new QVBoxLayout(); wLabels->setLayout(vlLeftTop); wLabels->setMinimumSize(0, 40); // Atmiņas bāzes teksta elements. QString labelStyle = "font-size: 20px; font-weight: 400;"; membaseLabel = new QLabel(); membaseLabel->setStyleSheet(labelStyle); vlLeftTop->addWidget(membaseLabel); // Atmiņas kartīšu faila teksta elements. mdemLabel = new QLabel(); mdemLabel->setStyleSheet(labelStyle); vlLeftTop->addWidget(mdemLabel); lastPracticeLabel = new QLabel(); lastPracticeLabel->setStyleSheet(labelStyle); vlLeftTop->addWidget(lastPracticeLabel); // Pogu izklājums. auto buttons = new QWidget(); auto vlButtons = new QVBoxLayout(); buttons->setLayout(vlButtons); buttons->setStyleSheet("font-size: 15px;"); auto buttonsTop = new QWidget(); auto hlButtonsTop = new QHBoxLayout(); buttonsTop->setLayout(hlButtonsTop); auto buttonsBottom = new QWidget(); auto hlButtonsBottom = new QHBoxLayout(); buttonsBottom->setLayout(hlButtonsBottom); // Pogu definēšana. QObject::connect(&toolbar->btnAdd, &QToolButton::clicked, []() { if (!currentMdemBuffer) { return; } editMdem = nullptr; editorWindow->show(); editor->setText(""); }); QObject::connect(&toolbar->btnLoad, &QToolButton::clicked, []() { if (!currentMdemBuffer) { return; } if (!trainWindow->isHidden()) { trainWindow->hide(); } reloadMdem(currentMdemPath); }); QObject::connect(&toolbar->btnSave, &QToolButton::clicked, []() { if (!currentMdemBuffer) { return; } saveMdem(); }); QObject::connect( &toolbar->btnPractice, &QToolButton::clicked, [toolbar]() { if (currentMdemBuffer) { trainWindow->show(); trainWindow->resize(600, 300); initiatePractice( currentMdemBuffer, static_cast( toolbar->cbAlgorithm.currentData().toInt() ) ); } } ); // Pogu saturs. toolbar->btnAdd.setText("Pievienot"); toolbar->btnSave.setText("Saglabāt"); toolbar->btnLoad.setText("Ielādēt"); QLabel *algorithmLabel = new QLabel(); algorithmLabel->setText("Algoritms:"); toolbar->cbAlgorithm.addItem("Intervālu", SPACED); toolbar->cbAlgorithm.addItem("Nejaušais", RANDOM); toolbar->cbAlgorithm.addItem("Primārais", PRIMARY); toolbar->btnPractice.setText("Mācīties"); // Pievieno pogas. hlButtonsTop->addWidget(&toolbar->btnAdd); hlButtonsTop->addWidget(&toolbar->btnSave); hlButtonsTop->addWidget(&toolbar->btnLoad); hlButtonsBottom->addWidget(algorithmLabel); hlButtonsBottom->addWidget(&toolbar->cbAlgorithm); hlButtonsBottom->addWidget(&toolbar->btnPractice); vlButtons->addWidget(buttonsTop); vlButtons->addWidget(buttonsBottom); vlButtons->setAlignment(Qt::AlignTop); // Style buttons hlButtonsTop->setContentsMargins(0, 0, 0, 0); hlButtonsBottom->setContentsMargins(0, 5, 0, 0); // Add top components. hlTop->addWidget(wLabels); hlTop->addStretch(1); hlTop->addWidget(buttons); } QWidget *leftWidget = new QWidget(); { // Kreisā puse. QVBoxLayout *leftLayout = new QVBoxLayout(); leftWidget->setLayout(leftLayout); model = new QFileSystemModel(); mdemList = new QTreeView(); QStringList filters; filters << "*.mdem" << "*.txt"; model->setNameFilters(filters); model->setNameFilterDisables(false); mdemList->setModel(model); mdemList->setStyleSheet( "font-size: 15px;" ); auto header = mdemList->header(); header->setSectionResizeMode(QHeaderView::ResizeToContents); currentMbasePath = settings->value(SETTING_MEMORYBASE).toString(); if (currentMbasePath.size() > 0) { pickDirectory(currentMbasePath); } QObject::connect( mdemList, &QTreeView::doubleClicked, [](const QModelIndex &index) { auto fileInfo = model->fileInfo(index); if (!fileInfo.isDir()) { trainWindow->close(); reloadMdem(fileInfo.filePath().toStdString()); } } ); for (int col = 1; col < model->columnCount(); ++col) { mdemList->hideColumn(col); } leftLayout->addWidget(mdemList); } auto wMain = new QWidget; auto *rightWidget = new QWidget(); auto *rightLayout = new QVBoxLayout(); { // Pamata izklājums. auto vlMain = new QVBoxLayout; wMain->setLayout(vlMain); rightWidget->setLayout(rightLayout); auto *hSplitter = new QSplitter(); hSplitter->addWidget(leftWidget); hSplitter->addWidget(rightWidget); hSplitter->setStretchFactor(1, 3); hSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); vlMain->addWidget(wTop); vlMain->addWidget(hSplitter); } { // Kļūda. errorView = new ErrorView; errorView->box.setObjectName("error-box"); errorView->box.setLayout(&errorView->layout); errorView->box.setMinimumHeight(70); errorView->box.setStyleSheet( QString( "QWidget#error-box {" "border: 1px solid red;" "background: %2;" "}" ).arg(MDEM_BACKGROUND) ); errorView->layout.addWidget(&errorView->label); errorView->label.setWordWrap(true); } { // Atmiņas kartītes. QScrollArea *mdemScroll = new QScrollArea(); QWidget *mdemContainer = new QWidget(); hMdemScroll = new QVBoxLayout(); mdemScroll->setWidget(mdemContainer); mdemScroll->setWidgetResizable(true); mdemScroll->setStyleSheet("font-size: 15px"); mdemContainer->setLayout(hMdemScroll); rightLayout->addWidget(mdemScroll); mdemSpacer = new QSpacerItem( 50, 50, QSizePolicy::Minimum, QSizePolicy::Expanding ); } { // Lappušu pogas. auto wPagination = new QWidget(); auto hPagination = new QHBoxLayout(); wPagination->setLayout(hPagination); wPagination->setStyleSheet("font-size: 15px;"); pagination->firstButton.setText(QString::fromStdString("<<")); hPagination->addWidget(&pagination->firstButton); pagination->firstButton.hide(); QObject::connect(&pagination->firstButton, &QToolButton::clicked, []() { if (pagination->pages.size() > 0) { switchPage(0); } }); pagination->prevButton.setText(QString::fromStdString("<")); hPagination->addWidget(&pagination->prevButton); pagination->prevButton.hide(); QObject::connect(&pagination->prevButton, &QToolButton::clicked, []() { if (pagination->pages.size() > 0) { switchPage(pagination->currentPage - 1); } }); perPage = settings->value(SETTING_PER_PAGE).toInt(); for (size_t i = 0; i < perPage; i++) { auto elButton = new QToolButton(); elButton->setText(QString("%1").arg(i+1)); hPagination->addWidget(elButton); elButton->hide(); QObject::connect(elButton, &QToolButton::clicked, [elButton]() { auto pageNum = std::stoi(elButton->text().toStdString().c_str()); auto pageIdx = pageNum - 1; if (pageIdx < pagination->pages.size()) { switchPage(pageIdx); } }); pagination->paginationButtons.push_back(elButton); } pagination->nextButton.setText(QString::fromStdString(">")); hPagination->addWidget(&pagination->nextButton); pagination->nextButton.hide(); QObject::connect(&pagination->nextButton, &QToolButton::clicked, []() { if (pagination->pages.size() > 0) { switchPage(pagination->currentPage + 1); } }); pagination->lastButton.setText(QString::fromStdString(">>")); hPagination->addWidget(&pagination->lastButton); pagination->lastButton.hide(); QObject::connect(&pagination->lastButton, &QToolButton::clicked, []() { if (pagination->pages.size() > 0) { switchPage(pagination->pages.size() - 1); } }); hPagination->addStretch(1); hPagination->addWidget(&pagination->paginationLabel); rightLayout->addWidget(wPagination); } { // Uzstāda īsceļus. auto addShortcut = [window](QString key, std::function func) { QShortcut* shortcut = new QShortcut(QKeySequence(key), window); QObject::connect(shortcut, &QShortcut::activated, [func]() { func(); }); }; addShortcut("Ctrl+O", [actionOpen]() { actionOpen->trigger(); }); addShortcut("Ctrl+M", [revealMbase]() { revealMbase->trigger(); }); addShortcut("Ctrl+H", [actionHelp]() { actionHelp->trigger(); }); addShortcut("Ctrl+,", [openSettings]() { openSettings->trigger(); }); addShortcut("Ctrl+S", [toolbar]() { toolbar->btnSave.click(); }); addShortcut("Ctrl+P", [toolbar]() { toolbar->btnPractice.click(); }); addShortcut("Ctrl+A", [toolbar]() { toolbar->btnAdd.click(); }); addShortcut("Ctrl+L", [toolbar]() { toolbar->btnLoad.click(); }); } window->setCentralWidget(wMain); window->show(); window->resize(800, 600); return window; }