1 /***************************************************************************
2 * ktouchlectureeditor.cpp *
3 * ----------------------- *
4 * Copyright (C) 2004 by Andreas Nicolai *
5 * ghorwin@users.sourceforge.net *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 ***************************************************************************/
16 #include <qstringlist.h>
18 #include <kpushbutton.h>
19 #include <klistview.h>
20 #include <klineedit.h>
21 #include <ktextedit.h>
24 #include <ksqueezedtextlabel.h>
25 #include <kmessagebox.h>
26 #include <kcombobox.h>
27 #include <kfontdialog.h>
28 #include <kfiledialog.h>
30 #include <algorithm> // for std::swap
32 #include "ktouchlectureeditor.h"
33 #include "ktouchlectureeditor.moc"
35 #include "ktouchlecture.h"
36 #include "ktouchopenrequest.h"
40 // **************************
41 // ***** Public functions ***
42 // **************************
44 KTouchLectureEditor::KTouchLectureEditor(QWidget
*parent
, const char* name
, bool modal
, WFlags fl
)
45 : KTouchEditorDlg(parent
, name
, modal
, fl
)
47 levelListView
->setSorting(-1); // don't sort my level list view!
49 connect(levelListView
, SIGNAL(selectionChanged(QListViewItem
*)),this, SLOT(newSelection(QListViewItem
*)) );
50 connect(newCharsEdit
, SIGNAL(textChanged(const QString
&)), this, SLOT(newCharsChanged(const QString
&)) );
51 connect(newBtn
, SIGNAL(clicked()), this, SLOT(newLevel()) );
52 connect(deleteBtn
, SIGNAL(clicked()), this, SLOT(deleteLevel()) );
53 connect(upBtn
, SIGNAL(clicked()), this, SLOT(moveUp()) );
54 connect(downBtn
, SIGNAL(clicked()), this, SLOT(moveDown()) );
56 // make the connections for making the lecture modified
57 connect(titleEdit
, SIGNAL(textChanged(const QString
&)), this, SLOT(setModified()) );
58 connect(lectureCommentEdit
, SIGNAL(textChanged()), this, SLOT(setModified()) );
59 connect(levelCommentEdit
, SIGNAL(textChanged(const QString
&)), this, SLOT(setModified()) );
60 connect(linesTextEdit
, SIGNAL(textChanged()), this, SLOT(setModified()) );
62 // The font, open, save, saveas and close buttons are already connected
64 // -----------------------------------------------------------------------------
66 bool KTouchLectureEditor::startEditor(const KURL
& url
) {
67 // call open request dialog and load a lecture, and start the dialogs event loop if
68 // the user did not cancel the open request dialog
69 if (openLectureFile(url
)==QDialog::Accepted
) {
75 // -----------------------------------------------------------------------------
78 // *************************
79 // ***** Private slots *****
80 // *************************
82 void KTouchLectureEditor::fontBtnClicked() {
84 if (KFontDialog::getFont(f
, false, this, true)==QDialog::Accepted
) {
85 linesTextEdit
->setFont(f
);
86 lectureCommentEdit
->setFont(f
);
87 levelCommentEdit
->setFont(f
);
88 newCharsEdit
->setFont(f
);
89 titleEdit
->setFont(f
);
90 levelListView
->setFont(f
);
91 m_lecture
.m_fontSuggestions
= f
.toString();
95 // -----------------------------------------------------------------------------
97 void KTouchLectureEditor::openBtnClicked() {
98 saveModified(); // save if modified
101 // -----------------------------------------------------------------------------
103 void KTouchLectureEditor::saveBtnClicked() {
104 if (m_currentURL
.isEmpty()) saveAsBtnClicked();
106 transfer_from_dialog();
107 m_lecture
.saveXML(this, m_currentURL
);
111 // -----------------------------------------------------------------------------
113 void KTouchLectureEditor::saveAsBtnClicked() {
114 QString tmp
= KFileDialog::getSaveFileName(QString::null
,
115 "*.ktouch.xml|KTouch Lecture Files\n*.*|All Files", this, i18n("Save Training Lecture") );
116 if (!tmp
.isEmpty()) {
117 transfer_from_dialog();
119 m_lecture
.saveXML(this, m_currentURL
);
120 setCaption(m_currentURL
.url());
124 // -----------------------------------------------------------------------------
126 void KTouchLectureEditor::newSelection(QListViewItem
* item
) {
127 if (m_selecting
) return;
128 bool current_modified_flag
= m_modified
; // remember our current status
129 // first store the current level data
131 // now we need to find the level which has been selected
132 QListViewItem
*i
= levelListView
->firstChild();
133 unsigned int level
=0;
134 while (i
!=0 && i
!=item
) {
135 i
= i
->nextSibling();
143 m_selecting
= true; // prevent the selectionChanged() signal from interfering
144 levelListView
->setSelected(m_currentItem
, true);
147 if (m_lecture
.m_lectureData
.size()==1) {
148 downBtn
->setEnabled(false);
149 upBtn
->setEnabled(false);
152 if (m_level
==m_lecture
.m_lectureData
.size()-1) downBtn
->setEnabled(false);
153 else downBtn
->setEnabled(true);
154 if (m_level
==0) upBtn
->setEnabled(false);
155 else upBtn
->setEnabled(true);
157 setModified(current_modified_flag
);
159 // -----------------------------------------------------------------------------
161 void KTouchLectureEditor::newCharsChanged(const QString
& text
) {
162 if (m_currentItem
==0) return; // shouldn't happen, but a little bit of paranoia...
163 m_currentItem
->setText(0, text
);
166 // -----------------------------------------------------------------------------
168 void KTouchLectureEditor::newLevel() {
170 QListViewItem
*newItem
= new QListViewItem( levelListView
,
171 levelListView
->lastItem(), m_lecture
.m_lectureData
.back().m_newChars
);
172 newSelection(newItem
);
173 upBtn
->setEnabled(true);
174 downBtn
->setEnabled(false);
175 deleteBtn
->setEnabled(true);
178 // -----------------------------------------------------------------------------
180 void KTouchLectureEditor::deleteLevel() {
181 // Open for discussion: Should there be a message box to confirm the delete?
182 if (m_level
>= m_lecture
.m_lectureData
.size()) return; // paranoia check
183 m_selecting
= true; // prevent the selectionChanged() signal from interfering
184 // first remove the item from the list view
185 delete m_currentItem
;
186 // then remove the level data
187 QValueVector
<KTouchLevelData
>::iterator it
=m_lecture
.m_lectureData
.begin();
188 std::advance(it
, m_level
);
189 m_lecture
.m_lectureData
.erase(it
);
190 m_currentItem
= levelListView
->firstChild();
191 for (unsigned int i
=0; i
<m_level
; ++i
)
192 m_currentItem
= m_currentItem
->nextSibling();
193 levelListView
->setSelected(m_currentItem
, true);
196 if (m_lecture
.m_lectureData
.size()==1)
197 deleteBtn
->setEnabled(false);
198 if (m_level
==m_lecture
.m_lectureData
.size()-1)
199 downBtn
->setEnabled(false);
201 upBtn
->setEnabled(false);
204 // -----------------------------------------------------------------------------
206 void KTouchLectureEditor::moveUp() {
207 if (m_level
==0) return;
208 m_selecting
=true; // again, I don't want to process changeSelection() signals now
210 QListViewItem
*upperItem
= m_currentItem
->itemAbove();
211 std::swap(m_lecture
.m_lectureData
[m_level
], m_lecture
.m_lectureData
[m_level
-1]);
212 upperItem
->setText(0, m_lecture
.m_lectureData
[m_level
-1].m_newChars
);
213 m_currentItem
->setText(0, m_lecture
.m_lectureData
[m_level
].m_newChars
);
214 m_currentItem
=upperItem
;
216 levelListView
->setSelected(m_currentItem
, true);
220 upBtn
->setEnabled(false);
221 downBtn
->setEnabled(true);
224 // -----------------------------------------------------------------------------
226 void KTouchLectureEditor::moveDown() {
227 if (m_level
>=m_lecture
.m_lectureData
.size()-1) return;
228 m_selecting
=true; // again, I don't want to process changeSelection() signals now
230 QListViewItem
*lowerItem
= m_currentItem
->itemBelow();
231 std::swap(m_lecture
.m_lectureData
[m_level
], m_lecture
.m_lectureData
[m_level
+1]);
232 m_currentItem
->setText(0, m_lecture
.m_lectureData
[m_level
].m_newChars
);
233 lowerItem
->setText(0, m_lecture
.m_lectureData
[m_level
+1].m_newChars
);
234 m_currentItem
=lowerItem
;
236 levelListView
->setSelected(m_currentItem
, true);
239 if (m_level
==m_lecture
.m_lectureData
.size()-1)
240 downBtn
->setEnabled(false);
241 upBtn
->setEnabled(true);
244 // -----------------------------------------------------------------------------
248 // ****************************
249 // ***** Private functions ****
250 // ****************************
252 void KTouchLectureEditor::transfer_to_dialog() {
253 bool current_modified_flag
= m_modified
;
254 // set the title and the filename of the lecture
255 titleEdit
->setText(m_lecture
.title());
256 lectureCommentEdit
->setText(m_lecture
.m_comment
);
257 if (m_currentURL
.isEmpty()) setCaption(i18n("KTouch Lecture Editor - ") + i18n("<new unnamed lecture file>"));
258 else setCaption(i18n("KTouch Lecture Editor - ") + m_currentURL
.fileName());
259 // copy the 'new char' strings of the lectures into the list view
260 levelListView
->clear();
261 QValueVector
<KTouchLevelData
>::const_iterator it
=m_lecture
.m_lectureData
.begin();
263 QListViewItem
*item
=new QListViewItem( levelListView
, (it
++)->m_newChars
);
264 // add all the others
265 for (;it
!=m_lecture
.m_lectureData
.end(); ++it
)
266 item
= new QListViewItem( levelListView
, item
, it
->m_newChars
);
267 m_currentItem
=levelListView
->firstChild();
268 m_selecting
= true; // prevent the selectionChanged() signal from interfering
269 levelListView
->setSelected(m_currentItem
, true);
274 // set up the buttons
275 upBtn
->setEnabled(false);
276 if (m_lecture
.m_lectureData
.size()>1) {
277 downBtn
->setEnabled(true);
278 deleteBtn
->setEnabled(true);
281 downBtn
->setEnabled(false);
282 deleteBtn
->setEnabled(false);
285 if (!m_lecture
.m_fontSuggestions
.isEmpty()) {
287 // TODO : multiple font suggestions
288 f
.fromString(m_lecture
.m_fontSuggestions
);
289 linesTextEdit
->setFont(f
);
290 lectureCommentEdit
->setFont(f
);
291 levelCommentEdit
->setFont(f
);
292 newCharsEdit
->setFont(f
);
293 titleEdit
->setFont(f
);
294 levelListView
->setFont(f
);
296 setModified(current_modified_flag
);
298 // -----------------------------------------------------------------------------
300 void KTouchLectureEditor::transfer_from_dialog() {
302 m_lecture
.m_title
= titleEdit
->text();
303 m_lecture
.m_comment
= lectureCommentEdit
->text();
306 // -----------------------------------------------------------------------------
308 void KTouchLectureEditor::showCurrentLevel() {
309 if (m_level
>= m_lecture
.m_lectureData
.size()) return; // should not happen, but why running a risk here...
310 levelLabel
->setText(i18n("Data of Level %1").arg(m_level
+1) );
311 levelCommentEdit
->setText(m_lecture
.m_lectureData
[m_level
].m_comment
);
312 newCharsEdit
->setText(m_lecture
.m_lectureData
[m_level
].m_newChars
);
314 for (QValueVector
<QString
>::const_iterator it
=m_lecture
.m_lectureData
[m_level
].m_lines
.begin();
315 it
!=m_lecture
.m_lectureData
[m_level
].m_lines
.end(); ++it
)
319 linesTextEdit
->setText(text
);
321 // -----------------------------------------------------------------------------
323 void KTouchLectureEditor::storeCurrentLevel() {
324 if (m_level
>=m_lecture
.m_lectureData
.size()) return; // should not happen, but ... better check one time too much...
325 m_lecture
.m_lectureData
[m_level
].m_comment
= levelCommentEdit
->text();
326 m_lecture
.m_lectureData
[m_level
].m_newChars
= newCharsEdit
->text();
327 m_lecture
.m_lectureData
[m_level
].m_lines
.clear();
328 QString text
= linesTextEdit
->text();
331 for (unsigned int i
=0; i
<text
.length(); ++i
) {
333 if (c
=='\t') c
=' '; // replace tabs with spaces
335 lines
.append(currentLine
);
341 lines
.append(currentLine
);
342 for (QStringList::const_iterator it
=lines
.begin(); it
!=lines
.end(); ++it
) {
343 if ((*it
).isEmpty()) continue;
344 m_lecture
.m_lectureData
[m_level
].m_lines
.push_back(*it
);
347 // -----------------------------------------------------------------------------
349 void KTouchLectureEditor::createNewLevel() {
350 KTouchLevelData newLevel
;
351 newLevel
.m_newChars
= i18n("abcdefghijklmnopqrstuvwxyz");
352 newLevel
.m_comment
= QString();
353 newLevel
.m_lines
.clear(); // remove the lines of the default mini level
354 newLevel
.m_lines
.push_back(i18n("Enter your lines here..."));
355 m_lecture
.m_lectureData
.push_back(newLevel
);
357 // -----------------------------------------------------------------------------
359 int KTouchLectureEditor::openLectureFile(const KURL
& url
) {
360 // First setup the open request dialog
361 KTouchOpenRequest
dlg(this);
364 int result
= dlg
.requestFileToOpen(new_url
,
365 i18n("Open Lecture File"),
366 i18n("Which Lecture File Would You Like to Edit?"),
367 i18n("Edit current lecture:"),
368 i18n("Open a default lecture:"),
369 i18n("Open a lecture file:"),
370 i18n("Create new lecture"),
371 url
, KTouchPtr
->lectureFiles(), i18n("<no lecture files available>"));
373 if (result
== QDialog::Accepted
) {
374 // Ok, user confirmed the dialog, now lets get the url
375 m_currentURL
= new_url
;
376 // Try to load the lecture, if that failes, we create a new lecture instead
377 m_lecture
= KTouchLecture(); // empty the lecture
378 if (!m_currentURL
.isEmpty()) {
379 // try to read old format first then XML format
380 if (!m_lecture
.load(this, m_currentURL
) && !m_lecture
.loadXML(this, m_currentURL
)) {
381 KMessageBox::sorry(this, i18n("Could not open the lecture file, creating a new one instead."));
382 m_currentURL
= QString::null
; // new lectures haven't got a URL
385 // If we have no URL, we create a new lecture - can happen if either the user
386 // chose "new lecture" or the chosen lecture could not be opened
387 if (m_currentURL
.isEmpty()) {
388 m_lecture
.createDefault();
389 m_modified
= true; // new lectures are modified by default
392 m_modified
= false; // newly read lectures are not modified in the begin
393 // Update our editor with the lecture data
394 transfer_to_dialog();
395 return QDialog::Accepted
;
397 else return QDialog::Rejected
;
399 // -----------------------------------------------------------------------------
401 void KTouchLectureEditor::setModified(bool flag
) {
403 if (!m_currentURL
.isEmpty()) {
404 if (flag
) setCaption(i18n("KTouch Lecture Editor - ") + m_currentURL
.fileName() + i18n(" (modified)"));
405 else setCaption(i18n("KTouch Lecture Editor - ") + m_currentURL
.fileName());
408 // -----------------------------------------------------------------------------
410 bool KTouchLectureEditor::saveModified() {
411 if (!m_modified
) return true;
412 // ok, ask the user to save the changes
413 int result
= KMessageBox::questionYesNoCancel(this,
414 i18n("The lecture has been changed. Do you want to save the changes?"));
415 if (result
== KMessageBox::Cancel
) return false; // User aborted
416 if (result
== KMessageBox::Yes
) saveBtnClicked();
417 // if successfully saved the modified flag will be resetted in the saveBtnClicked() function
418 return true; // User acknowledged
420 // -----------------------------------------------------------------------------