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/kvoctrain/kvoctrain/kva_io.cpp

698 lines
20 KiB

/***************************************************************************
i/o part of kvoctrain
-----------------------------------------------------------------------
begin : Thu Mar 11 20:50:53 MET 1999
copyright : (C) 1999-2001 Ewald Arnold <kvoctrain@ewald-arnold.de>
(C) 2001 The KDE-EDU team
(C) 2004-2005 Peter Hedlund <peter.hedlund@kdemail.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 <unistd.h>
#include <tqtimer.h>
#include <tdefiledialog.h>
#include <kcombobox.h>
#include <kprogress.h>
#include <tderecentdocument.h>
#include <kstatusbar.h>
#include <tdelocale.h>
#include <kstandarddirs.h>
#include <kdebug.h>
#include <tdenewstuff/downloaddialog.h>
#include "kvoctrain.h"
#include "UsageManager.h"
#include "common-dialogs/ProgressDlg.h"
#include <prefs.h>
static const char *PATTERN_ALL = I18N_NOOP("*|All Files (*)\n");
static const char *PATTERN_ML = I18N_NOOP("*.kvtml|KVocTrain Markup (*.kvtml)\n");
static const char *PATTERN_LEX = I18N_NOOP("*.lex|Vocabulary Trainer 5.0 (*.lex)\n");
static const char *PATTERN_VL = I18N_NOOP("*.vl|KVoclearn (*.vl)\n");
static const char *PATTERN_TQVO = I18N_NOOP("*.qvo|TQVocab (*.qvo)\n");
static const char *PATTERN_VOC = I18N_NOOP("*.voc|Vokabeltrainer (*.voc)\n");
static const char *PATTERN_CSV = I18N_NOOP("*.csv|Text (*.csv)\n");
static const char *PATTERN_VCB = I18N_NOOP("*.vocab|Vocabbox (*.vocab)\n");
// we can read these
#define FILTER_RPATTERN i18n(PATTERN_ML)+i18n(PATTERN_VCB)+i18n(PATTERN_VOC)+i18n(PATTERN_CSV)+i18n(PATTERN_LEX)+i18n(PATTERN_ALL)
// we can write these
#define FILTER_WPATTERN i18n(PATTERN_ML)+i18n(PATTERN_VCB)+i18n(PATTERN_CSV)+i18n(PATTERN_LEX)+i18n(PATTERN_ALL)
void kvoctrainApp::slotTimeOutBackup()
{
if (Prefs::autoBackup() && doc && doc->isModified() ) {
slotStatusMsg(i18n("Autobackup in progress"));
slotFileSave();
}
if (Prefs::backupTime() > 0)
btimer->start(Prefs::backupTime() * 60 * 1000, TRUE);
slotStatusMsg(IDS_DEFAULT);
}
bool kvoctrainApp::queryClose()
{
bool erg = queryExit();
if (erg)
doc->setModified(false); // avoid double query on exit via system menu
return erg;
}
bool kvoctrainApp::queryExit()
{
saveOptions();
if (!doc || !doc->isModified() ) return true;
bool save = (Prefs::autoSave()); //save without asking
if (!save)
{
int exit = KMessageBox::warningYesNoCancel(this,
i18n("Vocabulary is modified.\n\nSave file before exit?\n"),
kapp->makeStdCaption(""),
KStdGuiItem::save(), KStdGuiItem::discard());
if (exit==KMessageBox::Yes) {
save = true; // save and exit
}
else if (exit == KMessageBox::No) {
save = false; // dont save but exit
}
else {
return false; // continue work
}
}
if (save) {
if (!doc->URL().isEmpty())
slotFileSave(); // save and exit
if (doc->isModified())
{
// Error while saving or no name
slotFileSaveAs();
}
}
return true;
}
void kvoctrainApp::slotFileQuit()
{
///////////////////////////////////////////////////////////////////
// exits the Application
if(queryExit())
{
doc->setModified(false); // Make sure not to bother about saving again.
kapp->quit();
}
else
slotStatusMsg(IDS_DEFAULT);
}
void kvoctrainApp::slotProgress(kvoctrainDoc *curr_doc, int percent)
{
if (pdlg != 0)
pdlg->setValue (curr_doc, percent);
else if (pbar != 0)
pbar->setValue (percent);
kapp->processEvents();
}
void kvoctrainApp::slotFileOpenRecent(const KURL& url)
{
slotStatusMsg(i18n("Opening file..."));
if (queryExit() && fileOpenRecent->items().count() > 0)
{
fileOpenRecent->setCurrentItem(-1);
loadfileFromPath(url);
}
slotStatusMsg(IDS_DEFAULT);
}
void kvoctrainApp::slotFileNew()
{
slotStatusMsg(i18n("Creating new file..."));
if (queryExit() ) {
view->setView (0, langset);
delete doc;
TQString name = "";
doc = new kvoctrainDoc (TQT_TQOBJECT(this), 0 /*KURL(name)*/);
loadDocProps(doc);
if (doc->numLangs() == 0) {
TQString l = "en";
doc->appendLang(l);
}
view->setView(doc, langset);
view->getTable()->setFont(Prefs::tableFont());
view->adjustContent();
connect (doc, TQT_SIGNAL (docModified(bool)), this, TQT_SLOT(slotModifiedDoc(bool)));
doc->setModified(false);
}
slotStatusMsg(IDS_DEFAULT);
}
void kvoctrainApp::slotFileOpen()
{
slotStatusMsg(i18n("Opening file..."));
if (queryExit() ) {
TQString s;
KURL url = KFileDialog::getOpenURL(TQString(), FILTER_RPATTERN, parentWidget(), i18n("Open Vocabulary File"));
loadfileFromPath(url, true);
}
slotStatusMsg(IDS_DEFAULT);
}
void kvoctrainApp::loadfileFromPath(const KURL & url, bool addRecent)
{
if (!url.path().isEmpty())
{
view->setView(0, langset);
delete doc;
doc = 0;
TQString format = i18n("Loading %1");
TQString msg = format.arg(url.path());
slotStatusMsg(msg);
prepareProgressBar();
doc = new kvoctrainDoc (TQT_TQOBJECT(this), url);
removeProgressBar();
loadDocProps(doc);
view->setView(doc, langset);
view->getTable()->setFont(Prefs::tableFont());
view->adjustContent();
if (addRecent)
fileOpenRecent->addURL(url) /*addRecentFile (url.path())*/;
connect (doc, TQT_SIGNAL (docModified(bool)), this, TQT_SLOT(slotModifiedDoc(bool)));
doc->setModified(false);
}
}
void kvoctrainApp::slotFileOpenExample()
{
slotStatusMsg(i18n("Opening example file..."));
if (queryExit() ) {
TQString s;
s = locate("data", "kvoctrain/examples/");
KURL url = KFileDialog::getOpenURL(s, FILTER_RPATTERN, parentWidget(), i18n("Open Example Vocabulary File"));
loadfileFromPath(url, false);
if (doc)
doc->URL().setFileName(TQString());
}
slotStatusMsg(IDS_DEFAULT);
}
void kvoctrainApp::slotGHNS()
{
if (!m_newStuff)
m_newStuff = new KVTNewStuff(this);
m_newStuff->download();
}
void kvoctrainApp::slotFileMerge()
{
slotStatusMsg(i18n("Merging file..."));
TQString s;
KURL url = KFileDialog::getOpenURL(TQString(), FILTER_RPATTERN, parentWidget(), i18n("Merge Vocabulary File"));
if (!url.isEmpty() ) {
TQString format = i18n("Loading %1");
TQString msg = format.arg(url.path());
slotStatusMsg(msg);
prepareProgressBar();
kvoctrainDoc *new_doc = new kvoctrainDoc (TQT_TQOBJECT(this), url);
connect (new_doc, TQT_SIGNAL (docModified(bool)), this, TQT_SLOT(slotModifiedDoc(bool)));
doc->setModified(false);
removeProgressBar();
vector<TQString> old_names = doc->getLessonDescr();
vector<TQString> new_names = new_doc->getLessonDescr();
vector<TQString> old_types = doc->getTypeDescr();
vector<TQString> new_types = new_doc->getTypeDescr();
vector<TQString> old_tenses = doc->getTenseDescr();
vector<TQString> new_tenses = new_doc->getTenseDescr();
vector<int> old_in_query = doc->getLessonsInQuery();
vector<int> new_in_query = new_doc->getLessonsInQuery();
vector<TQString> old_usages = doc->getUsageDescr();
vector<TQString> new_usages = new_doc->getUsageDescr();
format = i18n("Merging %1");
msg = format.arg(url.path());
slotStatusMsg(msg);
TQApplication::setOverrideCursor( waitCursor );
int lesson_offset = lessons->count()-1;
for (int i = 0; i < (int) new_names.size(); i++) {
lessons->insertItem (new_names[i]);
old_names.push_back(new_names[i]);
}
doc->setLessonDescr(old_names);
for (int i = 0; i < (int) new_in_query.size(); i++)
old_in_query.push_back(new_in_query[i]+lesson_offset);
doc->setLessonsInQuery(old_in_query);
querymanager.setLessonItems(old_in_query);
int types_offset = old_types.size();
for (int i = 0; i < (int) new_types.size(); i++) {
old_types.push_back(new_types[i]);
}
doc->setTypeDescr(old_types);
QueryManager::setTypeNames(old_types);
int tenses_offset = old_tenses.size();
for (int i = 0; i < (int) new_tenses.size(); i++) {
old_tenses.push_back(new_tenses[i]);
}
doc->setTenseDescr(old_tenses);
Conjugation::setTenseNames(old_tenses);
int usages_offset = old_usages.size();
for (int i = 0; i < (int) new_usages.size(); i++) {
old_usages.push_back(new_usages[i]);
}
doc->setUsageDescr(old_usages);
UsageManager::setUsageNames(old_usages);
bool equal = true;
if (doc->getOriginalIdent() != new_doc->getOriginalIdent())
equal = false;
for (int i = 1; i < doc->numLangs(); i++)
if (doc->getIdent(i) != new_doc->getIdent(i))
equal = false;
if (equal) { // easy way: same language codes, just append
for (int i = 0; i < new_doc->numEntries(); i++) {
kvoctrainExpr *expr = new_doc->getEntry(i);
expr->setLesson(expr->getLesson()+lesson_offset);
for (int lang = 0; lang <= (int) expr->numTranslations(); lang++) {
TQString t = expr->getType (lang);
// adjust type offset
if (!t.isEmpty() && t.left(1) == TQM_USER_TYPE) {
TQString t2;
t.remove (0, 1);
t2.setNum (t.toInt()+types_offset);
t2.insert (0, TQM_USER_TYPE);
expr->setType (lang, t2);
}
t = expr->getUsageLabel (lang);
// adjust usage offset
TQString tg;
if (!t.isEmpty() ) {
TQString t2;
while (t.left(strlen(UL_USER_USAGE)) == UL_USER_USAGE) {
TQString n;
t.remove (0, 1);
int next;
if ((next = t.find(UL_USAGE_DIV)) >= 0) {
n = t.left(next);
t.remove (0, next+1);
}
else {
n = t;
t = "";
}
t2.setNum (n.toInt()+usages_offset);
t2.insert (0, UL_USER_USAGE);
if (tg.length() == 0)
tg = t2;
else
tg += UL_USAGE_DIV + t2;
}
if (tg.length() == 0)
tg = t;
else if (t.length() != 0)
tg += UL_USAGE_DIV + t;
expr->setUsageLabel (lang, tg);
}
Conjugation conj = expr->getConjugation(lang);
bool condirty = false;
for (int ci = 0; ci < conj.numEntries(); ci++) {
t = conj.getType(ci);
if (!t.isEmpty() && t.left(1) == UL_USER_TENSE) {
t.remove (0, strlen(UL_USER_TENSE));
TQString t2;
t2.setNum (t.toInt()+tenses_offset);
t2.insert (0, UL_USER_TENSE);
conj.setType(ci, t2);
condirty = true;
}
if (condirty)
expr->setConjugation(lang, conj);
}
}
doc->appendEntry (expr);
}
doc->setModified();
}
else { // hard way: move entries around, most attributes get lost
vector<int> move_matrix;
vector <bool> cs_equal;
for (int i = 0; i < TQMAX (doc->numLangs(), new_doc->numLangs()); i++)
cs_equal.push_back (false);
move_matrix.push_back(new_doc->findIdent(doc->getOriginalIdent()));
for (int i = 1; i < doc->numLangs(); i++)
move_matrix.push_back(new_doc->findIdent(doc->getIdent(i)));
for (int j = 0; j < new_doc->numEntries(); j++) {
kvoctrainExpr new_expr;
kvoctrainExpr *expr = new_doc->getEntry(j);
new_expr.setLesson(expr->getLesson()+lesson_offset);
for (int i = 0; i < (int) move_matrix.size(); i++) {
int lpos = move_matrix[i];
if (lpos >= 0) {
if (lpos == 0)
s = expr->getOriginal();
else
s = expr->getTranslation(lpos);
if (!cs_equal[lpos]) {
cs_equal[lpos] = true;
TQString id = lpos == 0 ? doc->getOriginalIdent()
: doc->getIdent(lpos);
}
if (i == 0)
new_expr.setOriginal(s);
else
new_expr.setTranslation(i, s);
TQString r = expr->getRemark(lpos);
new_expr.setRemark (i, r);
TQString t = expr->getType(lpos);
if (!t.isEmpty() && t.left(1) == TQM_USER_TYPE) {
TQString t2;
t.remove (0, 1);
t2.setNum (t.toInt()+types_offset);
t2.insert (0, TQM_USER_TYPE);
new_expr.setType (i, t2);
}
t = expr->getUsageLabel(lpos);
if (!t.isEmpty() && t.left(1) == TQM_USER_TYPE) {
TQString t2;
t.remove (0, 1);
t2.setNum (t.toInt()+usages_offset);
t2.insert (0, TQM_USER_TYPE);
new_expr.setUsageLabel (i, t2);
}
Conjugation conj = expr->getConjugation(lpos);
for (int ci = 0; ci < conj.numEntries(); ci++) {
t = conj.getType(ci);
if (!t.isEmpty() && t.left(1) == TQM_USER_TYPE) {
t.remove (0, strlen(TQM_USER_TYPE));
TQString t2;
t2.setNum (t.toInt()+tenses_offset);
t2.insert (0, TQM_USER_TYPE);
conj.setType(ci, t2);
}
}
}
}
// only append if entries are used
bool used = !new_expr.getOriginal().isEmpty();
for (int i = 1; i < (int) doc->numLangs(); i++)
if (!new_expr.getTranslation(i).isEmpty())
used = true;
if (used) {
doc->appendEntry(&new_expr);
doc->setModified();
}
}
}
delete (new_doc);
fileOpenRecent->addURL(url); // addRecentFile (url.path());
}
view->setView(doc, langset);
view->getTable()->setFont(Prefs::tableFont());
view->adjustContent();
TQApplication::restoreOverrideCursor();
slotStatusMsg(IDS_DEFAULT);
}
void kvoctrainApp::slotFileSave()
{
if (entryDlg != 0)
commitEntryDlg(false);
if (doc->URL().fileName() == i18n("Untitled") ) {
slotFileSaveAs();
return;
}
TQString format = i18n("Saving %1");
TQString msg = format.arg(doc->URL().path());
slotStatusMsg(msg);
// remove previous backup
TQFile::remove(TQFile::encodeName(doc->URL().path()+"~"));
::rename (TQFile::encodeName(doc->URL().path()),
TQFile::encodeName(doc->URL().path()+"~"));
prepareProgressBar();
saveDocProps(doc);
doc->saveAs(TQT_TQOBJECT(this), doc->URL(), doc->getTitle(), kvoctrainDoc::automatic);
fileOpenRecent->addURL(doc->URL());
removeProgressBar();
slotStatusMsg(IDS_DEFAULT);
}
void kvoctrainApp::fillLessonBox(kvoctrainDoc *the_doc)
{
lessons->clear();
lessons->insertItem (the_doc->getLessonDescr(0));
vector<TQString> names = the_doc->getLessonDescr();
for (int i = 0; i < (int) names.size(); i++)
lessons->insertItem (names[i]);
act_lesson = the_doc->getCurrentLesson();
if (act_lesson > lessons->count() ) {
act_lesson = 0;
the_doc->setCurrentLesson(act_lesson);
}
lessons->setCurrentItem (act_lesson);
}
void kvoctrainApp::loadDocProps(kvoctrainDoc *the_doc)
{
fillLessonBox(the_doc);
random_expr1.clear();
random_expr2.clear();
queryList.clear();
the_doc->getQueryLang (act_query_org, act_query_trans);
if (!act_query_org.isEmpty() && !act_query_trans.isEmpty() ) {
for (int i = 0; i < the_doc->numEntries(); i++)
{
kvoctrainExpr *entry = the_doc->getEntry(i);
if (entry->isInQuery())
{
int less = entry->getLesson();
for (int l = (int) queryList.size(); l <= less; l++) {
vector<QueryEntryRef> ref_vec;
queryList.push_back(ref_vec);
}
QueryEntryRef ref(entry, i);
queryList[less].push_back(ref);
}
}
}
QueryManager::setTypeNames (doc->getTypeDescr() );
UsageManager::setUsageNames (doc->getUsageDescr() );
Conjugation::setTenseNames (doc->getTenseDescr() );
querymanager.setLessonItems(doc->getLessonsInQuery() );
// remove empty elements
for (int i = (int) queryList.size()-1; i >= 0; i--)
if (queryList[i].size() == 0) {
queryList.erase(queryList.begin() + i);
}
query_cycle = 1;
query_startnum = 0;
for (int i = 0; i < (int) queryList.size(); i++)
query_startnum += queryList[i].size();
query_num = query_startnum;
}
void kvoctrainApp::saveDocProps(kvoctrainDoc *the_doc)
{
the_doc->setQueryLang (act_query_org, act_query_trans);
}
void kvoctrainApp::slotFileSaveAs()
{
slotStatusMsg(i18n("Saving file under new filename..."));
if (entryDlg != 0)
commitEntryDlg(false);
KURL url = KFileDialog::getSaveURL(TQString(), FILTER_WPATTERN, parentWidget(), i18n("Save Vocabulary As"));
if (!url.isEmpty() ) {
TQFileInfo fileinfo(url.path());
if (fileinfo.exists() && KMessageBox::warningContinueCancel(0,
i18n("<qt>The file<br><b>%1</b><br>already exists. Do you want to overwrite it?</qt>")
.arg(url.path()),TQString(),i18n("Overwrite")) == KMessageBox::Cancel)
{
// do nothing
}
else
if (doc) {
TQString format = i18n("Saving %1");
TQString msg = format.arg(url.path());
slotStatusMsg(msg);
TQFile::remove(TQFile::encodeName(url.path()+"~")); // remove previous backup
::rename (TQFile::encodeName(url.path()), TQFile::encodeName(TQString(url.path()+"~")));
saveDocProps(doc);
prepareProgressBar();
doc->saveAs(TQT_TQOBJECT(this), url, doc->getTitle(), kvoctrainDoc::automatic);
fileOpenRecent->addURL(doc->URL());
removeProgressBar();
}
}
slotStatusMsg(IDS_DEFAULT);
}
void kvoctrainApp::slotSaveSelection ()
{
if (entryDlg != 0)
commitEntryDlg(false);
slotStatusMsg(i18n("Saving selected area under new filename..."));
TQString save_separator = Prefs::separator();
Prefs::setSeparator("\t");
kvoctrainDoc seldoc(TQT_TQOBJECT(this), "");
// transfer most important parts
seldoc.appendLang(doc->getOriginalIdent());
for (int i = 1; i < doc->numLangs(); i++)
seldoc.appendLang(doc->getIdent(i));
seldoc.setAuthor(doc->getAuthor());
seldoc.setLessonDescr(doc->getLessonDescr());
seldoc.setTypeDescr(doc->getTypeDescr());
for (int i = doc->numEntries()-1; i >= 0; i--)
if (doc->getEntry(i)->isInQuery() )
seldoc.appendEntry(doc->getEntry(i));
KURL url = KFileDialog::getSaveURL(TQString(), FILTER_WPATTERN, parentWidget(), i18n("Save Vocabulary As"));
if (!url.isEmpty() )
{
TQFileInfo fileinfo(url.path());
if (fileinfo.exists() && KMessageBox::warningContinueCancel(0,
i18n("<qt>The file<br><b>%1</b><br>already exists. Do you want to overwrite it?</qt>")
.arg(url.path()),TQString(),i18n("Overwrite")) == KMessageBox::Cancel)
{
// do nothing
}
else
{
TQString format = i18n("Saving %1");
TQString msg = format.arg(url.path());
slotStatusMsg(msg);
TQFile::remove(url.path()+"~"); // remove previous backup
// FIXME: check error
::rename (TQFile::encodeName(url.path()), TQFile::encodeName(url.path()+"~"));
saveDocProps(&seldoc);
prepareProgressBar();
seldoc.saveAs(TQT_TQOBJECT(this), url, i18n ("Part of: ") + doc->getTitle(), kvoctrainDoc::automatic);
removeProgressBar();
}
}
Prefs::setSeparator(save_separator);
slotStatusMsg(IDS_DEFAULT);
}
void kvoctrainApp::prepareProgressBar ()
{
statusBar()->clear ();
pbar = new KProgress (statusBar());
pbar->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
statusBar()->addWidget(pbar, 150, true);
pbar->show();
}
void kvoctrainApp::removeProgressBar ()
{
statusBar()->clear ();
statusBar()->removeWidget(pbar);
delete pbar;
pbar = 0;
delete pdlg;
pdlg = 0;
}