diff options
Diffstat (limited to 'ktouch/src/ktouchlectureeditor.cpp')
-rw-r--r-- | ktouch/src/ktouchlectureeditor.cpp | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/ktouch/src/ktouchlectureeditor.cpp b/ktouch/src/ktouchlectureeditor.cpp new file mode 100644 index 00000000..ce433d8c --- /dev/null +++ b/ktouch/src/ktouchlectureeditor.cpp @@ -0,0 +1,420 @@ +/*************************************************************************** + * ktouchlectureeditor.cpp * + * ----------------------- * + * Copyright (C) 2004 by Andreas Nicolai * + * ghorwin@users.sourceforge.net * + * * + * 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 <qlabel.h> +#include <qstring.h> +#include <qstringlist.h> + +#include <kpushbutton.h> +#include <klistview.h> +#include <klineedit.h> +#include <ktextedit.h> +#include <klocale.h> +#include <kdebug.h> +#include <ksqueezedtextlabel.h> +#include <kmessagebox.h> +#include <kcombobox.h> +#include <kfontdialog.h> +#include <kfiledialog.h> + +#include <algorithm> // for std::swap + +#include "ktouchlectureeditor.h" +#include "ktouchlectureeditor.moc" + +#include "ktouchlecture.h" +#include "ktouchopenrequest.h" +#include "ktouch.h" + + +// ************************** +// ***** Public functions *** +// ************************** + +KTouchLectureEditor::KTouchLectureEditor(QWidget *parent, const char* name, bool modal, WFlags fl) + : KTouchLectureEditorDlg(parent, name, modal, fl) +{ + levelListView->setSorting(-1); // don't sort my level list view! + + connect(levelListView, SIGNAL(selectionChanged(QListViewItem*)),this, SLOT(newSelection(QListViewItem*)) ); + connect(newCharsEdit, SIGNAL(textChanged(const QString&)), this, SLOT(newCharsChanged(const QString&)) ); + connect(newBtn, SIGNAL(clicked()), this, SLOT(newLevel()) ); + connect(deleteBtn, SIGNAL(clicked()), this, SLOT(deleteLevel()) ); + connect(upBtn, SIGNAL(clicked()), this, SLOT(moveUp()) ); + connect(downBtn, SIGNAL(clicked()), this, SLOT(moveDown()) ); + + // make the connections for making the lecture modified + connect(titleEdit, SIGNAL(textChanged(const QString&)), this, SLOT(setModified()) ); + connect(lectureCommentEdit, SIGNAL(textChanged()), this, SLOT(setModified()) ); + connect(levelCommentEdit, SIGNAL(textChanged(const QString&)), this, SLOT(setModified()) ); + connect(linesTextEdit, SIGNAL(textChanged()), this, SLOT(setModified()) ); + + // The font, open, save, saveas and close buttons are already connected +} +// ----------------------------------------------------------------------------- + +bool KTouchLectureEditor::startEditor(const KURL& url) { + // call open request dialog and load a lecture, and start the dialogs event loop if + // the user did not cancel the open request dialog + if (openLectureFile(url)==QDialog::Accepted) { + exec(); + return true; + } + else return false; +} +// ----------------------------------------------------------------------------- + + +// ************************* +// ***** Private slots ***** +// ************************* + +void KTouchLectureEditor::fontBtnClicked() { + QFont f(m_lecture.m_fontSuggestions); + if (KFontDialog::getFont(f, false, this, true)==QDialog::Accepted) { + linesTextEdit->setFont(f); + lectureCommentEdit->setFont(f); + levelCommentEdit->setFont(f); + newCharsEdit->setFont(f); + titleEdit->setFont(f); + levelListView->setFont(f); + m_lecture.m_fontSuggestions = f.family(); + setModified(); + } +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::openBtnClicked() { + saveModified(); // save if modified + openLectureFile(""); +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::saveBtnClicked() { + if (m_currentURL.isEmpty()) saveAsBtnClicked(); + else { + transfer_from_dialog(); + m_lecture.saveXML(this, m_currentURL); + setModified(false); + } +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::saveAsBtnClicked() { + QString tmp = KFileDialog::getSaveFileName(QString::null, + "*.ktouch.xml|KTouch Lecture Files(*.ktouch.xml)\n*.*|All Files", this, i18n("Save Training Lecture") ); + if (!tmp.isEmpty()) { + transfer_from_dialog(); + m_currentURL = tmp; + m_lecture.saveXML(this, m_currentURL); + setCaption(m_currentURL.url()); + setModified(false); + } +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::newSelection(QListViewItem* item) { + if (m_selecting) return; + bool current_modified_flag = m_modified; // remember our current status + // first store the current level data + storeCurrentLevel(); + // now we need to find the level which has been selected + QListViewItem *i = levelListView->firstChild(); + unsigned int level=0; + while (i!=0 && i!=item) { + i = i->nextSibling(); + ++level; + }; + if (i!=0) { + m_currentItem = i; + m_level = level; + showCurrentLevel(); + } + m_selecting = true; // prevent the selectionChanged() signal from interfering + levelListView->setSelected(m_currentItem, true); + m_selecting = false; + + if (m_lecture.m_lectureData.size()==1) { + downBtn->setEnabled(false); + upBtn->setEnabled(false); + } + else { + if (m_level==m_lecture.m_lectureData.size()-1) downBtn->setEnabled(false); + else downBtn->setEnabled(true); + if (m_level==0) upBtn->setEnabled(false); + else upBtn->setEnabled(true); + }; + setModified(current_modified_flag); +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::newCharsChanged(const QString& text) { + if (m_currentItem==0) return; // shouldn't happen, but a little bit of paranoia... + m_currentItem->setText(0, text); + setModified(); +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::newLevel() { + createNewLevel(); + QListViewItem *newItem = new QListViewItem( levelListView, + levelListView->lastItem(), m_lecture.m_lectureData.back().m_newChars ); + newSelection(newItem); + upBtn->setEnabled(true); + downBtn->setEnabled(false); + deleteBtn->setEnabled(true); + setModified(); +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::deleteLevel() { + // Open for discussion: Should there be a message box to confirm the delete? + if (m_level >= m_lecture.m_lectureData.size()) return; // paranoia check + m_selecting = true; // prevent the selectionChanged() signal from interfering + // first remove the item from the list view + delete m_currentItem; + // then remove the level data + QValueVector<KTouchLevelData>::iterator it=m_lecture.m_lectureData.begin(); + std::advance(it, m_level); + m_lecture.m_lectureData.erase(it); + m_currentItem = levelListView->firstChild(); + for (unsigned int i=0; i<m_level; ++i) + m_currentItem = m_currentItem->nextSibling(); + levelListView->setSelected(m_currentItem, true); + showCurrentLevel(); + m_selecting = false; + if (m_lecture.m_lectureData.size()==1) + deleteBtn->setEnabled(false); + if (m_level==m_lecture.m_lectureData.size()-1) + downBtn->setEnabled(false); + if (m_level==0) + upBtn->setEnabled(false); + setModified(); +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::moveUp() { + if (m_level==0) return; + m_selecting=true; // again, I don't want to process changeSelection() signals now + storeCurrentLevel(); + QListViewItem *upperItem = m_currentItem->itemAbove(); + std::swap(m_lecture.m_lectureData[m_level], m_lecture.m_lectureData[m_level-1]); + upperItem->setText(0, m_lecture.m_lectureData[m_level-1].m_newChars); + m_currentItem->setText(0, m_lecture.m_lectureData[m_level].m_newChars); + m_currentItem=upperItem; + --m_level; + levelListView->setSelected(m_currentItem, true); + showCurrentLevel(); + m_selecting = false; + if (m_level==0) + upBtn->setEnabled(false); + downBtn->setEnabled(true); + setModified(); +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::moveDown() { + if (m_level>=m_lecture.m_lectureData.size()-1) return; + m_selecting=true; // again, I don't want to process changeSelection() signals now + storeCurrentLevel(); + QListViewItem *lowerItem = m_currentItem->itemBelow(); + std::swap(m_lecture.m_lectureData[m_level], m_lecture.m_lectureData[m_level+1]); + m_currentItem->setText(0, m_lecture.m_lectureData[m_level].m_newChars); + lowerItem->setText(0, m_lecture.m_lectureData[m_level+1].m_newChars); + m_currentItem=lowerItem; + ++m_level; + levelListView->setSelected(m_currentItem, true); + showCurrentLevel(); + m_selecting = false; + if (m_level==m_lecture.m_lectureData.size()-1) + downBtn->setEnabled(false); + upBtn->setEnabled(true); + setModified(); +} +// ----------------------------------------------------------------------------- + + + +// **************************** +// ***** Private functions **** +// **************************** + +void KTouchLectureEditor::transfer_to_dialog() { + bool current_modified_flag = m_modified; + // set the title and the filename of the lecture + titleEdit->setText(m_lecture.title()); + lectureCommentEdit->setText(m_lecture.m_comment); + if (m_currentURL.isEmpty()) setCaption(i18n("KTouch Lecture Editor - ") + i18n("<new unnamed lecture file>")); + else setCaption(i18n("KTouch Lecture Editor - ") + m_currentURL.fileName()); + // copy the 'new char' strings of the lectures into the list view + levelListView->clear(); + QValueVector<KTouchLevelData>::const_iterator it=m_lecture.m_lectureData.begin(); + // add first item + QListViewItem *item=new QListViewItem( levelListView, (it++)->m_newChars ); + // add all the others + for (;it!=m_lecture.m_lectureData.end(); ++it) + item = new QListViewItem( levelListView, item, it->m_newChars ); + m_currentItem=levelListView->firstChild(); + m_selecting = true; // prevent the selectionChanged() signal from interfering + levelListView->setSelected(m_currentItem, true); + m_selecting = false; + // open first lesson + m_level=0; + showCurrentLevel(); + // set up the buttons + upBtn->setEnabled(false); + if (m_lecture.m_lectureData.size()>1) { + downBtn->setEnabled(true); + deleteBtn->setEnabled(true); + } + else { + downBtn->setEnabled(false); + deleteBtn->setEnabled(false); + } + // finally the font + if (!m_lecture.m_fontSuggestions.isEmpty()) { + QFont f("Monospace"); + // TODO : multiple font suggestions + f.fromString(m_lecture.m_fontSuggestions); + linesTextEdit->setFont(f); + lectureCommentEdit->setFont(f); + levelCommentEdit->setFont(f); + newCharsEdit->setFont(f); + titleEdit->setFont(f); + levelListView->setFont(f); + } + setModified(current_modified_flag); +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::transfer_from_dialog() { + storeCurrentLevel(); + m_lecture.m_title = titleEdit->text(); + m_lecture.m_comment = lectureCommentEdit->text(); + setModified(); +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::showCurrentLevel() { + if (m_level >= m_lecture.m_lectureData.size()) return; // should not happen, but why running a risk here... + levelLabel->setText(i18n("Data of Level %1").arg(m_level+1) ); + levelCommentEdit->setText(m_lecture.m_lectureData[m_level].m_comment); + newCharsEdit->setText(m_lecture.m_lectureData[m_level].m_newChars); + QString text; + for (QValueVector<QString>::const_iterator it=m_lecture.m_lectureData[m_level].m_lines.begin(); + it!=m_lecture.m_lectureData[m_level].m_lines.end(); ++it) + { + text += *it + '\n'; + } + linesTextEdit->setText(text); +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::storeCurrentLevel() { + if (m_level>=m_lecture.m_lectureData.size()) return; // should not happen, but ... better check one time too much... + m_lecture.m_lectureData[m_level].m_comment = levelCommentEdit->text(); + m_lecture.m_lectureData[m_level].m_newChars = newCharsEdit->text(); + m_lecture.m_lectureData[m_level].m_lines.clear(); + QString text = linesTextEdit->text(); + QStringList lines; + QString currentLine; + for (unsigned int i=0; i<text.length(); ++i) { + QChar c = text[i]; + if (c=='\t') c=' '; // replace tabs with spaces + if (c=='\n') { + lines.append(currentLine); + currentLine = ""; + } + else + currentLine += c; + }; + lines.append(currentLine); + for (QStringList::const_iterator it=lines.begin(); it!=lines.end(); ++it) { + if ((*it).isEmpty()) continue; + m_lecture.m_lectureData[m_level].m_lines.push_back(*it); + } +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::createNewLevel() { + KTouchLevelData newLevel; + newLevel.m_newChars = i18n("abcdefghijklmnopqrstuvwxyz"); + newLevel.m_comment = QString(); + newLevel.m_lines.clear(); // remove the lines of the default mini level + newLevel.m_lines.push_back(i18n("Enter your lines here...")); + m_lecture.m_lectureData.push_back(newLevel); +} +// ----------------------------------------------------------------------------- + +int KTouchLectureEditor::openLectureFile(const KURL& url) { + // First setup the open request dialog + KTouchOpenRequest dlg(this); + // Call the dialog + KURL new_url; + int result = dlg.requestFileToOpen(new_url, + i18n("Open Lecture File"), + i18n("Which Lecture File Would You Like to Edit?"), + i18n("Edit current lecture:"), + i18n("Open a default lecture:"), + i18n("Open a lecture file:"), + i18n("Create new lecture"), + url, KTouchPtr->lectureFiles(), i18n("<no lecture files available>")); + + if (result == QDialog::Accepted) { + // Ok, user confirmed the dialog, now lets get the url + m_currentURL = new_url; + // Try to load the lecture, if that failes, we create a new lecture instead + m_lecture = KTouchLecture(); // empty the lecture + if (!m_currentURL.isEmpty()) { + // try to read old format first then XML format + if (!m_lecture.load(this, m_currentURL) && !m_lecture.loadXML(this, m_currentURL)) { + KMessageBox::sorry(this, i18n("Could not open the lecture file, creating a new one instead.")); + m_currentURL = QString::null; // new lectures haven't got a URL + } + } + // If we have no URL, we create a new lecture - can happen if either the user + // chose "new lecture" or the chosen lecture could not be opened + if (m_currentURL.isEmpty()) { + m_lecture.createDefault(); + m_modified = true; // new lectures are modified by default + } + else + m_modified = false; // newly read lectures are not modified in the begin + // Update our editor with the lecture data + transfer_to_dialog(); + return QDialog::Accepted; + } + else return QDialog::Rejected; +} +// ----------------------------------------------------------------------------- + +void KTouchLectureEditor::setModified(bool flag) { + m_modified = flag; + if (!m_currentURL.isEmpty()) { + if (flag) setCaption(i18n("KTouch Lecture Editor - ") + m_currentURL.fileName() + i18n(" (modified)")); + else setCaption(i18n("KTouch Lecture Editor - ") + m_currentURL.fileName()); + } +} +// ----------------------------------------------------------------------------- + +bool KTouchLectureEditor::saveModified() { + if (!m_modified) return true; + // ok, ask the user to save the changes + int result = KMessageBox::questionYesNoCancel(this, + i18n("The lecture has been changed. Do you want to save the changes?"),QString::null,KStdGuiItem::save(),KStdGuiItem::discard()); + if (result == KMessageBox::Cancel) return false; // User aborted + if (result == KMessageBox::Yes) saveBtnClicked(); + // if successfully saved the modified flag will be resetted in the saveBtnClicked() function + return true; // User acknowledged +} +// ----------------------------------------------------------------------------- |