/*************************************************************************** * 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 <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(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 (KFontDialog::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").tqarg(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 } // -----------------------------------------------------------------------------