diff --git a/src/editor/editor.cpp b/src/editor/editor.cpp index ea56703a..718c90b1 100644 --- a/src/editor/editor.cpp +++ b/src/editor/editor.cpp @@ -1,528 +1,529 @@ /*************************************************************************** Copyright 1999-2001 Ewald Arnold Copyright 2004-2007 Peter Hedlund Copyright 2007-2009 Frederik Gladhorn Copyright 2008 Daniel Laidig ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "editor.h" #include // Qt models on top of the KEduVocDocument // Views #include "vocabularyview.h" #include "containerview.h" #include "lessonview.h" #include "wordtypeview.h" #include "multiplechoicewidget.h" #include "comparisonwidget.h" #include "inflectionwidget.h" #include "imagechooserwidget.h" #include "audiowidget.h" #include "browserwidget.h" #include "synonymwidget.h" #include "summarywordwidget.h" #include "latexwidget.h" +#include "parleymainwindow.h" #include "settings/parleyprefs.h" #include "prefs.h" #include "scripts/scriptdialog.h" -#include "scripts/translator.h" #include "parleyactions.h" #include "parleyadaptor.h" //KEduVoc #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include using namespace Editor; EditorWindow::EditorWindow(ParleyMainWindow* parent) : KXmlGuiWindow(parent), m_mainWindow(parent) { // KXmlGui setXMLFile(QStringLiteral("editorui.rc")); setObjectName(QStringLiteral("Editor")); setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); initView(); initModel(); initDockWidgets(); initActions(); KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("parleyrc")), objectName()); applyMainWindowSettings(cfg); connect(parent->parleyDocument(), &ParleyDocument::documentChanged, this, &EditorWindow::updateDocument); connect(parent->parleyDocument(), &ParleyDocument::languagesChanged, this, &EditorWindow::slotLanguagesChanged); connect(parent->parleyDocument(), SIGNAL(statesNeedSaving()), this, SLOT(saveState())); connect(parent, &ParleyMainWindow::preferencesChanged, this, &EditorWindow::applyPrefs); QTimer::singleShot(0, this, &EditorWindow::initScripts); } EditorWindow::~EditorWindow() { saveState(); KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("parleyrc")), objectName()); saveMainWindowSettings(cfg); } void EditorWindow::updateDocument(KEduVocDocument *doc) { m_vocabularyView->setDocument(doc); m_vocabularyModel->setDocument(doc); m_lessonModel->setDocument(doc); m_wordTypeModel->setDocument(doc); m_summaryWordWidget->slotDocumentChanged(doc); m_inflectionWidget->setDocument(doc); m_comparisonWidget->setDocument(doc); m_synonymWidget->setDocument(doc); m_antonymWidget->setDocument(doc); m_falseFriendWidget->setDocument(doc); if (!m_mainWindow->parleyDocument()->document()) { return; } if (!doc) { return; } // expand the root items m_lessonView->expandToDepth(0); m_wordTypeView->expandToDepth(0); connect(m_vocabularyView->selectionModel(), &QItemSelectionModel::selectionChanged, m_summaryWordWidget, &SummaryWordWidget::slotSelectionChanged); connect(m_vocabularyView->selectionModel(), &QItemSelectionModel::selectionChanged, m_latexWidget, &LatexWidget::slotSelectionChanged); m_spellCheckMenu->menu()->clear(); for (int i = 0; i < doc->identifierCount(); ++i) { QAction* languageSpellCheck = new QAction(doc->identifier(i).name(), m_spellCheckMenu->menu()); m_spellCheckMenu->menu()->addAction(languageSpellCheck); connect(languageSpellCheck, &QAction::triggered, this, [=] {m_vocabularyView->checkSpelling(i);}); } } void EditorWindow::setAutomaticTranslation(bool v) { Prefs::setAutomaticTranslation(v); } void EditorWindow::initDockWidgets() { // Lesson dockwidget QDockWidget *lessonDockWidget = new QDockWidget(i18n("Units"), this); lessonDockWidget->setObjectName(QStringLiteral("LessonDock")); m_lessonView = new LessonView(this); lessonDockWidget->setWidget(m_lessonView); addDockWidget(Qt::LeftDockWidgetArea, lessonDockWidget); m_dockWidgets.append(lessonDockWidget); actionCollection()->addAction(QStringLiteral("show_units_dock"), lessonDockWidget->toggleViewAction()); m_lessonModel = new KEduVocLessonModel(this); m_lessonView->setModel(m_lessonModel); m_lessonView->setToolTip(i18n("Right click to add, delete, or rename units. \n" "With the checkboxes you can select which units you want to practice. \n" "Only checked units [x] will be asked in the practice!")); connect(m_lessonView, &LessonView::selectedLessonChanged, m_vocabularyModel, &VocabularyModel::setLesson); connect(m_lessonView, &LessonView::signalShowContainer, m_vocabularyModel, &VocabularyModel::showContainer); connect(m_vocabularyView, &VocabularyView::translationChanged, m_lessonView, &LessonView::setTranslation); // Word classes dock widget QDockWidget* wordTypeDockWidget = new QDockWidget(i18n("Word Types"), this); wordTypeDockWidget->setObjectName(QStringLiteral("WordTypeDock")); m_wordTypeView = new WordTypeView(this); wordTypeDockWidget->setWidget(m_wordTypeView); addDockWidget(Qt::LeftDockWidgetArea, wordTypeDockWidget); m_dockWidgets.append(wordTypeDockWidget); m_wordTypeModel = new KEduVocWordClassModel(this); wordTypeDockWidget->setVisible(false); actionCollection()->addAction(QStringLiteral("show_wordtype_dock"), wordTypeDockWidget->toggleViewAction()); ///@todo test, should be fixed with the lesson one though ///@todo remove before release // new ModelTest(m_wordTypeModel, this); m_wordTypeView->setModel(m_wordTypeModel); connect(m_vocabularyView, &VocabularyView::translationChanged, m_wordTypeView, &WordTypeView::setTranslation); // Inflections QDockWidget *inflectionDock = new QDockWidget(i18n("Inflection (verbs, adjectives, nouns)"), this); inflectionDock->setObjectName(QStringLiteral("InflectionDock")); m_inflectionWidget = new InflectionWidget(this); QScrollArea *inflectionScrollArea = new QScrollArea(this); inflectionScrollArea->setWidgetResizable(true); inflectionScrollArea->setWidget(m_inflectionWidget); inflectionDock->setWidget(inflectionScrollArea); addDockWidget(Qt::RightDockWidgetArea, inflectionDock); m_dockWidgets.append(inflectionDock); actionCollection()->addAction(QStringLiteral("show_inflection_dock"), inflectionDock->toggleViewAction()); connect(m_mainWindow->parleyDocument(), &ParleyDocument::documentChanged, m_inflectionWidget, &InflectionWidget::setDocument); connect(m_vocabularyView, &VocabularyView::translationChanged, m_inflectionWidget, &InflectionWidget::setTranslation); // Comparison forms QDockWidget *comparisonDock = new QDockWidget(i18n("Comparison forms"), this); comparisonDock->setObjectName(QStringLiteral("ComparisonDock")); m_comparisonWidget = new ComparisonWidget(this); QScrollArea *comparisonScrollArea = new QScrollArea(this); comparisonScrollArea->setWidgetResizable(true); comparisonScrollArea->setWidget(m_comparisonWidget); comparisonDock->setWidget(comparisonScrollArea); addDockWidget(Qt::RightDockWidgetArea, comparisonDock); m_dockWidgets.append(comparisonDock); actionCollection()->addAction(QStringLiteral("show_comparison_dock"), comparisonDock->toggleViewAction()); comparisonDock->setVisible(false); connect(m_vocabularyView, &VocabularyView::translationChanged, m_comparisonWidget, &ComparisonWidget::setTranslation); tabifyDockWidget(comparisonDock,inflectionDock); // Multiple choice QDockWidget *multipleChoiceDock = new QDockWidget(i18n("Multiple Choice"), this); multipleChoiceDock->setObjectName(QStringLiteral("MultipleChoiceDock")); MultipleChoiceWidget *multipleChoiceWidget = new MultipleChoiceWidget(this); QScrollArea *multipleChoiceScrollArea = new QScrollArea(this); multipleChoiceScrollArea->setWidgetResizable(true); multipleChoiceScrollArea->setWidget(multipleChoiceWidget); multipleChoiceDock->setWidget(multipleChoiceScrollArea); addDockWidget(Qt::RightDockWidgetArea, multipleChoiceDock); m_dockWidgets.append(multipleChoiceDock); actionCollection()->addAction(QStringLiteral("show_multiplechoice_dock"), multipleChoiceDock->toggleViewAction()); multipleChoiceDock->setVisible(false); connect(m_vocabularyView, &VocabularyView::translationChanged, multipleChoiceWidget, &MultipleChoiceWidget::setTranslation); // Synonym (and the same for antonym and false friends) QDockWidget *synonymDock = new QDockWidget(i18n("Synonyms"), this); synonymDock->setObjectName(QStringLiteral("SynonymDock")); m_synonymWidget = new SynonymWidget(SynonymWidget::Synonym, this); QScrollArea *synonymScrollArea = new QScrollArea(this); synonymScrollArea->setWidgetResizable(true); synonymScrollArea->setWidget(m_synonymWidget); synonymDock->setWidget(synonymScrollArea); addDockWidget(Qt::RightDockWidgetArea, synonymDock); m_dockWidgets.append(synonymDock); actionCollection()->addAction(QStringLiteral("show_synonym_dock"), synonymDock->toggleViewAction()); synonymDock->setVisible(false); connect(m_vocabularyView, &VocabularyView::translationChanged, m_synonymWidget, &SynonymWidget::setTranslation); QDockWidget *antonymDock = new QDockWidget(i18n("Antonyms"), this); antonymDock->setObjectName(QStringLiteral("AntonymDock")); m_antonymWidget = new SynonymWidget(SynonymWidget::Antonym, this); QScrollArea *antonymScrollArea = new QScrollArea(this); antonymScrollArea->setWidgetResizable(true); antonymScrollArea->setWidget(m_antonymWidget); antonymDock->setWidget(antonymScrollArea); addDockWidget(Qt::RightDockWidgetArea, antonymDock); m_dockWidgets.append(antonymDock); actionCollection()->addAction(QStringLiteral("show_antonym_dock"), antonymDock->toggleViewAction()); antonymDock->setVisible(false); connect(m_vocabularyView, &VocabularyView::translationChanged, m_antonymWidget, &SynonymWidget::setTranslation); tabifyDockWidget(synonymDock,antonymDock); QDockWidget *falseFriendDock = new QDockWidget(i18n("False Friends"), this); falseFriendDock->setObjectName(QStringLiteral("FalseFriendDock")); m_falseFriendWidget = new SynonymWidget(SynonymWidget::FalseFriend, this); QScrollArea *falseFriendScrollArea = new QScrollArea(this); falseFriendScrollArea->setWidgetResizable(true); falseFriendScrollArea->setWidget(m_falseFriendWidget); falseFriendDock->setWidget(falseFriendScrollArea); addDockWidget(Qt::RightDockWidgetArea, falseFriendDock); m_dockWidgets.append(falseFriendDock); actionCollection()->addAction(QStringLiteral("show_falsefriend_dock"), falseFriendDock->toggleViewAction()); falseFriendDock->setVisible(false); connect(m_vocabularyView, &VocabularyView::translationChanged, m_falseFriendWidget, &SynonymWidget::setTranslation); tabifyDockWidget(antonymDock,falseFriendDock); // Pronunciation symbols - Use KCharSelect QDockWidget *charSelectDock = new QDockWidget(i18n("Phonetic Symbols"), this); charSelectDock->setObjectName(QStringLiteral("IPADock")); KCharSelect *charSelectWidget = new KCharSelect(this, 0, KCharSelect::SearchLine | KCharSelect::BlockCombos | KCharSelect::CharacterTable); charSelectWidget->setCurrentChar(0x0250); QScrollArea *charSelectScrollArea = new QScrollArea(this); charSelectScrollArea->setWidgetResizable(true); charSelectScrollArea->setWidget(charSelectWidget); charSelectDock->setWidget(charSelectScrollArea); addDockWidget(Qt::BottomDockWidgetArea, charSelectDock); m_dockWidgets.append(charSelectDock); actionCollection()->addAction(QStringLiteral("show_pronunciation_dock"), charSelectDock->toggleViewAction()); charSelectDock->setVisible(false); connect(charSelectWidget, &KCharSelect::charSelected, m_vocabularyView, &VocabularyView::appendChar); // Image QDockWidget *imageDock = new QDockWidget(i18n("Image"), this); imageDock->setObjectName(QStringLiteral("ImageDock")); ImageChooserWidget *imageChooserWidget = new ImageChooserWidget(this); QScrollArea *imageScrollArea = new QScrollArea(this); imageScrollArea->setWidgetResizable(true); imageScrollArea->setWidget(imageChooserWidget); imageDock->setWidget(imageScrollArea); addDockWidget(Qt::RightDockWidgetArea, imageDock); m_dockWidgets.append(imageDock); actionCollection()->addAction(QStringLiteral("show_image_dock"), imageDock->toggleViewAction()); imageDock->setVisible(false); connect(m_vocabularyView, &VocabularyView::translationChanged, imageChooserWidget, &ImageChooserWidget::setTranslation); tabifyDockWidget(multipleChoiceDock,imageDock); // Summary word QDockWidget *summaryDock = new QDockWidget(i18n("Summary"), this); summaryDock->setObjectName(QStringLiteral("SummaryDock")); m_summaryWordWidget = new SummaryWordWidget(m_vocabularyFilter, m_mainWindow->parleyDocument()->document(), this); QScrollArea *summaryScrollArea = new QScrollArea(this); summaryScrollArea->setWidgetResizable(true); summaryScrollArea->setWidget(m_summaryWordWidget); summaryDock->setWidget(summaryScrollArea); addDockWidget(Qt::BottomDockWidgetArea, summaryDock); actionCollection()->addAction(QStringLiteral("show_summary_dock"), summaryDock->toggleViewAction()); summaryDock->setVisible(false); m_dockWidgets.append(summaryDock); connect(m_vocabularyView, &VocabularyView::translationChanged, m_summaryWordWidget, &SummaryWordWidget::setTranslation); // Sound QDockWidget *audioDock = new QDockWidget(i18n("Sound"), this); audioDock->setObjectName(QStringLiteral("AudioDock")); AudioWidget *audioWidget = new AudioWidget(this); QScrollArea *audioScrollArea = new QScrollArea(this); audioScrollArea->setWidgetResizable(true); audioScrollArea->setWidget(audioWidget); audioDock->setWidget(audioScrollArea); addDockWidget(Qt::RightDockWidgetArea, audioDock); m_dockWidgets.append(audioDock); actionCollection()->addAction(QStringLiteral("show_audio_dock"), audioDock->toggleViewAction()); audioDock->setVisible(false); connect(m_vocabularyView, &VocabularyView::translationChanged, audioWidget, &AudioWidget::setTranslation); tabifyDockWidget(imageDock,audioDock); // browser QDockWidget *browserDock = new QDockWidget(i18n("Internet"), this); browserDock->setObjectName(QStringLiteral("BrowserDock")); BrowserWidget *htmlPart = new BrowserWidget(browserDock); QScrollArea *browserScrollArea = new QScrollArea(this); browserScrollArea->setWidgetResizable(true); browserScrollArea->setWidget(htmlPart); browserDock->setWidget(browserScrollArea); addDockWidget(Qt::BottomDockWidgetArea, browserDock); m_dockWidgets.append(browserDock); actionCollection()->addAction(QStringLiteral("show_browser_dock"), browserDock->toggleViewAction()); browserDock->setVisible(false); connect(m_vocabularyView, &VocabularyView::translationChanged, htmlPart, &BrowserWidget::setTranslation); tabifyDockWidget(summaryDock,browserDock); // LaTeX QDockWidget *latexDock = new QDockWidget(i18n("LaTeX"), this); latexDock->setObjectName(QStringLiteral("LatexDock")); m_latexWidget = new LatexWidget(m_vocabularyFilter, m_mainWindow->parleyDocument()->document(), this); QScrollArea *latexScrollArea = new QScrollArea(this); latexScrollArea->setWidgetResizable(true); latexScrollArea->setWidget(m_latexWidget); latexDock->setWidget(latexScrollArea); addDockWidget(Qt::RightDockWidgetArea, latexDock); actionCollection()->addAction(QStringLiteral("show_latex_dock"), latexDock->toggleViewAction()); latexDock->setVisible(false); m_dockWidgets.append(latexDock); connect(m_vocabularyView, &VocabularyView::translationChanged, m_latexWidget, &LatexWidget::setTranslation); tabifyDockWidget(audioDock,latexDock); // Grades // QDockWidget *gradeDock = new QDockWidget(i18n("Grade"), this); // gradeDock->setObjectName("gradeDock"); // QLabel *gradeWidget = new QLabel("grade placeholder", this); // gradeDock->setWidget(gradeWidget); // addDockWidget(Qt::RightDockWidgetArea, gradeDock); // connect(this, SIGNAL(signalSetData(KEduVocTranslation*)), m_declensionWidget, SLOT(setTranslation(KEduVocTranslation*))); } void EditorWindow::initActions() { ParleyActions::create(ParleyActions::RemoveGrades, this, SLOT(removeGrades()), actionCollection()); m_spellCheckMenu = ParleyActions::create(ParleyActions::CheckSpelling, 0, "", actionCollection()); m_spellCheckMenu->setMenu(new QMenu(this)); ParleyActions::create(ParleyActions::ToggleShowSublessons, m_vocabularyModel, SLOT(setRecursive(bool)), actionCollection()); ParleyActions::create(ParleyActions::AutomaticTranslation, this, SLOT(setAutomaticTranslation(bool)), actionCollection()); ParleyActions::create(ParleyActions::StartPractice, m_mainWindow, SLOT(showPracticeConfiguration()), actionCollection()); actionCollection()->action(QStringLiteral("practice_start"))->setText(i18n("Practice")); actionCollection()->action(QStringLiteral("practice_start"))->setToolTip(i18n("Practice")); ParleyActions::create(ParleyActions::ConfigurePractice, m_mainWindow, SLOT(configurePractice()), actionCollection()); ParleyActions::create(ParleyActions::ToggleSearchBar, this, SLOT(slotConfigShowSearch()), actionCollection()); ParleyActions::create(ParleyActions::SearchVocabulary, this, SLOT(startSearch()), actionCollection()); ParleyActions::create(ParleyActions::ShowScriptManager, this, SLOT(slotShowScriptManager()), actionCollection()); ParleyActions::create(ParleyActions::LanguagesProperties, m_mainWindow->parleyDocument(), SLOT(languageProperties()), actionCollection()); ParleyActions::createUploadAction(m_mainWindow->parleyDocument(), SLOT(uploadFile()), actionCollection()); new EditorWindowAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/AddWithTranslation"), this); } void EditorWindow::addWordWithTranslation(const QStringList &w) { KEduVocExpression *kexpr = new KEduVocExpression(w); m_vocabularyModel->appendEntry(kexpr); } void EditorWindow::initModel() { m_vocabularyModel = new KEduVocVocabularyModel(Prefs::showSublessonentries(), this); m_vocabularyFilter = new KEduVocVocabularyFilter(this); m_vocabularyFilter->setSourceModel(m_vocabularyModel); m_vocabularyView->setFilter(m_vocabularyFilter); // connect(m_mainWindow->parleyDocument(), SIGNAL(documentChanged(KEduVocDocument*)), m_vocabularyModel, SLOT(setDocument(KEduVocDocument*))); // connect(m_mainWindow->parleyDocument(), SIGNAL(documentChanged(KEduVocDocument*)), m_vocabularyView, SLOT(setDocument(KEduVocDocument*))); connect(m_searchLine, &QLineEdit::textChanged, m_vocabularyFilter, &VocabularyFilter::setSearchString); } /** * This initializes the main widgets and table. */ void EditorWindow::initView() { QWidget *mainWidget = new QWidget(this); setCentralWidget(mainWidget); QVBoxLayout *topLayout = new QVBoxLayout(mainWidget); m_searchLine = new QLineEdit(this); m_searchLine->show(); m_searchLine->setFocusPolicy(Qt::ClickFocus); m_searchLine->setClearButtonEnabled(true); m_searchLine->setPlaceholderText(i18n("Enter search terms here")); m_searchLine->setToolTip(i18n("Search your vocabulary")); QLabel *label = new QLabel(i18n("S&earch:"), this); label->setBuddy(m_searchLine); label->show(); m_searchWidget = new QWidget(this); QHBoxLayout* layout = new QHBoxLayout(m_searchWidget); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(label); layout->addWidget(m_searchLine); ///@todo centralWidget()-> delete layout QVBoxLayout * rightLayout = new QVBoxLayout(); rightLayout->setContentsMargins(0, 0, 0, 0); rightLayout->addWidget(m_searchWidget); m_searchWidget->setVisible(Prefs::showSearch()); m_vocabularyView = new VocabularyView(this); rightLayout->addWidget(m_vocabularyView, 1, 0); topLayout->addLayout(rightLayout); } void EditorWindow::slotConfigShowSearch() { m_searchWidget->setVisible(m_searchWidget->isHidden()); Prefs::setShowSearch(m_searchWidget->isVisible()); } void EditorWindow::startSearch() { m_searchWidget->setVisible(true); m_searchLine->setFocus(); } void EditorWindow::slotShowScriptManager() { ScriptDialog * dialog = new ScriptDialog(m_scriptManager); dialog->show(); } void EditorWindow::applyPrefs() { m_vocabularyView->reset(); } void EditorWindow::removeGrades() { m_mainWindow->parleyDocument()->document()->lesson()->resetGrades(-1, KEduVocContainer::Recursive); } void EditorWindow::initScripts() { m_scriptManager = new ScriptManager(this); m_vocabularyView->setTranslator(m_scriptManager->translator()); //Load scripts m_scriptManager->loadScripts(); } void EditorWindow::saveState() { m_vocabularyView->saveColumnVisibility(); } void EditorWindow::slotLanguagesChanged() { m_vocabularyModel->resetLanguages(); } diff --git a/src/editor/editor.h b/src/editor/editor.h index b3bc359c..76b94efd 100644 --- a/src/editor/editor.h +++ b/src/editor/editor.h @@ -1,172 +1,173 @@ /*************************************************************************** Copyright 1999-2001 Ewald Arnold Copyright 2004-2007 Peter Hedlund Copyright 2007-2009 Frederik Gladhorn Copyright 2008 Daniel Laidig ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef EDITOR_H #define EDITOR_H #include "parleydocument.h" +#include "parleymainwindow.h" #include "scripts/scripting/parley.h" #include #include #include class QLineEdit; class ScriptManager; ///@brief contains objects for the editor main window // Models around the Collection / KEduVocDocument class KEduVocLessonModel; class KEduVocVocabularyModel; class KEduVocVocabularyFilter; class KEduVocWordClassModel; namespace Editor { class VocabularyView; class LessonView; class WordTypeView; class InflectionWidget; class ComparisonWidget; class SummaryWordWidget; class LatexWidget; class SynonymWidget; class EditorWindow : public KXmlGuiWindow { Q_OBJECT public: explicit EditorWindow(ParleyMainWindow* parent); ~EditorWindow(); /** * setup the action (menus etc) */ void initActions(); /** setup the main model*/ void initModel(); /** setup the main view*/ void initView(); void initDockWidgets(); /** This will look at the lesson list and also the combo box to determine what should be displayed in the table. */ void updateTableFilter(); public slots: /** * Load enabled scripts (from configuration parleyrc) */ void initScripts(); /** * Edit languages contained in the document. * This includes adding/removing languages, * editing articles, personal pronouns and tenses. */ void slotLanguagesChanged(); void slotConfigShowSearch(); /** * Display script manager (open a new window / or Settings window) */ void slotShowScriptManager(); void applyPrefs(); /** * Removes all grading information from the current document */ void removeGrades(); /** when closing the application, save the editor's state */ void saveState(); /** * Set the current doc (after creating a new one or opening a file) */ void updateDocument(KEduVocDocument *doc); /** * DBus method for adding words by external apps */ void addWordWithTranslation(const QStringList &w); /** * Set/Unset Automatic Translation in Prefs */ void setAutomaticTranslation(bool v); private slots: /** Make the search bar visible and focus it */ void startSearch(); signals: void signalSetData(const QList& entries, int currentTranslation); private: ParleyMainWindow *m_mainWindow; QAction* m_vocabShowSearchBarAction; KEduVocVocabularyModel *m_vocabularyModel; VocabularyView *m_vocabularyView; KEduVocVocabularyFilter *m_vocabularyFilter; QLineEdit *m_searchLine; QWidget *m_searchWidget; QAction *m_spellCheckMenu; /** Show a single conjugation and let the user edit it */ InflectionWidget *m_inflectionWidget; SummaryWordWidget *m_summaryWordWidget; ComparisonWidget *m_comparisonWidget; LatexWidget *m_latexWidget; SynonymWidget *m_synonymWidget; SynonymWidget *m_antonymWidget; SynonymWidget *m_falseFriendWidget; /// dock widgets to display lessons, word types, ... LessonView *m_lessonView; KEduVocLessonModel *m_lessonModel; KEduVocWordClassModel *m_wordTypeModel; WordTypeView *m_wordTypeView; ScriptManager* m_scriptManager; ///stores all the translations of a vocabulary word - Translator* m_translator; + KEduVocTranslator* m_translator; QList m_dockWidgets; QList m_dockWidgetVisibility; friend class ::ParleyDocument; friend class Scripting::Parley; friend class ::ScriptManager; }; } #endif // EDITOR_H diff --git a/src/editor/vocabularydelegate.cpp b/src/editor/vocabularydelegate.cpp index d85d03cd..e3ae6564 100644 --- a/src/editor/vocabularydelegate.cpp +++ b/src/editor/vocabularydelegate.cpp @@ -1,373 +1,373 @@ /*************************************************************************** Copyright 2006, 2007 Peter Hedlund Copyright 2007 Frederik Gladhorn ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "vocabularydelegate.h" #include "prefs.h" #include "languagesettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Editor; VocabularyDelegate::VocabularyDelegate(QObject *parent) : QItemDelegate(parent), m_doc(0), m_translator(0) { } QSet VocabularyDelegate::getTranslations(const QModelIndex & index) const { if (Prefs::automaticTranslation() == false) return QSet(); QSet translations; //translations of this column from all the other languages int language = index.column() / KEduVocVocabularyModel::EntryColumnsMAX; QString toLanguage = m_doc->identifier(language).locale(); //iterate through all the Translation columns for (int i = 0; i < index.model()->columnCount(index.parent()); i ++) { if (KEduVocVocabularyModel::columnType(i) == KEduVocVocabularyModel::Translation) { //translation column QString fromLanguage = m_doc->identifier(KEduVocVocabularyModel::translation(i)).locale(); QString word = index.model()->index(index.row(), i, QModelIndex()).data().toString(); if (fromLanguage != toLanguage) { // qDebug() << fromLanguage << toLanguage << word; //get the word translations and add them to the translations set QSet * tr = m_translator->getTranslation(word, fromLanguage, toLanguage); if (tr) translations.unite(* (tr)); } } } return translations; } QWidget * VocabularyDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { Q_UNUSED(option); /// as long as it's unused if (!index.isValid()) { return 0; } switch (KEduVocVocabularyModel::columnType(index.column())) { case KEduVocVocabularyModel::WordClass: { if (!m_doc) return 0; KComboBox *wordTypeCombo = new KComboBox(parent); WordTypeBasicModel *basicWordTypeModel = new WordTypeBasicModel(parent); wordTypeCombo->setModel(basicWordTypeModel); QTreeView *view = new QTreeView(parent); view->setModel(basicWordTypeModel); wordTypeCombo->setView(view); view->header()->setVisible(false); view->setRootIsDecorated(true); basicWordTypeModel->setDocument(m_doc); view->expandAll(); qDebug() << "index data" << index.data().toString(); //view->setCurrentItem(); return wordTypeCombo; } case KEduVocVocabularyModel::Translation: { if (!m_doc || !m_translator) return 0; if (KEduVocVocabularyModel::columnType(index.column()) == KEduVocVocabularyModel::Translation) { //get the translations of this word (fetch only with the help of scripts, if enabled) QSet translations = getTranslations(index); //create combo box //if there is only one word and that is the suggestion word (in translations) then don't create the combobox if (!translations.isEmpty() && !(translations.size() == 1 && (*translations.begin()) == index.model()->data(index, Qt::DisplayRole).toString())) { KComboBox *translationCombo = new KComboBox(parent); translationCombo->setFrame(false); translationCombo->addItems(translations.toList()); translationCombo->setEditable(true); translationCombo->setFont(index.model()->data(index, Qt::FontRole).value()); translationCombo->setEditText(index.model()->data(index, Qt::DisplayRole).toString()); translationCombo->completionObject()->setItems(translations.toList()); return translationCombo; } } // no break - we fall back to a line edit if there are not multiple translations fetched onlin // fallthrough default: { QLineEdit *editor = new QLineEdit(parent); editor->setFrame(false); editor->setFont(index.model()->data(index, Qt::FontRole).value()); editor->setText(index.model()->data(index, Qt::DisplayRole).toString()); QString locale = index.model()->data(index, KEduVocVocabularyModel::LocaleRole).toString(); if (!locale.isEmpty()) { LanguageSettings settings(locale); settings.load(); QString layout = settings.keyboardLayout(); if (!layout.isEmpty()) { QDBusInterface kxkb(QStringLiteral("org.kde.keyboard"), QStringLiteral("/Layouts"), QStringLiteral("org.kde.KeyboardLayouts")); if (kxkb.isValid()) { kxkb.call(QStringLiteral("setLayout"), layout); } } } return editor; } } } bool VocabularyDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { Q_UNUSED(view); if (event->type() == QEvent::ToolTip) { QPainterPath audioPainterPath; QPainterPath imagePainterPath; audioPainterPath.addPolygon(audioPolygon(option)); imagePainterPath.addPolygon(imagePolygon(option)); int column = columnType(index.column()); if (audioPainterPath.contains(event->pos()) && hasAudio(index) && (column == Translation || column == Pronunciation)) { QToolTip::showText(event->globalPos(), i18n("Sound file selected: %1", audioUrl(index))); } else if (imagePainterPath.contains(event->pos()) && hasImage(index) && (column == Translation || column == Pronunciation)) { QToolTip::showText(event->globalPos(), i18n("Image file selected: %1", imageUrl(index))); } else { QToolTip::hideText(); event->ignore(); } return true; } return false; } QPolygon VocabularyDelegate::audioPolygon(const QStyleOptionViewItem &option) const { QRect rect = option.rect; QPolygon polygon; polygon << QPoint(rect.x() + rect.width() - 10, rect.y()); polygon << QPoint(rect.x() + rect.width(), rect.y()); polygon << QPoint(rect.x() + rect.width(), rect.y() + 10); return polygon; } QPolygon VocabularyDelegate::imagePolygon(const QStyleOptionViewItem &option) const { QRect rect = option.rect; QPolygon polygon; polygon << QPoint(rect.x() + rect.width() - 10, rect.y() + rect.height()); polygon << QPoint(rect.x() + rect.width(), rect.y() + rect.height()); polygon << QPoint(rect.x() + rect.width(), rect.y() + rect.height() - 10); return polygon; } bool VocabularyDelegate::hasAudio(const QModelIndex &index) const { return !audioUrl(index).isEmpty(); } bool VocabularyDelegate::hasImage(const QModelIndex &index) const { return !imageUrl(index).isEmpty(); } QString VocabularyDelegate::audioUrl(const QModelIndex &index) const { QVariant audioVar = index.data(KEduVocVocabularyModel::AudioRole); QString audioUrl = audioVar.toString(); return audioUrl; } QString VocabularyDelegate::imageUrl(const QModelIndex &index) const { QVariant imageVar = index.data(KEduVocVocabularyModel::ImageRole); QString imageUrl = imageVar.toString(); return imageUrl; } int VocabularyDelegate::columnType(int column) { return column % EntryColumnsMAX; } void VocabularyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QItemDelegate::paint(painter, option, index); painter->save(); int column = columnType(index.column()); if (hasAudio(index) == true && (column == Translation || column == Pronunciation)) { painter->setPen(QPen(Qt::red)); painter->setBrush(QBrush(Qt::red)); painter->drawPolygon(audioPolygon(option)); } if (hasImage(index) == true && (column == Translation || column == Pronunciation)) { painter->setPen(QPen(Qt::blue)); painter->setBrush(QBrush(Qt::blue)); painter->drawPolygon(imagePolygon(option)); } painter->restore(); } void VocabularyDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const { if (!index.isValid()) { return; } switch (KEduVocVocabularyModel::columnType(index.column())) { case (KEduVocVocabularyModel::Translation) : { QString value = index.model()->data(index, Qt::DisplayRole).toString(); KComboBox * translationCombo = qobject_cast (editor); if (translationCombo) { translationCombo->setEditText(value); if (value.isEmpty()) { // show the translations that were fetched as popup translationCombo->showPopup(); } break; } } // fallthrough default: { QString value = index.model()->data(index, Qt::DisplayRole).toString(); QLineEdit *lineEdit = qobject_cast (editor); if (lineEdit) { lineEdit->setText(value); } } } } void VocabularyDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const { if (!index.isValid()) { return; } switch (KEduVocVocabularyModel::columnType(index.column())) { case (KEduVocVocabularyModel::WordClass) : { qDebug() << "word type editor"; KComboBox *combo = qobject_cast (editor); if (!combo) { return; } qDebug() << "combo" << combo->currentText(); QModelIndex comboIndex = combo->view()->currentIndex(); KEduVocWordType* wordType = static_cast(comboIndex.internalPointer()); // the root is the same as no word type if (wordType && wordType->parent() == 0) { wordType = 0; } KEduVocVocabularyFilter *filter = qobject_cast (model); KEduVocVocabularyModel *vocModel = qobject_cast ((filter)->sourceModel()); Q_ASSERT(vocModel); QVariant data = vocModel->data(filter->mapToSource(index), KEduVocVocabularyModel::EntryRole); KEduVocExpression *expression = data.value(); Q_ASSERT(expression); int translationId = KEduVocVocabularyModel::translation(index.column()); expression->translation(translationId)->setWordType(wordType); model->setData(index, combo->currentText()); break; } case (KEduVocVocabularyModel::Translation) : { QLineEdit *lineEdit = qobject_cast (editor); if (lineEdit) { model->setData(index, lineEdit->text()); } break; } default: { QLineEdit *lineEdit = qobject_cast (editor); if (lineEdit) { model->setData(index, lineEdit->text()); } } } } void VocabularyDelegate::setDocument(KEduVocDocument * doc) { m_doc = doc; } /* QPair< QString, QString > VocabularyDelegate::guessWordType(const QString & entry, int language) const { qDebug() << "guessing word type for: " << entry; QString article = entry.section(" ", 0, 0); if ( article.length() < entry.length() ) { if ( article == ->identifier(language).articles().article(KEduVocWordFlag::Singular| KEduVocWordFlag::Definite| KEduVocWordFlag::Masculine) ) { qDebug() << "Noun masculine"; return qMakePair(m_doc->wordTypes().specialTypeNoun(), m_doc->wordTypes().specialTypeNounMale()); } } return qMakePair(QString(), QString()); } */ VocabularyDelegate::WordTypeBasicModel::WordTypeBasicModel(QObject * parent) : KEduVocReadonlyContainerModel(KEduVocContainer::WordType, parent) { } KEduVocContainer * VocabularyDelegate::WordTypeBasicModel::rootContainer() const { if (!document()) { return 0; } return document()->wordTypeContainer(); } /** - * Sets the member variable m_translator to a Translator object - * @param translator Translator Object to be used for retrieving word translations + * Sets the member variable m_translator to a KEduVocTranslator object + * @param translator KEduVocTranslator Object to be used for retrieving word translations */ -void VocabularyDelegate::setTranslator(Translator* translator) +void VocabularyDelegate::setTranslator(KEduVocTranslator* translator) { m_translator = translator; } diff --git a/src/editor/vocabularydelegate.h b/src/editor/vocabularydelegate.h index c3622ffd..b24dd866 100644 --- a/src/editor/vocabularydelegate.h +++ b/src/editor/vocabularydelegate.h @@ -1,93 +1,93 @@ /*************************************************************************** Copyright 2006, 2007 Peter Hedlund Copyright 2007 Frederik Gladhorn ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef VOCABULARYDELEGATE_H #define VOCABULARYDELEGATE_H -#include "../scripts/translator.h" #include #include #include +#include class KEduVocDocument; namespace Editor { class VocabularyDelegate : public QItemDelegate { Q_OBJECT public: enum entryColumns { Translation = 0, Pronunciation, WordType, Synonym, Antonym, Example, Comment, Paraphrase, // Audio, // Image, EntryColumnsMAX }; explicit VocabularyDelegate(QObject *parent = 0); QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE; - void setTranslator(Translator * translator); + void setTranslator(KEduVocTranslator * translator); static int columnType(int column); bool hasAudio(const QModelIndex &index) const; bool hasImage(const QModelIndex &index) const; QString audioUrl(const QModelIndex &index) const; QString imageUrl(const QModelIndex &index) const; QPolygon audioPolygon(const QStyleOptionViewItem &option) const; QPolygon imagePolygon(const QStyleOptionViewItem &option) const; public slots: void setDocument(KEduVocDocument *doc); bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index ) Q_DECL_OVERRIDE; private: KEduVocDocument *m_doc; - Translator * m_translator; + KEduVocTranslator * m_translator; /** Returns the translations of the word of the given index */ QSet getTranslations(const QModelIndex & index) const; // for the word type combo class WordTypeBasicModel; }; class VocabularyDelegate::WordTypeBasicModel : public KEduVocReadonlyContainerModel { public: explicit WordTypeBasicModel(QObject *parent = 0); protected: KEduVocContainer * rootContainer() const Q_DECL_OVERRIDE; }; } #endif diff --git a/src/editor/vocabularyview.cpp b/src/editor/vocabularyview.cpp index e0f8302a..20e9cae1 100644 --- a/src/editor/vocabularyview.cpp +++ b/src/editor/vocabularyview.cpp @@ -1,465 +1,465 @@ /*************************************************************************** Copyright 2006, 2007 Peter Hedlund Copyright 2007-2008 Frederik Gladhorn ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ ///@file vocabularyview.cpp #include "vocabularyview.h" #include "vocabularyheaderview.h" #include "vocabularydelegate.h" #include "editor/editor.h" #include "prefs.h" #include "vocabularycolumnsdialog.h" #include "documentsettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Editor; VocabularyView::VocabularyView(EditorWindow * parent) : QTableView(parent), m_model(0), m_doc(0), m_spellChecker(0), m_spellDialog(0) { installEventFilter(this); setHorizontalHeader(new VocabularyHeaderView(Qt::Horizontal, this)); horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); horizontalHeader()->setSectionsMovable(true); setEditTriggers(QAbstractItemView::AnyKeyPressed | QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked); setSortingEnabled(true); setTabKeyNavigation(true); m_vocabularyDelegate = new VocabularyDelegate(this); setItemDelegate(m_vocabularyDelegate); setFrameStyle(QFrame::NoFrame); setAlternatingRowColors(true); // Enable context menus setContextMenuPolicy(Qt::ActionsContextMenu); horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu); setWordWrap(true); setDragEnabled(true); // smooth scrolling horizontally, otherwise it tries to jump from item to item. setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); m_appendEntryAction = new QAction(this); parent->actionCollection()->addAction(QStringLiteral("edit_append"), m_appendEntryAction); parent->actionCollection()->setDefaultShortcut( m_appendEntryAction, QKeySequence(Qt::Key_Insert)); m_appendEntryAction->setIcon(QIcon::fromTheme(QStringLiteral("list-add-card"))); m_appendEntryAction->setText(i18n("&Add New Entry")); connect(m_appendEntryAction, &QAction::triggered, this, &VocabularyView::appendEntry); m_appendEntryAction->setShortcut(QKeySequence(Qt::Key_Insert)); m_appendEntryAction->setWhatsThis(i18n("Append a new row to the vocabulary")); m_appendEntryAction->setToolTip(m_appendEntryAction->whatsThis()); m_appendEntryAction->setStatusTip(m_appendEntryAction->whatsThis()); addAction(m_appendEntryAction); m_deleteEntriesAction = new QAction(this); parent->actionCollection()->addAction(QStringLiteral("edit_remove_selected_area"), m_deleteEntriesAction); parent->actionCollection()->setDefaultShortcut( m_deleteEntriesAction, QKeySequence::Delete); m_deleteEntriesAction->setIcon(QIcon::fromTheme(QStringLiteral("list-remove-card"))); m_deleteEntriesAction->setText(i18n("&Delete Entry")); connect(m_deleteEntriesAction, &QAction::triggered, this, &VocabularyView::deleteSelectedEntries); m_deleteEntriesAction->setShortcut(QKeySequence::Delete); m_deleteEntriesAction->setWhatsThis(i18n("Delete the selected rows")); m_deleteEntriesAction->setToolTip(m_deleteEntriesAction->whatsThis()); m_deleteEntriesAction->setStatusTip(m_deleteEntriesAction->whatsThis()); addAction(m_deleteEntriesAction); QAction* separator = new QAction(this); separator->setSeparator(true); addAction(separator); m_copyAction = KStandardAction::copy(this, SLOT(slotEditCopy()), parent->actionCollection()); parent->actionCollection()->setDefaultShortcut( m_copyAction, QKeySequence::Copy); m_copyAction->setWhatsThis(i18n("Copy")); m_copyAction->setToolTip(m_copyAction->whatsThis()); m_copyAction->setStatusTip(m_copyAction->whatsThis()); addAction(m_copyAction); m_cutAction = KStandardAction::cut(this, SLOT(slotCutEntry()), parent->actionCollection()); parent->actionCollection()->setDefaultShortcut( m_cutAction, QKeySequence::Cut); m_cutAction->setWhatsThis(i18n("Cut")); m_cutAction->setToolTip(m_cutAction->whatsThis()); m_cutAction->setStatusTip(m_cutAction->whatsThis()); addAction(m_cutAction); m_pasteAction = KStandardAction::paste(this, SLOT(slotEditPaste()), parent->actionCollection()); parent->actionCollection()->setDefaultShortcut( m_pasteAction, QKeySequence::Paste); m_pasteAction->setWhatsThis(i18n("Paste")); m_pasteAction->setToolTip(m_pasteAction->whatsThis()); m_pasteAction->setStatusTip(m_pasteAction->whatsThis()); addAction(m_pasteAction); m_selectAllAction = KStandardAction::selectAll(this, SLOT(selectAll()), parent->actionCollection()); parent->actionCollection()->setDefaultShortcut( m_selectAllAction, QKeySequence::SelectAll); m_selectAllAction->setWhatsThis(i18n("Select all rows")); m_selectAllAction->setToolTip(m_selectAllAction->whatsThis()); m_selectAllAction->setStatusTip(m_selectAllAction->whatsThis()); m_clearSelectionAction = KStandardAction::deselect(this, SLOT(clearSelection()), parent->actionCollection()); parent->actionCollection()->setDefaultShortcut( m_clearSelectionAction, QKeySequence::Deselect); m_clearSelectionAction->setWhatsThis(i18n("Deselect all rows")); m_clearSelectionAction->setToolTip(m_clearSelectionAction->whatsThis()); m_clearSelectionAction->setStatusTip(m_clearSelectionAction->whatsThis()); // vocabulary columns dialog QAction *vocabularyColumnsDialogAction = new QAction(this); parent->actionCollection()->addAction(QStringLiteral("show_vocabulary_columns_dialog"), vocabularyColumnsDialogAction); vocabularyColumnsDialogAction->setIcon(QIcon::fromTheme(QStringLiteral("view-file-columns"))); vocabularyColumnsDialogAction->setText(i18n("Vocabulary Columns...")); vocabularyColumnsDialogAction->setWhatsThis(i18n("Toggle display of individual vocabulary columns")); vocabularyColumnsDialogAction->setToolTip(vocabularyColumnsDialogAction->whatsThis()); vocabularyColumnsDialogAction->setStatusTip(vocabularyColumnsDialogAction->whatsThis()); horizontalHeader()->addAction(vocabularyColumnsDialogAction); addAction(vocabularyColumnsDialogAction); connect(vocabularyColumnsDialogAction, &QAction::triggered, this, &VocabularyView::slotShowVocabularyColumnsDialog); } void VocabularyView::setFilter(KEduVocVocabularyFilter * model) { QTableView::setModel(model); m_model = model; connect(selectionModel(), &QItemSelectionModel::currentChanged, this, &VocabularyView::slotCurrentChanged); connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &VocabularyView::slotSelectionChanged); slotSelectionChanged(QItemSelection(), QItemSelection()); } void VocabularyView::slotCurrentChanged(const QModelIndex & current, const QModelIndex & previous) { Q_UNUSED(previous); KEduVocExpression* entry = 0; if (current.isValid()) { entry = model()->data(current, KEduVocVocabularyModel::EntryRole).value(); } emit translationChanged(entry, KEduVocVocabularyModel::translation(current.column())); } void VocabularyView::reset() { QTableView::reset(); emit translationChanged(0, 0); QList visibleColumns; if (m_doc) { DocumentSettings ds(m_doc->url().url()); ds.load(); visibleColumns = ds.visibleColumns(); KConfig parleyConfig(QStringLiteral("parleyrc")); KConfigGroup documentGroup(&parleyConfig, "Document " + m_doc->url().url()); QByteArray state = documentGroup.readEntry("VocabularyColumns", QByteArray()); if (!horizontalHeader()->restoreState(state)) { resizeColumnsToContents(); } } horizontalHeader()->setSectionsMovable(true); for (int i = 0; i < model()->columnCount(QModelIndex()); i++) { if (i < visibleColumns.size()) { setColumnHidden(i, !visibleColumns.value(i)); } else { if (KEduVocVocabularyModel::columnType(i) != KEduVocVocabularyModel::Translation) { setColumnHidden(i, true); } } } } void VocabularyView::saveColumnVisibility() const { if (!m_doc) { return; } // Generate a QList for saving QList visibleList; for (int i = 0; i < m_model->columnCount(); ++i) { visibleList.append(static_cast(!isColumnHidden(i))); } DocumentSettings ds(m_doc->url().url()); ds.setVisibleColumns(visibleList); ds.save(); QByteArray saveState = horizontalHeader()->saveState(); KConfig parleyConfig(QStringLiteral("parleyrc")); KConfigGroup documentGroup(&parleyConfig, "Document " + m_doc->url().url()); documentGroup.writeEntry("VocabularyColumns", horizontalHeader()->saveState()); } void VocabularyView::appendEntry() { QModelIndex newIndex = m_model->appendEntry(); scrollTo(newIndex); selectionModel()->clear(); // otherwise proxy mapping gets screwed for some reason selectionModel()->select(newIndex, QItemSelectionModel::ClearAndSelect); selectionModel()->setCurrentIndex(newIndex, QItemSelectionModel::ClearAndSelect); edit(newIndex); } void VocabularyView::appendChar(const QChar &c) { const QModelIndex &index = selectionModel()->currentIndex(); m_model->setData(index, QString(m_model->data(index).toString() + c)); } void VocabularyView::deleteSelectedEntries(bool askConfirmation) { QSet rows; foreach(const QModelIndex & index, selectionModel()->selectedIndexes()) { rows.insert(index.row()); } bool del = true; if (askConfirmation) { del = KMessageBox::Continue == KMessageBox::warningContinueCancel(this, i18np("Do you really want to delete the selected entry?", "Do you really want to delete the selected %1 entries?", rows.count()), i18n("Delete"), KStandardGuiItem::del()); } if (del) { emit translationChanged(0, 0); while (!selectionModel()->selectedIndexes().isEmpty()) { m_model->removeRows(selectionModel()->selectedIndexes()[0].row(), 1, QModelIndex()); } } } void VocabularyView::slotEditCopy() { QModelIndexList sortedIndexes = selectionModel()->selectedIndexes(); std::sort(sortedIndexes.begin(), sortedIndexes.end()); QMimeData *mimeData = m_model->mimeData(sortedIndexes); QClipboard *clipboard = QApplication::clipboard(); clipboard->setMimeData(mimeData); } void VocabularyView::slotEditPaste() { QClipboard *clipboard = QApplication::clipboard(); const QMimeData *mimeData = clipboard->mimeData(); const KEduVocVocabularyMimeData *vocMimeData = qobject_cast(mimeData); if (vocMimeData) { qDebug() << "Clipboard contains vocabulary mime data."; foreach(const KEduVocVocabularyMimeData::MimeExpression & mimeEntry, vocMimeData->expressionList()) { KEduVocExpression *pasteExpression = new KEduVocExpression(mimeEntry.expression); m_model->appendEntry(pasteExpression); // find word type (create if not found) KEduVocWordType *type = m_doc->wordTypeContainer(); foreach(int translation, mimeEntry.wordTypes.keys()) { // append if needed foreach(const QString & typeName, mimeEntry.wordTypes.value(translation).wordType) { qDebug() << mimeEntry.wordTypes.value(translation).wordType; KEduVocContainer *childType = type->childContainer(typeName); if (!childType) { // the doc does not contain the right word type - create it childType = new KEduVocWordType(typeName); type->appendChildContainer(childType); } type = static_cast(childType); } pasteExpression->translation(translation)->setWordType(type); // check for special type stuff if (type->wordType() != mimeEntry.wordTypes.value(translation).grammarType) { if (type->wordType() == KEduVocWordFlag::NoInformation) { type->setWordType(mimeEntry.wordTypes.value(translation).grammarType); } } } } } else if (mimeData->hasText()) { qDebug() << "Clipboard contains text data."; // split at newline QStringList lines = clipboard->text().split('\n'); foreach(QString line, lines) { // split at tabs or semicolon: m_model->appendEntry(new KEduVocExpression(line.split(QRegExp(QStringLiteral("[\t;]")), QString::KeepEmptyParts))); } } } void VocabularyView::slotCutEntry() { slotEditCopy(); deleteSelectedEntries(false); } void VocabularyView::slotSelectionChanged(const QItemSelection &, const QItemSelection &) { bool hasSelection = selectionModel()->hasSelection(); m_deleteEntriesAction->setEnabled(hasSelection); m_clearSelectionAction->setEnabled(hasSelection); m_copyAction->setEnabled(hasSelection); m_cutAction->setEnabled(hasSelection); } void VocabularyView::setDocument(KEduVocDocument * doc) { m_doc = doc; m_vocabularyDelegate->setDocument(doc); QTimer::singleShot(0, this, SLOT(reset())); } /** * Set the translator to be used by the delegate * @param translator */ -void VocabularyView::setTranslator(Translator* translator) +void VocabularyView::setTranslator(KEduVocTranslator* translator) { m_vocabularyDelegate->setTranslator(translator); } void VocabularyView::slotShowVocabularyColumnsDialog() { VocabularyColumnsDialog *dialog = new VocabularyColumnsDialog(m_doc, this); if (dialog->exec() == QDialog::Accepted) { reset(); } } void VocabularyView::checkSpelling(int language) { if (!m_model->rowCount()) { KMessageBox::information(this, i18n("Nothing to spell check.")); return; } if (!m_spellChecker) { m_spellChecker = new Sonnet::BackgroundChecker(this); m_spellDialog = new Sonnet::Dialog(m_spellChecker, this); connect(m_spellDialog, SIGNAL(done(QString)), this, SLOT(continueSpelling())); connect(m_spellDialog, &Sonnet::Dialog::misspelling, this, &VocabularyView::misspelling); connect(m_spellDialog, &Sonnet::Dialog::replace, this, &VocabularyView::spellingReplace); } m_spellColumn = language * KEduVocVocabularyModel::EntryColumnsMAX; m_spellRow = -1; if (m_spellColumn < 0) { return; } QString locale = m_doc->identifier(language).locale(); LanguageSettings settings(locale); QString spellCode = settings.spellChecker().isEmpty() ? locale : settings.spellChecker(); m_spellChecker->changeLanguage(spellCode); if (!m_spellChecker->speller().isValid()) { qDebug() << "Invalid Language, popup here!"; KNotification::event(KNotification::Warning, i18nc("@title of a popup", "No Spell Checker Available"), i18nc("@popupmessage", "Either the language set up is incorrect or no spellchecker was installed for this locale: %1.", locale)); } m_spellDialog->show(); continueSpelling(); } void VocabularyView::continueSpelling() { qDebug() << "Check spelling: " << m_spellRow << m_spellColumn; ++m_spellRow; while (m_spellRow < m_model->rowCount()) { QModelIndex index = m_model->index(m_spellRow, m_spellColumn); qDebug() << " " << m_model->data(index).toString(); if (!m_model->data(index).toString().isEmpty()) { m_spellDialog->setBuffer(m_model->data(index).toString()); break; } else { ++m_spellRow; } } } void VocabularyView::selectIndex(const QModelIndex &newIndex) { selectionModel()->select(newIndex, QItemSelectionModel::ClearAndSelect); selectionModel()->setCurrentIndex(newIndex, QItemSelectionModel::ClearAndSelect); scrollTo(newIndex); } bool VocabularyView::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress && Prefs::smartAppend()) { QKeyEvent *keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { if (selectionModel()->currentIndex().row() == m_model->rowCount() - 1) { appendEntry(); } } } // standard event processing return QObject::eventFilter(obj, event); } void VocabularyView::misspelling(const QString & word, int start) { Q_UNUSED(word) Q_UNUSED(start) QModelIndex index = m_model->index(m_spellRow, m_spellColumn); selectIndex(index); } void VocabularyView::spellingReplace(const QString & oldWord, int start, const QString & newWord) { qDebug() << oldWord << start << newWord; QModelIndex index = m_model->index(m_spellRow, m_spellColumn); QString data = index.data().toString(); QString newData = data.replace(start, oldWord.length(), newWord); qDebug() << "Changing " << data << " to " << newData; m_model->setData(index, newData); } QModelIndexList VocabularyView::getSelectedIndexes() const { return selectionModel()->selectedIndexes(); } diff --git a/src/editor/vocabularyview.h b/src/editor/vocabularyview.h index d5af82cc..971190bb 100644 --- a/src/editor/vocabularyview.h +++ b/src/editor/vocabularyview.h @@ -1,135 +1,132 @@ /*************************************************************************** Copyright 2006, 2007 Peter Hedlund Copyright 2007-2008 Frederik Gladhorn ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef VOCABULARYVIEW_H #define VOCABULARYVIEW_H #include // Qt #include #include // KDE class KActionMenu; class QAction; // KEduVocDocument class KEduVocExpression; class KEduVocDocument; class KEduVocVocabularyFilter; - - -// parley / collection -class Translator; +class KEduVocTranslator; namespace Editor { class EditorWindow; class VocabularyDelegate; class VocabularyView : public QTableView { Q_OBJECT public: explicit VocabularyView(EditorWindow *parent); virtual ~VocabularyView() {} KActionMenu* columnsActionMenu(); void setFilter(KEduVocVocabularyFilter * model); /** Save column visibility settings */ void saveColumnVisibility() const; QModelIndexList getSelectedIndexes() const; public slots: void reset() Q_DECL_OVERRIDE; void appendEntry(); /** Delete the currently selected entries */ void deleteSelectedEntries(bool askConfirmation = true); /** put the marked text/object into the clipboard*/ void slotEditCopy(); /** Cut an entry */ void slotCutEntry(); /** paste the clipboard into the document*/ void slotEditPaste(); /** * Append a char to the last edited entry (used to add the phonetic stuff). * @param c the char */ void appendChar(const QChar & c); void setDocument(KEduVocDocument * doc); - void setTranslator(Translator* translator); + void setTranslator(KEduVocTranslator* translator); void checkSpelling(int language); /** * Show the vocabulary columns dialog to enable or disable the columns in the view */ void slotShowVocabularyColumnsDialog(); signals: void translationChanged(KEduVocExpression*, int); private slots: void slotCurrentChanged(const QModelIndex& current, const QModelIndex& previous); void slotSelectionChanged(const QItemSelection&, const QItemSelection&); void continueSpelling(); void misspelling(const QString &word, int start); void spellingReplace(const QString& oldWord, int start, const QString &newWord); private: void selectIndex(const QModelIndex &index); // trap enter presses at the end of the document to add a new entry instead of moving to the first cell bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; // Make this private to avoid inadvertent use. Instead use setFilter() which is public. void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE { Q_UNUSED(model) } QAction* m_appendEntryAction; QAction* m_deleteEntriesAction; QAction* m_copyAction; QAction* m_cutAction; QAction* m_pasteAction; QAction* m_selectAllAction; QAction* m_clearSelectionAction; KEduVocVocabularyFilter* m_model; VocabularyDelegate* m_vocabularyDelegate; KEduVocDocument *m_doc; int m_spellColumn; int m_spellRow; Sonnet::BackgroundChecker *m_spellChecker; Sonnet::Dialog *m_spellDialog; }; } #endif diff --git a/src/scripts/scripting/document.h b/src/scripts/scripting/document.h index f7e91476..68032278 100644 --- a/src/scripts/scripting/document.h +++ b/src/scripts/scripting/document.h @@ -1,554 +1,554 @@ /*************************************************************************** Copyright 2008 Avgoustinos Kadis ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef SCRIPTOBJECTDOCUMENT_H #define SCRIPTOBJECTDOCUMENT_H #include #include "lesson.h" #include "identifier.h" #include namespace Scripting { class Translation; /** * @class Document * @brief KEduVocDocument wrapping class for Kross scripts * * The Document class provides methods and properties for accessing the document lessons, entries, languages, word types and general document parameters. The easiest way of accessing this class is through the Parley.document (Parley.doc) property like in the example. * * @code * #how to get a reference to the Parley's active document * import Parley * doc = Parley.doc * print doc.title, doc.author, doc.authorContact * @endcode * * You can access document lessons with the following ways: * - Document::rootLesson property * - allLessons() function * - findLesson() function * * and add a new lesson with * - newLesson() and appendLesson() function * - Document::appendNewLesson(const QString &) function * - Document::appendNewLesson(const QString &,Lesson*) function * * The document identifiers (see Identifier class) can be set by these functions: * - newIdentifier() and appendIdentifier() functions * - appendNewIdentifier() function * - removeIdentifier() function (for removing a language) * * and be accessed by: * - as a list with identifiers() function * - individually by identifier() function * - and get how many identifiers exist with identifierCount() function * * The saveAs() function can be used to save into a file a newly created document, or the active document. See Parley::newDocument(). * * @author Avgoustinos Kadis */ class Document : public QObject { Q_OBJECT /// Document's root lesson Q_PROPERTY(QObject * rootLesson READ rootLesson) /// Document's title Q_PROPERTY(QString title READ title WRITE setTitle) /// Document author's name Q_PROPERTY(QString author READ author WRITE setAuthor) /// Author contact info (email) Q_PROPERTY(QString authorContact READ authorContact WRITE setAuthorContact) /// Document license Q_PROPERTY(QString license READ license WRITE setLicense) /// Comment about the document Q_PROPERTY(QString documentComment READ documentComment WRITE setDocumentComment) /// Category that the lesson belongs Q_PROPERTY(QString category READ category WRITE setCategory) /// Generator program (which program generates this file) Q_PROPERTY(QString generator READ generator WRITE setGenerator) /// Document version Q_PROPERTY(QString version READ version WRITE setVersion) /// Delimiter (separator) used for csv import and export. Q_PROPERTY(QString csvDelimiter READ csvDelimiter WRITE setCsvDelimiter) /// URL of the XML file Q_PROPERTY(QString url READ url WRITE setUrl) Q_ENUMS(FileType) public: /// known vocabulary file types enum FileType { KvdNone, Automatic, Kvtml, Wql, Pauker, Vokabeln, Xdxf, Csv, Kvtml1 }; /// the return code when opening/saving enum ErrorCode { NoError = 0, Unknown, InvalidXml, FileTypeUnknown, FileCannotWrite, FileWriterFailed, FileCannotRead, FileReaderFailed, FileDoesNotExist }; /// used as parameter for pattern enum FileDialogMode { Reading, Writing }; /// delete only empty lessons or also if they have entries enum LessonDeletion { DeleteEmptyLesson, DeleteEntriesAndLesson }; explicit Document(QObject* parent = 0); explicit Document(KEduVocDocument * doc); ~Document(); - KEduVocDocument * kEduVocDocument() { + ::KEduVocDocument * kEduVocDocument() { return m_doc; } //Property: rootLesson (READ) QObject * rootLesson() { return new Lesson(m_doc->lesson()); } KEduVocWordType * wordTypeFromString(const QString & name); //**** Property Methods ****// /* set the title of the file * @param title title to set */ void setTitle(const QString & title) { m_doc->setTitle(title); } /* @returns the title of the file */ QString title() const { return m_doc->title(); } /* set the author of the file * @param author author to set */ void setAuthor(const QString & author) { m_doc->setAuthor(author); } /* @returns the author of the file */ QString author() const { return m_doc->author(); } /* set the author contact info * @param contact email/contact info to set */ void setAuthorContact(const QString & authorContact) { m_doc->setAuthorContact(authorContact); } /* @returns the author contact information */ QString authorContact() const { return m_doc->authorContact(); } /* set the license of the file * @param license license to set */ void setLicense(const QString & license) { m_doc->setLicense(license); } /* @returns the license of the file */ QString license() const { return m_doc->license(); } /* set the comment of the file * @param comment comment to set */ void setDocumentComment(const QString & comment) { m_doc->setDocumentComment(comment); } /* @return the comment of the file */ QString documentComment() const { return m_doc->documentComment(); } /* set the category of the file * @param category category to set */ void setCategory(const QString & category) { m_doc->setCategory(category); } /* @return the category of the file */ QString category() const { return m_doc->category(); } /* * Sets the generator of the file */ void setGenerator(const QString & generator) { m_doc->setGenerator(generator); } /* @returns the generator of the file */ QString generator() const { return m_doc->generator(); } /* Sets version of the loaded file * @param ver the new version */ void setVersion(const QString & ver) { m_doc->setVersion(ver); } /* @returns the version of the loaded file */ QString version() const { return m_doc->version(); } /* * Returns the delimiter (separator) used for csv import and export. * The default is a single tab character * * @returns the delimiter used */ QString csvDelimiter() const { return m_doc->csvDelimiter(); } /* * Sets the delimiter (separator) used for csv import and export * * @param delimiter the delimiter to use */ void setCsvDelimiter(const QString &delimiter) { m_doc->setCsvDelimiter(delimiter); } /* * Sets the URL of the XML file */ void setUrl(const QString& url) { m_doc->setUrl(QUrl(url)); } /* @returns the URL of the XML file */ QString url() const { return m_doc->url().toString(); } public slots: /** * Creates and returns a new lesson (doesn't add it as a sublesson to any lesson) * * @code * #how to add a new lesson to the root lesson * import Parley * newlesson = Parley.doc.newLesson("My New Lesson") * Parley.doc.rootLesson.appendChildLesson(newlesson) * @endcode * * @param name Name of the lesson * @return Lesson object (the new lesson) */ QObject * newLesson(const QString & name) { return new Lesson(name); } /** * Appends a lesson to the document * * @code * #how to add a new lesson with appendLesson() function * import Parley * newlesson = Parley.doc.newLesson("My New Lesson") * Parley.doc.appendLesson(newlesson) * @endcode * * @param lesson Lesson object (the lesson to be added) */ void appendLesson(QObject * lesson); /** * Creates a new lesson and appends it to the root lesson * @code * #how to add a new lesson to the root lesson * import Parley * newlesson = Parley.doc.appendNewLesson("My New Lesson") * @endcode * @param name Lesson name * @return A reference to the new lesson */ QObject * appendNewLesson(const QString & name); /** * Creates a new lesson and appends it to the @p parent lesson * @code * #how to add a new lesson under another lesson * import Parley * parentLesson = Parley.doc.appendNewLesson("My Parent Lesson") * childLesson = Parley.doc.appendNewLesson("My new child lesson",parentLesson) * @endcode * @param name Lesson name * @param parent Parent lesson * @return A reference to the new lesson */ QObject * appendNewLesson(const QString & name, Lesson * parent); /** * Returns all the lessons in the document (including sublessons) * @code * #how to print the names of all the lessons * import Parley * for lesson in Parley.document.allLessons(): * print lesson.name * @endcode * @return A list of all the lessons in the document */ QVariantList allLessons(); /** * Searches through all the lessons (recursively) and returns the first lesson the specified @p name * @code * #how to search for a lesson * import Parley * lesson = Parley.doc.findLesson("Lesson 2") * if lesson != None: * print lesson.name * else: * print "not found" * @endcode * @param name Name of the lesson to look for * @return A reference to a lesson if found. 0 otherwise */ QObject * findLesson(const QString& name); /** * Sets the word type (@p wordtype) of the given @p tr translation object. * If the @p wordtype is not valid, no changes are made to the translation object * @param tr Translation object to set it's word type * @param wordtype Word type name */ void setWordType(QObject * tr, const QString & wordtype); /** * Returns a string list with all the available word type's names */ QStringList wordTypes(); // --------------------- copied from KEduVocDocument /* * Open a document file * * @param url url to file to open * @returns ErrorCode */ // int open ( const QString & url ) { return m_doc->open ( url ); } /** * Saves the data under the given name * * @param url if url is empty (or NULL) actual name is preserved * @param ft the filetype to be used when saving the document (default value: Automatic). See enum FileType. * @param generator the name of the application saving the document (default value: "Parley") * @returns ErrorCode */ - int saveAs(const QString & url, KEduVocDocument::FileType ft = KEduVocDocument::Automatic, const QString & generator = QStringLiteral("Parley")) { + int saveAs(const QString & url, ::KEduVocDocument::FileType ft = ::KEduVocDocument::Automatic, const QString & generator = QString("Parley")) { m_doc->setGenerator(generator); return m_doc->saveAs(QUrl(url), ft); } // QByteArray toByteArray ( const QString &generator ); /** * Merges data from another document * * @param docToMerge document containing the data to be merged * @param matchIdentifiers if true only entries having identifiers present in the * current document will be mergedurl is empty (or NULL) actual name is preserved */ void merge(Document *docToMerge, bool matchIdentifiers) { m_doc->merge(docToMerge->kEduVocDocument(), matchIdentifiers); } // NOT NEEDED /* * Indicates if the document is modified * * @param dirty new state */ // void setModified ( bool dirty = true ) { m_doc->setModified ( dirty ); } /* @returns the modification state of the doc */ // bool isModified() const { return m_doc->isModified(); } // *** identifier methods *** /** * @returns the number of different identifiers (usually languages) */ int identifierCount() const { return m_doc->identifierCount(); } /** * Creates a new identifier and returns a reference to it * @return */ QObject * newIdentifier() { return new Identifier(); } /** * Append a new identifier by giving the @p name and @p locale * @param name Language description ex. "American English" * @param locale Language locale ex. "en_US" */ void appendNewIdentifier(const QString& name, const QString& locale); /** * Appends a new identifier (usually a language) * * @param identifier the identifier to append. If empty default names are used. * @returns the identifier number */ int appendIdentifier(Identifier * identifier) { return m_doc->appendIdentifier(* (identifier->kEduVocIdentifier())); } /* * Sets the identifier of translation * * @param index number of translation 0..x * @param lang thr language identifier: en=english, de=german, ... */ // void setIdentifier ( int index, Identifier * lang ) { m_doc->setIdentifier ( index,* ( lang->kEduVocIdentifier() ) ); } /** * Returns the identifier of translation @p index * * @param index number of translation 0..x * @returns the language identifier: en=english, de=german, ... */ QObject * identifier(int index) { return new Identifier(m_doc->identifier(index)); } /** * Removes identifier and the according translations in all entries * * @param index number of translation 0..x */ void removeIdentifier(int index) { m_doc->removeIdentifier(index); } /** Returns a list of all the identifiers of this document */ QVariantList identifiers(); /* * Determines the index of a given identifier * * @param lang identifier of language * @returns index of identifier, 0 = original, 1..n = translation, -1 = not found */ // not implemented in KEduVocDocument // int indexOfIdentifier ( const QString &name ) const { return m_doc->indexOfIdentifier(name); } // *** grade methods *** /* * Retrieves the identifiers for the current query * not written in the new version! * * @param org identifier for original * @param trans identifier for translation */ // KDE_DEPRECATED void queryIdentifier ( QString &org, QString &trans ) const; /* * Sets the identifiers for the current query * not written in the new version! * * @param org identifier for original * @param trans identifier for translation */ // KDE_DEPRECATED void setQueryIdentifier ( const QString &org, const QString &trans ); // *** lesson methods *** /* get the lesson root object * @returns a pointer to the lesson object */ // KEduVocLesson * lesson(); // KEduVocWordType * wordTypeContainer(); // KEduVocLeitnerBox * leitnerContainer(); // *** file format specific methods *** - static KEduVocDocument::FileType detectFileType(const QString &fileName) { - return KEduVocDocument::detectFileType(fileName); + static ::KEduVocDocument::FileType detectFileType(const QString &fileName) { + return ::KEduVocDocument::detectFileType(fileName); } /** * Create a string with the supported document types, that can be used * as filter in KFileDialog. It includes also an entry to match all the * supported types. * * @param mode the mode for the supported document types. See FileDialogMode enum * @returns the filter string */ - static QString pattern(KEduVocDocument::FileDialogMode mode) { - return KEduVocDocument::pattern(mode); + static QString pattern(::KEduVocDocument::FileDialogMode mode) { + return ::KEduVocDocument::pattern(mode); } /** Returns a more detailed description of the @p errorCode given */ static QString errorDescription(int errorCode) { - return KEduVocDocument::errorDescription(errorCode); + return ::KEduVocDocument::errorDescription(errorCode); } private: - KEduVocDocument * m_doc; + ::KEduVocDocument * m_doc; }; } #endif diff --git a/src/scripts/scripting/parley.cpp b/src/scripts/scripting/parley.cpp index 627ea711..1bd0f24e 100644 --- a/src/scripts/scripting/parley.cpp +++ b/src/scripts/scripting/parley.cpp @@ -1,152 +1,152 @@ /*************************************************************************** Copyright 2008 Avgoustinos Kadis ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "parley.h" #include "editor/editor.h" #include +#include #include "vocabularyview.h" #include "../scriptmanager.h" -#include "../translator.h" #include "document.h" #include "lesson.h" #include "expression.h" #include "translation.h" #include #include #include using namespace Editor; namespace Scripting { Parley::Parley(EditorWindow * editor) : QObject(), m_editor(editor) { - m_translator = new Translator(this); //parameter has to be cause it's used by Translator to access callTranslateWord + m_translator = new KEduVocTranslator(this); //parameter has to be cause it's used by Translator to access callTranslateWord m_doc = new Document(m_editor->m_mainWindow->parleyDocument()->document()); } Parley::~Parley() { delete m_translator; delete m_doc; } void Parley::callTranslateWord(const QString & word, const QString& fromLanguage, const QString& toLanguage) { emit translationStarted(word, fromLanguage, toLanguage); emit translateWord(word, fromLanguage, toLanguage); emit translationFinished(word, fromLanguage, toLanguage); } void Parley::addTranslation(const QString &word, const QString &fromLanguage, const QString &toLanguage, const QString &translation) { if (m_translator) m_translator->addTranslation(word, fromLanguage, toLanguage, translation); } QStringList Parley::locales() { /// @todo Change it into a QMap property (Parley.languageCodes) return QLocale().uiLanguages(); } QString Parley::localeName(const QString &locale) { return QLocale( locale ).nativeLanguageName( ); } void Parley::open(const QString &filename) { QUrl url( QUrl::fromLocalFile(filename) ); qDebug() << url; m_editor->m_mainWindow->parleyDocument()->open(url); } QObject* Parley::activeLesson() { return new Lesson(m_editor->m_vocabularyModel->lesson()); } QVariantList Parley::selectedEntries() { QVariantList entries; //get selected indexes and active lesson QModelIndexList indexes = m_editor->m_vocabularyView->getSelectedIndexes(); //get the unique selected entries QSet kentries; foreach(const QModelIndex & index, indexes) { // qDebug() << index.row() << index.data(Qt::DisplayRole); KEduVocExpression * expr = qvariant_cast (index.data(KEduVocVocabularyModel::EntryRole)); kentries << expr; } //convert them to Expression objects and add them to the QVariantList foreach(KEduVocExpression * expr, kentries) { // Expression entry(expr); // qDebug() << entry.translationTexts(); QObject * obj = new Expression(expr); entries << QVariant::fromValue(obj); } return entries; } QVariantList Parley::selectedTranslations() { QVariantList translations; //get selected indexes and active lesson QModelIndexList indexes = m_editor->m_vocabularyView->getSelectedIndexes(); //get the unique selected entries QSet ktranslations; // const QModelIndex &index; foreach(const QModelIndex & index, indexes) { if (KEduVocVocabularyModel::columnType(index.column()) == KEduVocVocabularyModel::Translation) { KEduVocExpression * expr = qvariant_cast (index.data(KEduVocVocabularyModel::EntryRole)); ktranslations << expr->translation(KEduVocVocabularyModel::translation(index.column())); } // qDebug() << index.row() << index.data(Qt::DisplayRole); } //convert them to Expression objects and add them to the QVariantList foreach(KEduVocTranslation * tr, ktranslations) { // Translation transltion(tr); // qDebug() << entry.translationTexts(); QObject * obj = new Translation(tr); translations << QVariant::fromValue(obj); } return translations; } QObject * Scripting::Parley::newAction(const QString & name, const QString& text) { //create new action QAction* action = new QAction(text, m_editor); m_editor->m_scriptManager->addScriptAction(name, action); return action; } } diff --git a/src/scripts/scripting/parley.h b/src/scripts/scripting/parley.h index e01a3ff6..6adff3a8 100644 --- a/src/scripts/scripting/parley.h +++ b/src/scripts/scripting/parley.h @@ -1,415 +1,416 @@ /*************************************************************************** Copyright 2008 Avgoustinos Kadis ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef SCRIPTOBJECTPARLEY_H #define SCRIPTOBJECTPARLEY_H #include "document.h" #include #include #include #include #include #include +#include namespace Editor { class EditorWindow; } -class Translator; +class KEduVocTranslator; /** * @namespace Scripting * @brief Contains all the classes exposed to Kross scripts. * * Main entry point is the Scripting::Parley class which allows us to access all the other Scripting classes (see code below). * * Class Hierarchy: * * - Parley * - Document * - Lesson (inherits Container) * - Expression (known as Entry in functions) * - Translation (inherits Text) * - Identifier * *

How to create a new %Parley script (full example)

* * Each %Parley script must be accompanied by a .desktop file, both put in the plugins folder in parley data directory (usually in /usr/share/apps/parley/plugins/). In this example the desktop file is "example.desktop" and the script file is "example.py". * * The desktop file provides information about the script's functionality, author and specifies the script file that implements it. This information will appear in the Scripts Manager (Scripts->Script Manager in main menu) and the user will be able to enable/disable the script. If the script is enabled then it'll be loaded every time Parley starts up. * * Content of example.desktop (/usr/share/apps/parley/plugins/example.desktop) * @code [Desktop Entry] Encoding=UTF-8 Icon=mypluginicon Type=Service ServiceTypes=KPluginInfo Name=Example Parley Script Comment=This Script offers two actions: 1) Move to new lesson 2) Mark as known for the Scripts menu Script=example.py X-KDE-PluginInfo-Author=Avgoustinos Kadis X-KDE-PluginInfo-Email=avgoustinos.kadis@kdemail.net X-KDE-PluginInfo-Name=parley_example_script X-KDE-PluginInfo-Version=1.1 X-KDE-PluginInfo-Website=http://edu.kde.org/parley X-KDE-PluginInfo-Category=examples X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true @endcode * * The script file will contain the functions (script functionality) and some code for creating an action for the Scripts menu. In the example below, the functions are moveSelectedToNewLesson() and markAsKnown() and they are called by the two actions that are added to the scripts menu (action1 and action2). * * When the script file is loaded all the global code (outside of any function) is executed. This way we can register the Scripts menu actions and connect them with script functions (see example below for how to do this). * * Another way to have a function called is by connecting it to a %Parley signal (see Parley::translateWord() and the example in Detailed Description of the Parley class). * * Content of example.py (/usr/share/apps/parley/plugins/example.py) @code #!/usr/bin/env kross import Parley #FUNCTIONS #moves selected entries to a new lesson def moveSelectedToNewLesson(): selected_entries = Parley.selectedEntries() if len(selected_entries) > 0: newlesson = Parley.doc.appendNewLesson("New Lesson") for entry in selected_entries: newlesson.appendEntry(entry) #marks the selected translations as known (grade 7) def markAsKnown(): for tr in Parley.selectedTranslations(): tr.grade = 7 #SCRIPT MENU #create a new action for the Scripts menu (action1) action1 = Parley.newAction("example_action1","Move to new lesson") action1.statusTip="Moves the selected rows to a new lesson" Parley.connect(action1,"triggered()",moveSelectedToNewLesson) #create a new action for the Scripts menu (action2) action2 = Parley.newAction("example_action2","Mark as known (highest level)") action2.statusTip="Sets the confidence level selected translations to 7 (highest level)" Parley.connect(action2,"triggered()",markAsKnown) @endcode * * After creating the Script action and being able to call a function you can start adding your own code, using the documentation provided for the scripting classes and by seeing other examples. * * For debugging use the standard output and observed it in the terminal. * */ namespace Scripting { /** * @class Parley * @brief Parley scripting class (main entry point of a %Parley Kross script) * * Parley class is the main entry point of Parley scripting classes. Through it you can access the Document class (Parley.doc or Parley.document) which provides functionality for viewing/modifying a %Parley document (%KEduVocDocument), that means access lessons, entries, document languages etc. * * The Parley class has to do more with the active %Parley application. Here it follows a list of possible usages of Parley class: * * - Add a new Action to the script menu (see Parley::newAction() function) * - Add a new translation script (see Parley::translateWord() signal) * - Have direct access to the active lesson (see Parley::activeLesson property) * - Have access to various enumerations (see Parley::Number, Parley::Case, Parley::Person, Parley::Gender and Parley::Definiteness enumerations) * - Create a new %Parley %Document (see Parley::newDocument() function) * * Signals and Slots: To connect a script function (slot) to a signal you just define a function with the same name as the signal or use the Parley.connect function: * @code * #how to connect a function to a signal (example with Parley::translateWord() signal) * def translateFromInternet(word,fromLang,toLang): * print "Translating from Internet!!.." * * Parley.connect("translateWord(const QString &,const QString &,const QString &)",translateFromInternet) * @endcode * * @author Avgoustinos Kadis */ class Parley : public QObject { Q_OBJECT /// Read-only property of the active document Q_PROPERTY(QObject * document READ getDocument) /// Abreviation of document property (same as Parley.document) Q_PROPERTY(QObject * doc READ getDocument) /// Currently active lesson Q_PROPERTY(QObject * activeLesson READ activeLesson) // Q_ENUMS ( Number Case Person Gender Definiteness ) Q_ENUMS(Flags) public: enum Flags { // This is used for both empty flags and to denote no flags of the correct type were set. NoInformation = 0x0, // Gender Masculine = 0x1, Feminine = 0x2, Neuter = 0x4, // Plurality Singular = 0x10, Dual = 0x20, Plural = 0x40, // Part of Speech Verb = 0x100, Noun = 0x200, Pronoun = 0x400, Adjective = 0x800, Adverb = 0x1000, Article = 0x2000, Conjunction = 0x4000, // Person First = 0x10000, Second = 0x20000, Third = 0x40000, // Declension Case Nominative = 0x80000, Genitive = 0x100000, Dative = 0x200000, Accusative = 0x400000, Ablative = 0x800000, Locative = 0x1000000, Vocative = 0x2000000, // Other assorted flags Definite = 0x4000000, // The article is definite Indefinite = 0x8000000, // The article is indefinite Regular = 0x10000000, Irregular = 0x20000000 }; explicit Parley(Editor::EditorWindow * editor); ~Parley(); /* * Emits translateWord signal so the script function connected to it translate the @p word * @param word Word to translate * @param fromLanguage The language of @p word to translate from * @param toLanguage The language you want to translate to */ void callTranslateWord(const QString & word, const QString& fromLanguage, const QString& toLanguage); //sets the translator object // void setTranslator ( Translator* translator ) { m_translator = translator; } - Translator * translator() { + KEduVocTranslator * translator() { return m_translator; } //Returns the active document QObject* getDocument() { return m_doc; } //Returns the active lesson QObject* activeLesson(); public Q_SLOTS: QStringList dataDirs() { return QStandardPaths::standardLocations(QStandardPaths::DataLocation); } QStringList pluginDirs() { QStringList basedirs(QStandardPaths::standardLocations(QStandardPaths::DataLocation)); QStringList ret; foreach ( const QString dir , basedirs){ ret << (dir + "/plugins"); } return ret; } /** Returns a list of Expression objects (the selected entries of the active lesson) */ QVariantList selectedEntries(); /** Returns a list of Translation objects (the selected translations of the active lesson) */ QVariantList selectedTranslations(); /** * Adds the found @p translation of the @p word from language @p fromLanguage to language @p toLanguage to %Parley translations to be used for translating lesson entries (or anything else). This function is ment to be used by scripts to add a translation of a word by parsing either online or offline dictionaries. * * @code * #example usage of addTranslation function * import Parley * #function called by Parley whenever a translation of a word is needed * def translateWord(word,fromLang,toLang): * <> * Parley.addTranslation(word,fromLang,toLang,foundWord) * <> * @endcode * * @param word Translated word * @param fromLanguage From language * @param toLanguage To language * @param translation %Translation of word */ void addTranslation(const QString &word, const QString &fromLanguage, const QString &toLanguage, const QString &translation); /** * Returns a list of all available locales (to be used by the scripts) * @return */ QStringList locales(); /** * Gives the language name of the given @p locale * @param locale Language locale * @return Language name */ QString localeName(const QString &locale); /// @todo Make this function working (not very important function) /* * Open the Parley Document @p file * Usage: * @code * import Parley * Parley.open("Vocab/MyVocab.kvtml") * @endcode * @param file Parley Document file path (ex. /home/kde-user/MyVocab.kvtml) */ void open(const QString &filename); /** * Creates a new document and returns a reference to it * * @code * #how to create a new document, add lessons, add entries and save it to a kvtml file * import Parley * * #create new document * doc = Parley.newDocument() * doc.title = "New document" * * #set identifiers * doc.appendNewIdentifier("English","en_US") * doc.appendNewIdentifier("French","fr") * * #lessons * l1 = doc.newLesson("Lesson1") * doc.rootLesson.appendChildLesson(l1) * * #add a new entry (first way) * e = l1.newEntry() * e.setTranslation(0,"dog") * e.setTranslation(1,"chien") * l1.appendEntry(e) * * #add a new entry (second way) * ee = l1.newEntry(["glass","verre"]) * l1.appendEntry(ee) * #third way * ee = l1.appendNewEntry(["book","livre"]) * * #add a new lesson (fast way) * l2 = doc.appendNewLesson("Lesson 2") * * #add a new child lesson under "Lesson 2" * l3 = doc.appendNewLesson("Lesson 3",l2) * * #add a new entry (third way) * l2.appendNewEntry(["I","je"]); * l3.appendNewEntry(["good morning","bonjour"]) * * #save document * doc.saveAs("/home/kde-devel/test_new_document.kvtml") * @endcode * * @return A Document object, the newly created lesson */ QObject * newDocument() { return new Document(); } /** * Creates and adds to the Scripts menu a new QAction (see QAction documentation) * * @code * #how to add two new Scripts menu entries * import Parley * * def convertLessonToPDF(): * print "Converting lesson to PDF.." * * def convertLessonToHTML(): * print "Converting lesson to HTML.." * * #one way of creating a new action * newaction_pdf = Parley.newAction("convert_lesson_pdf") * newaction_pdf.text="Convert Lesson to PDF" * Parley.connect(newaction_pdf,"triggered()",convertLessonToPDF) * * #second way of creating a new action (short) * newaction_html = Parley.newAction("convert_lesson_html","Convert Lesson to HTML") * Parley.connect(newaction_html,"triggered()",convertLessonToHTML) * @endcode * * @param name Unique action name * @param text Action's text (what text appears in the scripts menu) * @return A reference to a QAction object (accessible by scripts) */ QObject * newAction(const QString & name, const QString & text = QString()); Q_SIGNALS: /** * Slots (script functions) connected to this signal are called when a translation of @p word is requested. Note that a script function with the same name as a signal will be automatically connected to that signal when the script is activated. * * @code * #example usage of translateWord signal * import Parley * #function called by Parley whenever a translation of a word is needed * def translateWord(word,fromLang,toLang): * <> * Parley.addTranslation(word,fromLang,toLang,foundWord) * <> * @endcode * * @param word Word to translate * @param fromLanguage The language of @p word to translate from * @param toLanguage The language you want to translate to */ void translateWord(const QString & word, const QString& fromLanguage, const QString& toLanguage); /* Emits when the translation of a word is finished (from all the scripts) [not to be used by scripts] */ void translationFinished(const QString & word, const QString& fromLanguage, const QString& toLanguage); /* Emits when the translation of a word starts [not to be used by scripts] */ void translationStarted(const QString & word, const QString& fromLanguage, const QString& toLanguage); private: - Translator* m_translator; + KEduVocTranslator* m_translator; Document* m_doc; Editor::EditorWindow * m_editor; }; } #endif diff --git a/src/scripts/scriptmanager.h b/src/scripts/scriptmanager.h index 1fa0b291..6299c601 100644 --- a/src/scripts/scriptmanager.h +++ b/src/scripts/scriptmanager.h @@ -1,125 +1,127 @@ /*************************************************************************** Copyright 2008 Avgoustinos Kadis ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef SCRIPTMANAGER_H #define SCRIPTMANAGER_H #include "script.h" #include "editor/editor.h" #include +#include + /** * This class finds the scripts installed in the application directory and manages loading and unloading of the scripts. For each script an instance of Script class is created. * * @author Avgoustinos Kadis */ class ScriptManager : public QObject { public: explicit ScriptManager(Editor::EditorWindow * editor); ~ScriptManager(); /** * Finds all the available desktop files in {PARLEY_DATA_FOLDER}/plugins * * @return The list of desktop filenames available for parley */ static QStringList getDesktopFiles(); /** * Returns a QMap (from from categories codenames to categories display label) * to be used in KPluginSelector (ScriptDialog) for displaying the various * categories * * @note this function is not used later on (categories are disabled) * * @return the QMap described above */ static QMap categories(); /** * Parses the desktop @p desktopFile given and returns the value of "Script" entry. * * @param desktopFile The .desktop file that will get the value from * @return The value of "Script" entry. Empty string of no "Script" entry is found */ static QString getScriptEntry(const QString &desktopFile); /** * Returns the full path to the script name given in the @p desktopFile. * * @param desktopFile The desktop file for the parley plugin * @return The full-path to the script */ QString getScriptFileName(const QString &desktopFile); /** * Returns a list of filenames (full path) of enabled scripts */ QStringList enabledScripts(); /** * Modify the parleyrc configuration so it disables the @p dektopFile plugin. * This function is to be used when the plugin is invalid (wrong script name, * incorrect desktop file etc) * * @param desktopFile */ void disablePlugin(const QString &desktopFile); /** * Loads (activates) all the available scripts and notifies the user if any * script was not activated (due to errors in the script) */ void loadScripts(); /** * Adds a QObject as a module for the script * @param obj The QObject to be added to the script * @param name The name of the object as it will appear in the script */ void addObject(QObject * obj, const QString & name); /** * Reloads all the scripts */ void reloadScripts(); /** * Add a QAction to the Scripts menu * @param name The action name * @param action QAction to be added */ void addScriptAction(const QString & name, QAction * action); /** returns the Translator object the Scripting::Parley */ - Translator * translator() { + KEduVocTranslator * translator() { return m_scriptingParley->translator(); } private: Editor::EditorWindow * m_editor; QList m_scripts; QMap m_scriptObjects; QList m_scriptActions; ///script objects (objects that will be used from inside the scripts) Scripting::Parley* m_scriptingParley; }; #endif