You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeedu/ktouch/src/ktouchlectureeditor.cpp

421 lines
17 KiB

/***************************************************************************
* 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 <tqlabel.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <kpushbutton.h>
#include <tdelistview.h>
#include <klineedit.h>
#include <ktextedit.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <ksqueezedtextlabel.h>
#include <tdemessagebox.h>
#include <kcombobox.h>
#include <tdefontdialog.h>
#include <tdefiledialog.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(TQWidget *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, TQT_SIGNAL(selectionChanged(TQListViewItem*)),this, TQT_SLOT(newSelection(TQListViewItem*)) );
connect(newCharsEdit, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(newCharsChanged(const TQString&)) );
connect(newBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(newLevel()) );
connect(deleteBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(deleteLevel()) );
connect(upBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(moveUp()) );
connect(downBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(moveDown()) );
// make the connections for making the lecture modified
connect(titleEdit, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(setModified()) );
connect(lectureCommentEdit, TQT_SIGNAL(textChanged()), this, TQT_SLOT(setModified()) );
connect(levelCommentEdit, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(setModified()) );
connect(linesTextEdit, TQT_SIGNAL(textChanged()), this, TQT_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)==TQDialog::Accepted) {
exec();
return true;
}
else return false;
}
// -----------------------------------------------------------------------------
// *************************
// ***** Private slots *****
// *************************
void KTouchLectureEditor::fontBtnClicked() {
TQFont f(m_lecture.m_fontSuggestions);
if (TDEFontDialog::getFont(f, false, this, true)==TQDialog::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() {
TQString tmp = KFileDialog::getSaveFileName(TQString(),
"*.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(TQListViewItem* 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
TQListViewItem *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 TQString& 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();
TQListViewItem *newItem = new TQListViewItem( 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
TQValueVector<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();
TQListViewItem *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();
TQListViewItem *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();
TQValueVector<KTouchLevelData>::const_iterator it=m_lecture.m_lectureData.begin();
// add first item
TQListViewItem *item=new TQListViewItem( levelListView, (it++)->m_newChars );
// add all the others
for (;it!=m_lecture.m_lectureData.end(); ++it)
item = new TQListViewItem( 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()) {
TQFont 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);
TQString text;
for (TQValueVector<TQString>::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();
TQString text = linesTextEdit->text();
TQStringList lines;
TQString currentLine;
for (unsigned int i=0; i<text.length(); ++i) {
TQChar 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 (TQStringList::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 = TQString();
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 == TQDialog::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 = TQString(); // 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 TQDialog::Accepted;
}
else return TQDialog::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?"),TQString(),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
}
// -----------------------------------------------------------------------------