diff options
Diffstat (limited to 'kandy/src')
34 files changed, 6886 insertions, 0 deletions
diff --git a/kandy/src/Makefile.am b/kandy/src/Makefile.am new file mode 100644 index 000000000..d41626331 --- /dev/null +++ b/kandy/src/Makefile.am @@ -0,0 +1,38 @@ +bin_PROGRAMS = kandy kandy_client + +INCLUDES = -I$(top_srcdir) $(all_includes) + +kandy_LDFLAGS = $(KDE_RPATH) $(all_libraries) +kandy_LDADD = $(KANDY_LIBLOCKDEV) $(LIB_KFILE) -lkabc $(top_builddir)/libkdepim/libkdepim.la +kandy_SOURCES = main.cpp kandy.cpp \ + cmdpropertiesdialog_base.ui cmdpropertiesdialog.cpp \ + kandyview.cpp \ + kandyiface.skel \ + modem.cpp \ + atcommand.cpp commanditem.cpp mobilegui_base.ui mobilegui.cpp \ + commandscheduler.cpp commandset.cpp \ + kandyprefs.kcfgc kandyprefsdialog.cpp \ + mobilemain.cpp + +noinst_HEADERS = kandy.h kandyview.h modem.h atcommand.h \ + commanditem.h mobilegui.h commandscheduler.h + +kandy_client_LDFLAGS = $(KDE_RPATH) $(all_libraries) +kandy_client_LDADD = $(LIB_KDECORE) +kandy_client_SOURCES = kandy_client.cpp + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kandy.pot + +xdg_apps_DATA = kandy.desktop + +kde_kcfg_DATA = kandy.kcfg + +install-data-local: uninstall.desktop + $(mkinstalldirs) $(DESTDIR)$(kde_appsdir)/Utilities + $(INSTALL_DATA) $(srcdir)/uninstall.desktop $(DESTDIR)$(kde_appsdir)/Utilities/kandy.desktop + +rcdir = $(kde_datadir)/kandy +rc_DATA = kandyui.rc kandymobileui.rc diff --git a/kandy/src/atcommand.cpp b/kandy/src/atcommand.cpp new file mode 100644 index 000000000..006fedf15 --- /dev/null +++ b/kandy/src/atcommand.cpp @@ -0,0 +1,313 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "atcommand.h" + +#include <kdebug.h> +#include <klocale.h> + +ATParameter::ATParameter() +{ + mUserInput = false; +} + +ATParameter::ATParameter(const QString &value,const QString &name, + bool userInput) +{ + mName = name; + mValue = value; + mUserInput = userInput; +} + + +ATCommand::ATCommand() +{ + mHexOutput = false; + + construct(); +} + +ATCommand::ATCommand(const QString &cmdString) +{ + setCmdName(i18n("New Command")); + setCmdString(cmdString); + mHexOutput = false; + + extractParameters(); + + construct(); +} + +ATCommand::ATCommand(const QString &cmdName,const QString &cmdString, + bool hexOutput) +{ + setCmdName(cmdName); + setCmdString(cmdString); + mHexOutput = hexOutput; + + construct(); +} + +void ATCommand::construct() +{ + mAutoDelete = false; + mResultFieldsList.setAutoDelete(true); + mParameters.setAutoDelete(true); +} + +ATCommand::~ATCommand() +{ +// kdDebug() << "~ATCommand: " << cmdString() << endl; +} + + +void ATCommand::setCmdName(const QString &cmdName) +{ + mCmdName = cmdName; +} + +QString ATCommand::cmdName() +{ + return mCmdName; +} + + +void ATCommand::setCmdString(const QString &cmdString) +{ + mCmdString = cmdString; + + mId = cmdString; + if (mId.startsWith("at")) mId = mId.mid(2); + else mCmdString.prepend("at"); + +// kdDebug() << "ATCommand: Id: " << mId << endl; +} + +QString ATCommand::cmdString() +{ + return mCmdString; +} + +QString ATCommand::cmd() +{ + if (mParameters.count() > 0) { + QString cmd = cmdString().left(cmdString().find("=") + 1); +// kdDebug() << "--1-cmd: " << cmd << endl; + for(uint i=0;i<mParameters.count();++i) { + cmd += mParameters.at(i)->value(); + if (i < mParameters.count() - 1) cmd += ","; + } +// kdDebug() << "--2-cmd: " << cmd << endl; + return cmd; + } else { + return cmdString(); + } +} + +QString ATCommand::id() +{ + return mId; +} + +void ATCommand::setHexOutput(bool hexOutput) +{ + mHexOutput = hexOutput; +} + +bool ATCommand::hexOutput() +{ + return mHexOutput; +} + +void ATCommand::setResultString(const QString &resultString) +{ + mResultString = resultString; + + mResultFieldsList.clear(); + + QStringList resultFields = QStringList::split("\n",mResultString); + + for(QStringList::Iterator it = resultFields.begin(); + it != resultFields.end(); ++it) { + setResultFields(*it); + } +} + + +void ATCommand::setResultFields( QString fieldsString ) +{ + QString id = mId.upper().left( mId.find( '=' ) ); + + + // Truncate the command name prepended to the output by the modem. + if ( fieldsString.startsWith( id ) ) + fieldsString = fieldsString.mid( id.length() + 2 ); + + // If modem output is enclosed by brackets, remove them, too + if ( ( fieldsString[ 0 ] == '(' ) && ( fieldsString[ fieldsString.length() - 1 ] == ')' ) ) + fieldsString = fieldsString.mid( 1, fieldsString.length() - 2 ); + + QStringList *fields = new QStringList; + QStringList TmpFields = QStringList::split( ',', fieldsString ); + QString TmpString = ""; + + + // Assume a phonebook entry of the mobile phone has the format + // <familyname>, <givenname> + // Then, the above split() call separtes this entry into 2 distinct fields + // leading to an error in MobileGui::fillPhonebook since the number of + // fields is != 4. + // Hence, the fieldsString needs to be parsed a little bit. Names stored on + // the mobile phone are quoted. Commas within a quoted are of the fieldsString + // must not be divided into differend fields. + for ( QStringList::Iterator it = TmpFields.begin(); it != TmpFields.end(); it++ ) + { + // Start of a quoted area + if ( ( (*it)[ 0 ] == '\"' ) && ( (*it)[ (*it).length() - 1 ] != '\"' ) ) + TmpString = (*it).copy(); + else + // End of a quoted area + if ( ( (*it)[ 0 ] != '\"' ) && ( (*it)[ (*it).length() - 1 ] == '\"' ) ) + { + TmpString += "," + (*it).copy(); + (*fields).append( TmpString.copy() ); + TmpString = ""; + } else + // Not within a quoted area + if (TmpString.isEmpty()) + (*fields).append( *it ); + else + // Within a quoted area + TmpString += "," + (*it).copy(); + } + + mResultFieldsList.append( fields ); +} + + +QString ATCommand::resultString() +{ + return mResultString; +} + +QString ATCommand::resultField(int index) +{ + if (mResultFieldsList.count() == 0) return ""; + + QStringList *resultFields = mResultFieldsList.at(0); + + QStringList::Iterator it = resultFields->at(index); + if (it == resultFields->end()) { + kdDebug() << "ATCommand::resultField: index " << index << " out of range." + << endl; + return ""; + } + + return *it; +} + + +QPtrList<QStringList> *ATCommand::resultFields() +{ + return &mResultFieldsList; +} + +void ATCommand::addParameter(ATParameter *p) +{ + mParameters.append(p); +} + +void ATCommand::clearParameters() +{ + mParameters.clear(); +} + +QPtrList<ATParameter> ATCommand::parameters() +{ + return mParameters; +} + +void ATCommand::setParameter(int index,const QString &value) +{ + if (mParameters.count() <= (unsigned int)index) { + kdDebug() << "ATCommand " << cmdName() << " has no Parameter " << index + << endl; + return; + } + + mParameters.at(index)->setValue(value); +} + +void ATCommand::setParameter(int index,int value) +{ + setParameter(index,QString::number(value)); +} + +QString ATCommand::processOutput(const QString &output) +{ + if (hexOutput()) { + QString hexString = output.mid(output.find('\n')+1); + int i=0; + QString aChar = hexString.mid(i,2); + QString result; + while(!aChar.isEmpty()) { + int charValue = aChar.toInt(0,16); + QChar charEncoded(charValue); +// result += aChar + ": " + charEncoded + "\n"; + result += charEncoded; + i += 2; + aChar = hexString.mid(i,2); + } + result += "\n"; + return result; + } else { + return output; + } +} + +QString ATCommand::processOutput() +{ + return processOutput(mResultString); +} + +void ATCommand::extractParameters() +{ +// kdDebug() << "Arg String: " << cmdString() << endl; + + int pos = cmdString().find("="); + if (pos < 0) return; + + QString paraString = cmdString().mid(pos+1); +// kdDebug() << "Para String: " << paraString << endl; + QStringList paraList = QStringList::split(",",paraString); + + QStringList::ConstIterator it = paraList.begin(); + QStringList::ConstIterator end = paraList.end(); + int argNum = 1; + while(it != end) { + addParameter(new ATParameter(*it,i18n("Arg %1").arg(QString::number(argNum++)), + false)); + ++it; + } +} diff --git a/kandy/src/atcommand.h b/kandy/src/atcommand.h new file mode 100644 index 000000000..8296d1291 --- /dev/null +++ b/kandy/src/atcommand.h @@ -0,0 +1,111 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef ATCOMMAND_H +#define ATCOMMAND_H + +#include <qstring.h> +#include <qstringlist.h> +#include <qptrlist.h> + +class ATParameter { + public: + ATParameter(); + ATParameter(const QString &value,const QString &name="", + bool userInput=false); + + void setName(const QString &name) { mName = name; } + QString name() const { return mName; } + void setValue(const QString &value) { mValue = value; } + QString value() const { return mValue; } + void setUserInput(bool userInput) { mUserInput = userInput; } + bool userInput() const { return mUserInput; } + + private: + QString mName; + QString mValue; + bool mUserInput; +}; + +/** + This class provides an abstraction of an AT command. +*/ +// TODO: emit a signal, when the command was executed. +class ATCommand { + public: + ATCommand(); + ATCommand(const QString &cmdString); + ATCommand(const QString &cmdName,const QString &cmdString, + bool hexOutput=false); + virtual ~ATCommand(); + + void setCmdName(const QString &); + QString cmdName(); + + void setCmdString(const QString &); + QString cmdString(); + + QString cmd(); + + QString id(); + + void setHexOutput(bool); + bool hexOutput(); + + QString processOutput(const QString &); + QString processOutput(); + + void setResultString(const QString &); + QString resultString(); + QString resultField(int index); + QPtrList<QStringList> *resultFields(); + + void addParameter(ATParameter *); + void clearParameters(); + QPtrList<ATParameter> parameters(); + + void setParameter(int index,const QString &value); + void setParameter(int index,int value); + + void setAutoDelete(bool autoDelete) { mAutoDelete = autoDelete; } + bool autoDelete() { return mAutoDelete; } + + private: + void construct(); + void setResultFields(QString fieldsString); + void extractParameters(); + + QString mCmdName; + QString mCmdString; + QString mId; + bool mHexOutput; + + QString mResultString; + QPtrList<QStringList> mResultFieldsList; + + QPtrList<ATParameter> mParameters; + + bool mAutoDelete; +}; + +#endif diff --git a/kandy/src/cmdpropertiesdialog.cpp b/kandy/src/cmdpropertiesdialog.cpp new file mode 100644 index 000000000..f871a02bb --- /dev/null +++ b/kandy/src/cmdpropertiesdialog.cpp @@ -0,0 +1,120 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlistview.h> +#include <qlineedit.h> +#include <qcheckbox.h> + +#include <kinputdialog.h> +#include <klocale.h> + +#include "atcommand.h" + +#include "cmdpropertiesdialog.h" +#include "cmdpropertiesdialog.moc" + +class ParameterItem : public QCheckListItem { + public: + ParameterItem(ATParameter *p,QListView *parent) : + QCheckListItem(parent,p->name(),CheckBox),mParameter(p) + { + setText(1,p->value()); + setOn(p->userInput()); + } + + void writeParameter() + { + mParameter->setName(text(0)); + mParameter->setValue(text(1)); + mParameter->setUserInput(isOn()); + } + + private: + ATParameter *mParameter; +}; + + +/* + * Constructs a CmdPropertiesDialog which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +CmdPropertiesDialog::CmdPropertiesDialog(ATCommand *cmd, QWidget* parent, + const char* name, bool modal, + WFlags fl ) + : CmdPropertiesDialog_base( parent, name, modal, fl ) +{ + mCmd = cmd; + + readCommand(); +} + +CmdPropertiesDialog::~CmdPropertiesDialog() +{ +} + +void CmdPropertiesDialog::readCommand() +{ + mNameEdit->setText(mCmd->cmdName()); + mStringEdit->setText(mCmd->cmdString()); + mHexCheck->setChecked(mCmd->hexOutput()); + + QPtrList<ATParameter> parameters = mCmd->parameters(); + for(int i=(int)parameters.count()-1;i>=0;--i) { + ATParameter *p = parameters.at(i); + new ParameterItem(p,mParameterList); + } +} + +void CmdPropertiesDialog::writeCommand() +{ + mCmd->setCmdName(mNameEdit->text()); + mCmd->setCmdString(mStringEdit->text()); + mCmd->setHexOutput(mHexCheck->isChecked()); + ParameterItem *item = (ParameterItem *)mParameterList->firstChild(); + while (item) { + item->writeParameter(); + item = (ParameterItem *)item->nextSibling(); + } +} + +void CmdPropertiesDialog::editParameterName(QListViewItem *item) +{ + bool ok = false; + + QString newName = KInputDialog::getText(QString::null, + i18n("Enter parameter name:"),item->text(0),&ok,this); + + if (ok) { + item->setText(0,newName); + } +} + +void CmdPropertiesDialog::slotAccept() +{ + writeCommand(); + accept(); +} diff --git a/kandy/src/cmdpropertiesdialog.h b/kandy/src/cmdpropertiesdialog.h new file mode 100644 index 000000000..18849d3d6 --- /dev/null +++ b/kandy/src/cmdpropertiesdialog.h @@ -0,0 +1,50 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef CMDPROPERTIESDIALOG_H +#define CMDPROPERTIESDIALOG_H + +#include "cmdpropertiesdialog_base.h" + +class ATCommand; + +class CmdPropertiesDialog : public CmdPropertiesDialog_base +{ + Q_OBJECT + public: + CmdPropertiesDialog(ATCommand *cmd,QWidget* parent=0,const char* name=0, + bool modal=false,WFlags fl=0); + ~CmdPropertiesDialog(); + + protected slots: + void editParameterName(QListViewItem *); + void slotAccept(); + + private: + void readCommand(); + void writeCommand(); + + ATCommand *mCmd; +}; + +#endif // CMDPROPERTIESDIALOG_H diff --git a/kandy/src/cmdpropertiesdialog_base.ui b/kandy/src/cmdpropertiesdialog_base.ui new file mode 100644 index 000000000..092074c6e --- /dev/null +++ b/kandy/src/cmdpropertiesdialog_base.ui @@ -0,0 +1,172 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>CmdPropertiesDialog_base</class> +<widget class="QDialog"> + <property name="name"> + <cstring>CmdPropertiesDialog_base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>323</width> + <height>281</height> + </rect> + </property> + <property name="caption"> + <string>Command Properties</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLineEdit" row="0" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>mNameEdit</cstring> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>mStringEdit</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>Name:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>String:</string> + </property> + </widget> + <widget class="QCheckBox" row="3" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>mHexCheck</cstring> + </property> + <property name="text"> + <string>Hex result</string> + </property> + </widget> + <widget class="QListView" row="2" column="0" rowspan="1" colspan="4"> + <column> + <property name="text"> + <string>Position</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Parameter</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Value</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>mParameterList</cstring> + </property> + </widget> + <spacer row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>79</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="4" column="2"> + <property name="name"> + <cstring>buttonOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton" row="4" column="3"> + <property name="name"> + <cstring>buttonCancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>mParameterList</sender> + <signal>rightButtonClicked(QListViewItem*,const QPoint&,int)</signal> + <receiver>CmdPropertiesDialog_base</receiver> + <slot>editParameterName(QListViewItem*)</slot> + </connection> + <connection> + <sender>buttonOk</sender> + <signal>clicked()</signal> + <receiver>CmdPropertiesDialog_base</receiver> + <slot>slotAccept()</slot> + </connection> + <connection> + <sender>buttonCancel</sender> + <signal>clicked()</signal> + <receiver>CmdPropertiesDialog_base</receiver> + <slot>reject()</slot> + </connection> +</connections> +<slots> + <slot>editParameterName(QListViewItem *)</slot> + <slot access="protected">slotAccept()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kandy/src/commanditem.cpp b/kandy/src/commanditem.cpp new file mode 100644 index 000000000..fde599c3f --- /dev/null +++ b/kandy/src/commanditem.cpp @@ -0,0 +1,102 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qdom.h> + +#include <kdebug.h> + +#include "atcommand.h" + +#include "commanditem.h" + +CommandItem::CommandItem(QListView *listView,ATCommand *command) + : QListViewItem(listView) +{ + mCommand = command; + + setItemText(); +} + +CommandItem::~CommandItem() +{ +} + +ATCommand *CommandItem::command() +{ + return mCommand; +} + +void CommandItem::load(QDomElement *c) +{ + mCommand->setCmdName(c->attribute("name","unknown")); + mCommand->setCmdString(c->attribute("string","at")); + mCommand->setHexOutput(c->attribute("hexoutput","n") == "y"); + + QDomNode n = c->firstChild(); + while(!n.isNull()) { + QDomElement e = n.toElement(); + if (!e.isNull()) { + ATParameter *p = new ATParameter; + p->setName(e.attribute("name","unnamed")); + p->setValue(e.attribute("value","0")); + p->setUserInput(e.attribute("userinput","n") == "y"); + + mCommand->addParameter(p); + } + n = n.nextSibling(); + } + + setItemText(); +} + +void CommandItem::save(QDomDocument *doc,QDomElement *parent) +{ + QDomElement c = doc->createElement("command"); + c.setAttribute("name",mCommand->cmdName()); + c.setAttribute("string",mCommand->cmdString()); + c.setAttribute("hexoutput",mCommand->hexOutput() ? "y" : "n"); + parent->appendChild(c); + + QPtrList<ATParameter> paras = mCommand->parameters(); + for(uint i=0;i<paras.count();++i) { + saveParameter(paras.at(i),doc,&c); + } +} + +void CommandItem::saveParameter(ATParameter *p, QDomDocument *doc, + QDomElement *parent) +{ + QDomElement e = doc->createElement("parameter"); + e.setAttribute("name",p->name()); + e.setAttribute("value",p->value()); + e.setAttribute("userinput",p->userInput() ? "y" : "n"); + parent->appendChild(e); +} + +void CommandItem::setItemText() +{ + setText(0,mCommand->cmdName()); + setText(1,mCommand->cmdString()); + setText(2,mCommand->hexOutput() ? "y" : "n"); +} diff --git a/kandy/src/commanditem.h b/kandy/src/commanditem.h new file mode 100644 index 000000000..853bba01b --- /dev/null +++ b/kandy/src/commanditem.h @@ -0,0 +1,57 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef _COMMAND_ITEM_H_ +#define _COMMAND_ITEM_H_ + +#include <qlistview.h> + +class ATCommand; +class ATParameter; +class QDomElement; +class QDomDocument; + +/** + QListView item representing a modem command. +*/ +class CommandItem : public QListViewItem { + public: + CommandItem(QListView *listView,ATCommand *command); + ~CommandItem(); + + ATCommand *command(); + + void load(QDomElement *c); + void save(QDomDocument *doc,QDomElement *parent); + + void setItemText(); + + protected: + void saveParameter(ATParameter *p, QDomDocument *doc,QDomElement *parent); + + private: + ATCommand *mCommand; +}; + +#endif diff --git a/kandy/src/commandscheduler.cpp b/kandy/src/commandscheduler.cpp new file mode 100644 index 000000000..23544e8a2 --- /dev/null +++ b/kandy/src/commandscheduler.cpp @@ -0,0 +1,140 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <kdebug.h> +#include <klocale.h> + +#include "modem.h" + +#include "commandscheduler.h" +#include "commandscheduler.moc" + +CommandScheduler::CommandScheduler(Modem *modem,QObject *parent, + const char *name) : + QObject(parent,name), + mModem(modem) +{ + connect(mModem,SIGNAL(gotLine(const char *)), + SLOT(processOutput(const char *))); +} + +void CommandScheduler::execute(ATCommand *command) +{ + if (!mModem->isOpen()) { + kdDebug(5960) << "Warning! Modem not open." << endl; + return; + } + + mCommandQueue.append(command); + +// if (mCommandQueue.count() == 1) sendCommand(command->cmdString()); + if (mCommandQueue.count() == 1) sendCommand(command->cmd()); +} + +void CommandScheduler::execute(const QString &command) +{ + ATCommand *cmd = new ATCommand("",command); + cmd->setAutoDelete(true); + + execute(cmd); +} + +void CommandScheduler::executeId(const QString &id) +{ + QPtrList<ATCommand> *cmds = mCommandSet.commandList(); + + for(uint i=0;i<cmds->count();++i) { + if (cmds->at(i)->id() == id) { + execute(cmds->at(i)); + return; + } + } + kdDebug(5960) << "CommandScheduler::executeId(): Id '" << id << "' not found" << endl; +} + +void CommandScheduler::sendCommand(const QString &command) +{ + if (command.isEmpty()) { + kdDebug(5960) << "CommandScheduler::sendCommand(): Warning! Empty command." + << endl; + return; + } + + kdDebug(5960) << "CommandScheduler:sendCommand(): " << command << endl; + + mModem->writeLine(command.latin1()); +} + + +void CommandScheduler::processOutput(const char *line) +{ + QString l = line; + ATCommand *cmd = mCommandQueue.first(); + if (l == "OK") { + mState = WAITING; + emit result(mResult); + cmd->setResultString(mResult); + emit commandProcessed(cmd); + nextCommand(); + } else if (l == "ERROR") { + mState = WAITING; + emit result(i18n("Error")); + nextCommand(); + } else { + if (mState == WAITING) { + mState = PROCESSING; + mResult = ""; + } else if (mState == PROCESSING) { + if (!l.isEmpty()) { + mResult += l; + mResult += "\n"; + } + } + } +} + +void CommandScheduler::nextCommand() +{ + if (mCommandQueue.first()->autoDelete()) delete mCommandQueue.first(); + mCommandQueue.removeFirst(); + if (mCommandQueue.count() > 0) { + sendCommand(mCommandQueue.first()->cmd()); + } +} + +bool CommandScheduler::loadProfile(const QString& filename) +{ + mCommandSet.clear(); + + if (!mCommandSet.loadFile(filename)) return false; + + return true; +} + +bool CommandScheduler::saveProfile(const QString& filename) +{ + if (!mCommandSet.saveFile(filename)) return false; + + return true; +} diff --git a/kandy/src/commandscheduler.h b/kandy/src/commandscheduler.h new file mode 100644 index 000000000..20398aafa --- /dev/null +++ b/kandy/src/commandscheduler.h @@ -0,0 +1,76 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef COMMANDSCHEDULER_H +#define COMMANDSCHEDULER_H + +#include <qobject.h> +#include <qptrlist.h> + +#include "atcommand.h" +#include "commandset.h" + +class Modem; + +class CommandScheduler : public QObject { + Q_OBJECT + public: + CommandScheduler (Modem *modem,QObject *parent = 0, const char *name = 0); + + void execute(const QString &command); + void execute(ATCommand *command); + void executeId(const QString &id); + + Modem *modem() { return mModem; } + CommandSet *commandSet() { return &mCommandSet; } + + bool loadProfile(const QString& filename); + bool saveProfile(const QString& filename); + + signals: + void result(const QString &); + void commandProcessed(ATCommand *); + + private slots: + void processOutput(const char *line); + + private: + void sendCommand(const QString &command); + void nextCommand(); + + private: + Modem *mModem; + + CommandSet mCommandSet; + + ATCommand *mLastCommand; + + QPtrList<ATCommand> mCommandQueue; + + enum State { WAITING, PROCESSING }; + State mState; + + QString mResult; +}; + +#endif diff --git a/kandy/src/commandset.cpp b/kandy/src/commandset.cpp new file mode 100644 index 000000000..f44899cac --- /dev/null +++ b/kandy/src/commandset.cpp @@ -0,0 +1,154 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qdom.h> +#include <qfile.h> +#include <qtextstream.h> + +#include <kdebug.h> + +#include "atcommand.h" + +#include "commandset.h" + +CommandSet::CommandSet() +{ + mList.setAutoDelete(true); +} + +CommandSet::~CommandSet() +{ +} + +void CommandSet::addCommand(ATCommand *command) +{ + mList.append(command); +} + +void CommandSet::deleteCommand(ATCommand *command) +{ + mList.removeRef(command); +} + +bool CommandSet::loadFile(const QString& filename) +{ +// kdDebug(5960) << "CommandSet::loadFile(): " << filename << endl; + + QDomDocument doc("Kandy"); + QFile f(filename); + if (!f.open(IO_ReadOnly)) + return false; + if (!doc.setContent(&f)) { + f.close(); + return false; + } + f.close(); + + QDomNodeList commands = doc.elementsByTagName("command"); + for(uint i=0;i<commands.count();++i) { + QDomElement c = commands.item(i).toElement(); + if (!c.isNull()) { + ATCommand *cmd = new ATCommand; + loadCommand(cmd,&c); + addCommand(cmd); + } + } + + return true; +} + +bool CommandSet::saveFile(const QString& filename) +{ + kdDebug(5960) << "CommandSet::saveFile(): " << filename << endl; + + QDomDocument doc("Kandy"); + QDomElement set = doc.createElement("commandset"); + doc.appendChild(set); + + for(uint i=0; i<mList.count();++i) { + saveCommand(mList.at(i),&doc,&set); + } + + QFile xmlfile(filename); + if (!xmlfile.open(IO_WriteOnly)) { + kdDebug(5960) << "Error opening file for write." << endl; + return false; + } + QTextStream ts(&xmlfile); + doc.documentElement().save(ts,2); + xmlfile.close(); + + return true; +} + +void CommandSet::clear() +{ + mList.clear(); +} + +void CommandSet::loadCommand(ATCommand *command,QDomElement *c) +{ + command->setCmdName(c->attribute("name","unknown")); + command->setCmdString(c->attribute("string","at")); + command->setHexOutput(c->attribute("hexoutput","n") == "y"); + + QDomNode n = c->firstChild(); + while(!n.isNull()) { + QDomElement e = n.toElement(); + if (!e.isNull()) { + ATParameter *p = new ATParameter; + p->setName(e.attribute("name","unnamed")); + p->setValue(e.attribute("value","0")); + p->setUserInput(e.attribute("userinput","n") == "y"); + + command->addParameter(p); + } + n = n.nextSibling(); + } +} + +void CommandSet::saveCommand(ATCommand *command,QDomDocument *doc, + QDomElement *parent) +{ + QDomElement c = doc->createElement("command"); + c.setAttribute("name",command->cmdName()); + c.setAttribute("string",command->cmdString()); + c.setAttribute("hexoutput",command->hexOutput() ? "y" : "n"); + parent->appendChild(c); + + QPtrList<ATParameter> paras = command->parameters(); + for(uint i=0;i<paras.count();++i) { + saveParameter(paras.at(i),doc,&c); + } +} + +void CommandSet::saveParameter(ATParameter *p, QDomDocument *doc, + QDomElement *parent) +{ + QDomElement e = doc->createElement("parameter"); + e.setAttribute("name",p->name()); + e.setAttribute("value",p->value()); + e.setAttribute("userinput",p->userInput() ? "y" : "n"); + parent->appendChild(e); +} diff --git a/kandy/src/commandset.h b/kandy/src/commandset.h new file mode 100644 index 000000000..41c9cd144 --- /dev/null +++ b/kandy/src/commandset.h @@ -0,0 +1,61 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef COMMANDSET_H +#define COMMANDSET_H + +#include <qlistview.h> + +class ATCommand; +class ATParameter; +class QDomElement; +class QDomDocument; + +/** + QListView item representing a modem command. +*/ +class CommandSet { + public: + CommandSet(); + ~CommandSet(); + + void addCommand(ATCommand *); + void deleteCommand(ATCommand *); + + bool loadFile(const QString &); + bool saveFile(const QString &); + + void clear(); + + QPtrList<ATCommand> *commandList() { return &mList; } + + protected: + void loadCommand(ATCommand *,QDomElement *c); + void saveCommand(ATCommand *,QDomDocument *doc,QDomElement *parent); + void saveParameter(ATParameter *p, QDomDocument *doc,QDomElement *parent); + + private: + QPtrList<ATCommand> mList; +}; + +#endif diff --git a/kandy/src/kandy.cpp b/kandy/src/kandy.cpp new file mode 100644 index 000000000..860aff5bb --- /dev/null +++ b/kandy/src/kandy.cpp @@ -0,0 +1,348 @@ +/* + This file is part of Kandy. + + Copyright (c) 2000,2001,2002 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlineedit.h> +#include <qprinter.h> +#include <qprintdialog.h> +#include <qpainter.h> +#include <qpaintdevicemetrics.h> + +#include <kglobal.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmenubar.h> +#include <kkeydialog.h> +#include <kaccel.h> +#include <kio/netaccess.h> +#include <kfiledialog.h> +#include <kconfig.h> +#include <kurl.h> +#include <kurlrequesterdlg.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kedittoolbar.h> +#include <kstdaccel.h> +#include <kaction.h> +#include <kstdaction.h> +#include <kurldrag.h> + +#include "kandyprefsdialog.h" +#include "commandscheduler.h" +#include "kandyprefs.h" +#include "modem.h" + +#include "kandy.h" +#include <kstatusbar.h> +#include "kandy.moc" + +Kandy::Kandy(CommandScheduler *scheduler) + : KMainWindow( 0, "Kandy" ), + mPrinter(0) +{ + mScheduler = scheduler; + + mPreferencesDialog = 0; + + mView = new KandyView(mScheduler,this); + + // accept dnd + setAcceptDrops(true); + + // tell the KMainWindow that this is indeed the main widget + setCentralWidget(mView); + + // then, setup our actions + setupActions(); + + statusBar()->insertItem(i18n(" Disconnected "),0,0,true); + + setAutoSaveSettings(); + + // allow the view to change the statusbar and caption + connect(mView, SIGNAL(signalChangeStatusbar(const QString&)), + this, SLOT(changeStatusbar(const QString&))); + connect(mView, SIGNAL(signalChangeCaption(const QString&)), + this, SLOT(changeCaption(const QString&))); + + connect(mView,SIGNAL(modifiedChanged(bool)),SLOT(setTitle())); + + KConfig *config = KGlobal::config(); + config->setGroup("General"); + QString currentProfile = config->readEntry("CurrentProfile", + locate("appdata","default.kandy")); + if (!currentProfile.isEmpty()) load(currentProfile); +} + +Kandy::~Kandy() +{ +} + +void Kandy::load(const QString& filename) +{ + if (!mView->loadFile(filename)) { + KMessageBox::error(this,i18n("Could not load file %1").arg(filename)); + } + + mFilename = filename; + setTitle(); +} + +void Kandy::save(const QString & filename) +{ + if (!filename.isEmpty()) { + if (!mView->saveFile(filename)) { + KMessageBox::error(this,i18n("Could not save file %1.").arg(filename)); + } else { + mFilename = filename; + setTitle(); + } + } +} + +void Kandy::setupActions() +{ + KStdAction::open(this, SLOT(fileOpen()), actionCollection()); + KStdAction::save(this, SLOT(fileSave()), actionCollection()); + KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection()); +// KStdAction::print(this, SLOT(filePrint()), actionCollection()); + KStdAction::quit(this, SLOT(close()), actionCollection()); + + createStandardStatusBarAction(); + setStandardToolBarMenuEnabled(true); + + KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection()); + KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection()); + KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection()); + + new KAction(i18n("Mobile GUI"),0,this,SLOT(showMobileGui()), + actionCollection(),"show_mobilegui"); + + mConnectAction = new KAction(i18n("Connect"),0,this,SLOT(modemConnect()), + actionCollection(),"modem_connect"); + mDisconnectAction = new KAction(i18n("Disconnect"),0,this, + SLOT(modemDisconnect()),actionCollection(), + "modem_disconnect"); + + createGUI(); +} + +void Kandy::saveProperties(KConfig */*config*/) +{ + // the 'config' object points to the session managed + // config file. anything you write here will be available + // later when this app is restored +} + +void Kandy::readProperties(KConfig */*config*/) +{ + // the 'config' object points to the session managed + // config file. this function is automatically called whenever + // the app is being restored. read in here whatever you wrote + // in 'saveProperties' +} + +void Kandy::dragEnterEvent(QDragEnterEvent *event) +{ + // do nothing + KMainWindow::dragEnterEvent(event); + + // accept uri drops only +// event->accept(KURLDrag::canDecode(event)); +} + +void Kandy::dropEvent(QDropEvent *event) +{ + // this is a very simplistic implementation of a drop event. we + // will only accept a dropped URL. the Qt dnd code can do *much* + // much more, so please read the docs there + + // do nothing + KMainWindow::dropEvent(event); +/* + KURL::List list; + + // see if we can decode a URI.. if not, just ignore it + if (KURLDrag::decode(event, list) && !list.isEmpty()) + { + // okay, we have a URI.. process it + const KURL &url = uri.first(); + + if (url.isLocalFile()) + { + // load in the file + load(url.path()); + } + } +*/ +} + +void Kandy::fileOpen() +{ + // this slot is called whenever the File->Open menu is selected, + // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar + // button is clicked + QString filename = KFileDialog::getOpenFileName(); + if (!filename.isEmpty()) load(filename); +} + +void Kandy::fileSave() +{ + if (mFilename.isEmpty()) fileSaveAs(); + else save(mFilename); +} + +void Kandy::fileSaveAs() +{ + QString filename = KFileDialog::getSaveFileName(); + save(filename); +} + +void Kandy::filePrint() +{ + // this slot is called whenever the File->Print menu is selected, + // the Print shortcut is pressed (usually CTRL+P) or the Print toolbar + // button is clicked + if (!mPrinter) mPrinter = new QPrinter; + if (QPrintDialog::getPrinterSetup(mPrinter)) + { + // setup the printer. with Qt, you always "print" to a + // QPainter.. whether the output medium is a pixmap, a screen, + // or paper + QPainter p; + p.begin(mPrinter); + + // we let our view do the actual printing + QPaintDeviceMetrics metrics(mPrinter); + mView->print(&p, metrics.height(), metrics.width()); + + // and send the result to the printer + p.end(); + } +} + +void Kandy::optionsConfigureKeys() +{ + KKeyDialog::configure( actionCollection(), this ); +} + +void Kandy::optionsConfigureToolbars() +{ + // use the standard toolbar editor + saveMainWindowSettings( KGlobal::config(), autoSaveGroup() ); + KEditToolbar dlg(actionCollection()); + connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(newToolbarConfig())); + dlg.exec(); +} + +void Kandy::newToolbarConfig() +{ + // this slot is called when user clicks "Ok" or "Apply" in the toolbar editor. + // recreate our GUI, and re-apply the settings (e.g. "text under icons", etc.) + createGUI(); + applyMainWindowSettings( KGlobal::config(), autoSaveGroup() ); +} + +void Kandy::optionsPreferences() +{ + if (!mPreferencesDialog) { + mPreferencesDialog = new KandyPrefsDialog(this); + mPreferencesDialog->readConfig(); + } + + mPreferencesDialog->show(); + mPreferencesDialog->raise(); +} + +void Kandy::changeStatusbar(const QString& text) +{ + // display the text on the statusbar + statusBar()->message(text); +} + +void Kandy::changeCaption(const QString& text) +{ + // display the text on the caption + setCaption(text); +} + +void Kandy::setTitle() +{ + if (mFilename.isEmpty()) { + setCaption(i18n("New Profile"),mView->isModified()); + } else { + setCaption(mFilename,mView->isModified()); + } +} + +bool Kandy::queryClose() +{ + if (mView->isModified()) { + switch (KMessageBox::warningYesNoCancel(this, + i18n("Save changes to profile %1?").arg(mFilename), QString::null, KStdGuiItem::save(), KStdGuiItem::discard())) { + case KMessageBox::Yes : + fileSave(); + return true; + case KMessageBox::No : + return true; + default: // cancel + return false; + } + } else { + return true; + } +} + +void Kandy::modemConnect() +{ + if (!mScheduler->modem()->open()) { + KMessageBox::sorry(this, + i18n("Cannot open modem device %1.") + .arg(KandyPrefs::serialDevice()), i18n("Modem Error")); + return; + } + + statusBar()->changeItem(i18n(" Connected "),0); + + emit connectStateChanged(true); +} + +void Kandy::modemDisconnect() +{ + mScheduler->modem()->close(); + + statusBar()->changeItem(i18n(" Disconnected "),0); + + emit connectStateChanged(false); +} + +void Kandy::showMobileGui() +{ + emit showMobileWin(); +} + +void Kandy::showErrorMessage( const QString &text ) +{ + KMessageBox::error( 0, text ); +} diff --git a/kandy/src/kandy.desktop b/kandy/src/kandy.desktop new file mode 100644 index 000000000..b003dd045 --- /dev/null +++ b/kandy/src/kandy.desktop @@ -0,0 +1,121 @@ +[Desktop Entry] +Name=Kandy +Name[hi]=केंडी +Name[ne]=केनà¥à¤¡à¥€ +Name[ta]=Kஅனà¯à®Ÿà®¿ +Comment=Tool for syncing address book data with mobile phones +Comment[af]=Program om die adres boek data met die van 'n selfoon te sinkroniseer +Comment[bg]=ИнÑтрумент за Ñинхронизиране на адреÑника Ñ Ð¼Ð¾Ð±Ð¸Ð»Ð½Ð¸ телефони +Comment[bs]=Alat za sinhroniziranje podataka izmeÄ‘u adresara i mobilnih telefona +Comment[ca]=Eina per sincronitzar dades de la llibreta d'adreces amb telèfons mòbils +Comment[cs]=Nástroj pro synchronizaci kontaktů s mobilnÃmi telefony +Comment[da]=Værktøj til at synkronisere adressebogens data med mobiltelefoner +Comment[de]=Werkzeug zum Abgleich von Adressbuchdaten mit dem Mobiltelefon +Comment[el]=ΕÏγαλείο συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï Î²Î¹Î²Î»Î¯Ï‰Î½ διευθÏνσεων με κινητά τηλÎφωνα +Comment[es]=Herramienta para sincronizar datos de la libreta de direcciones con teléfonos móviles +Comment[et]=Vahend aadressiraamatu andmete sünkroniseerimiseks mobiiltelefoniga +Comment[eu]=Helbide-liburua zure mugikorrarekin sinkronizatzeko tresna +Comment[fa]=ابزار برای همگام‌سازی دادۀ کتاب نشانی با تلÙنهای همراه +Comment[fi]=Osoitekirjan tietojan ja kännykän liitostyökalu +Comment[fr]=Outil pour synchroniser les données de carnets d'adresses avec les téléphones mobiles +Comment[fy]=Helpmiddel om adresboekdata te syngronisearjen mei mobile tillefoans +Comment[gl]=Ferramenta para sincronizar os datos do caderno de enderezos con teléfonos móbiles +Comment[hu]=Segédprogram számÃtógép és mobiltelefon cÃmjegyzékének szinkronizálásához +Comment[is]=Tól sem samstillir vistfangagögn við farsÃma +Comment[it]=Strumento per sincronizzare i dati della rubrica indirizzi con i telefoni cellulari +Comment[ja]=アドレス帳ã®ãƒ‡ãƒ¼ã‚¿ã‚’æºå¸¯é›»è©±ã¨åŒæœŸã™ã‚‹ãŸã‚ã®ãƒ„ール +Comment[ka]=მáƒáƒ‘ილურტელეფáƒáƒœáƒ—áƒáƒœ წიგნáƒáƒ™áƒ˜áƒ¡ მáƒáƒœáƒáƒªáƒ”მების სინქრáƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ˜áƒ¡ ხელსáƒáƒ¬áƒ§áƒ +Comment[kk]=ÐдреÑтік кітапшаны қалта телефонмен қадамдаÑтыру құралы +Comment[km]=ឧបករណáŸâ€‹ážŸáž˜áŸ’រាប់​ធ្វើ​សមកាលកម្ម​ទិន្ននáŸáž™â€‹ážŸáŸ€ážœáž—ៅ​អាសយដ្ឋាន​ជាមួយ​នឹង​ទូរសáŸáž–្ទ​ចលáŸáž +Comment[lt]=Ä®rankis adresų knygelÄ—s sinchronizavimui su mobiliaisiais telefonais +Comment[mk]=Ðлатка за Ñинхронизирање адреÑари Ñо мобилни телефони +Comment[ms]=Alat untuk segerakkan data buku alamat dengan telefon bimbit +Comment[nb]=Verktøy for synkronisering av adressebok med mobiltelefoner +Comment[nds]=Synkroniseren vun Adressbookdaten mit Mobiltelefonen +Comment[ne]=मोबाइल फोनमा ठेगाना पà¥à¤¸à¥à¤¤à¤¿à¤•à¤¾ समकà¥à¤°à¤®à¤£ गरà¥à¤¨à¤•à¤¾ लागि उपकरण +Comment[nl]=Hulpmiddel om adresboekgegevens te synchroniseren met mobiele telefoons +Comment[nn]=Verktøy for Ã¥ synkronisera adresseboka med mobiltelefonar +Comment[pl]=NarzÄ™dzie do synchronizacji książki adresowej z telefonami komórkowymi +Comment[pt]=Ferramenta para sincronizar dados do livro de endereços com telemóveis +Comment[pt_BR]=Ferramenta para a sincronização dos dados do livro de endereços com dispositivos móveis +Comment[ru]=Программа Ñинхронизации адреÑной книги Ñ Ð¼Ð¾Ð±Ð¸Ð»ÑŒÐ½Ñ‹Ð¼ телефоном +Comment[sk]=Nástroj pre synchronizáciu adresára s mobilmi +Comment[sl]=Orodje za usklajevanje podatkov adresarja z mobilnim telefonom +Comment[sr]=Ðлат за Ñинхронизацију адреÑара Ñа мобилним телефонима +Comment[sr@Latn]=Alat za sinhronizaciju adresara sa mobilnim telefonima +Comment[sv]=Verktyg för att synkronisera adressboksdata med mobiltelefoner +Comment[ta]= செலà¯à®ªà¯‡à®šà®¿ கொணà¯à®Ÿ à®®à¯à®•à®µà®°à®¿ பà¯à®¤à¯à®¤à®• தரவின௠ஒனà¯à®±à®¿à®£à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à®±à¯à®•à®¾à®© கரà¯à®µà®¿ +Comment[tg]=Барномаи ÑинхронизатÑиÑи китоби адреÑÓ£ бо телефони мобилӣ +Comment[tr]=Cep telefonları ile adres defteri paylaşımı için araç +Comment[uk]=ІнÑтрумент Ð´Ð»Ñ Ñинхронізації даних адреÑної книги з мобільним телефоном +Comment[zh_CN]=将地å€ç°¿æ•°æ®ä¸Žç§»åŠ¨ç”µè¯åŒæ¥çš„工具 +Comment[zh_TW]=將通訊錄與手機åŒæ¥çš„工具 +Exec=kandy %i %m -caption "%c" +Icon=kandy +Type=Application +GenericName=Mobile Phone Tool +GenericName[af]=Mobiele Foon Program +GenericName[bg]=Мобилни телефони +GenericName[bs]=Alat za mobilne telefone +GenericName[ca]=Eina per a telèfons mòbils +GenericName[cs]=Nástroj pro mobilnà telefony +GenericName[cy]=Erfyn Ffôn Symudol +GenericName[da]=Mobiltelefonværktøj +GenericName[de]=Programm für Mobiltelefone +GenericName[el]=ΕÏγαλείο κινητών τηλεφώνων +GenericName[eo]=Ilo por poÅtelefono +GenericName[es]=Gestor de teléfonos móviles +GenericName[et]=Mobiiltelefoni rakendus +GenericName[eu]=Telefono mugikorrendako Tresna +GenericName[fa]=ابزار تلÙÙ† همراه +GenericName[fi]=Matkapuhelintyökalu +GenericName[fr]=Outil de connexion à votre téléphone portable +GenericName[fy]=Mobiele tillefoan-behear +GenericName[gl]=Ferramenta para o Teléfono Móbil +GenericName[he]=כלי טלפון × ×™×™×“ +GenericName[hi]=मोबाइल फोन उपकरण +GenericName[hr]=Alat za mobitele +GenericName[hu]=Mobil-cÃmjegyzék +GenericName[is]=FarsÃmatól +GenericName[it]=Strumento per i telefoni cellulari +GenericName[ja]=æºå¸¯é›»è©±ãƒ„ール +GenericName[ka]=მáƒáƒ‘ილურტელეფáƒáƒœáƒ—áƒáƒœ სáƒáƒ›áƒ£áƒ¨áƒáƒ ხელსáƒáƒ¬áƒ§áƒ +GenericName[kk]=Қалта телефон құралы +GenericName[km]=ឧបករណáŸâ€‹áž‘ូរសáŸáž–្ទ​ចលáŸáž +GenericName[lt]=Mobilaus telefono įrankis +GenericName[lv]=MobÄ«lÄ Telefona RÄ«ks +GenericName[mk]=Ðлатка за мобилни телефони +GenericName[ms]=Alatan Fon Mudah Alih +GenericName[nb]=Mobiltelefonverktøy +GenericName[nds]=Mobiltelefoon-Warktüüch +GenericName[ne]=मोबाइल फोन उपकरण +GenericName[nl]=Mobiele telefoon-beheer +GenericName[nn]=Mobiltelefonverktøy +GenericName[nso]=Sebereka sago Thatha sa Mogala +GenericName[pl]=ÅÄ…cznik z telefonem komórkowym +GenericName[pt]=Ferramenta para Telemóveis +GenericName[pt_BR]=Ferramenta de Telefonia Móvel +GenericName[ro]=Utilitar telefon mobil +GenericName[ru]=Работа Ñ Ð¼Ð¾Ð±Ð¸Ð»ÑŒÐ½Ñ‹Ð¼ телефоном +GenericName[se]=Mátketelefuvdnareaidu +GenericName[sk]=Nástroj pre mobily +GenericName[sl]=Orodje za mobilni telefon +GenericName[sr]=Ðлат за мобилни телефон +GenericName[sr@Latn]=Alat za mobilni telefon +GenericName[sv]=Verktyg för mobiltelefon +GenericName[ta]=செலà¯à®ªà¯‡à®šà®¿ கரà¯à®µà®¿ +GenericName[tg]=Кор бо телефони мобилӣ +GenericName[th]=เครื่à¸à¸‡à¸¡à¸·à¸à¸ªà¸³à¸«à¸£à¸±à¸šà¹‚ทรศัพท์เคลื่à¸à¸™à¸—ี่ +GenericName[tr]=Cep Telefonu Aracı +GenericName[uk]=ЗаÑіб Ð´Ð»Ñ Ð¼Ð¾Ð±Ñ–Ð»ÑŒÐ½Ð¸Ñ… телефонів +GenericName[uz]=Uyali telefon uchun vosita +GenericName[uz@cyrillic]=УÑли телефон учун воÑита +GenericName[ven]=Tshishumiswa tsha lutingo thendeleki +GenericName[vi]=Công cụ Ä‘iện thoại di Ä‘á»™ng +GenericName[xh]=Isixhobo Semfono-mfono Ekuhanjwa nayo +GenericName[zh_CN]=移动电è¯å·¥å…· +GenericName[zh_TW]=行動電話工具 +GenericName[zu]=Ithuluzi Lamakhala ekhukhwini +Terminal=false +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Utility;X-KDE-Utilities-Peripherals;Network;Telephony; diff --git a/kandy/src/kandy.h b/kandy/src/kandy.h new file mode 100644 index 000000000..ba2e66155 --- /dev/null +++ b/kandy/src/kandy.h @@ -0,0 +1,138 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KANDY_H +#define KANDY_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <kapplication.h> +#include <kmainwindow.h> + +#include "kandyview.h" + +class QPrinter; + +class KandyPrefsDialog; + +/** + * This class serves as the main window for Kandy. It handles the + * menus, toolbars, and status bars. + * + * @short Main window class + * @author Cornelius Schumacher <schumacher@kde.org> + * @version 0.1 + */ +class Kandy : public KMainWindow +{ + Q_OBJECT + public: + /** + * Default Constructor + */ + Kandy(CommandScheduler *); + + /** + * Default Destructor + */ + virtual ~Kandy(); + + /** + * Use this method to load whatever file/URL you have + */ + void load(const QString& url); + void save(const QString& url); + + public slots: + void setTitle(); + + void modemConnect(); + + void showErrorMessage( const QString & ); + + signals: + void showMobileWin(); + void connectStateChanged(bool); + + protected: + /** + * Overridden virtuals for Qt drag 'n drop (XDND) + */ + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dropEvent(QDropEvent *event); + + bool queryClose(); + + protected: + /** + * This function is called when it is time for the app to save its + * properties for session management purposes. + */ + void saveProperties(KConfig *); + + /** + * This function is called when this app is restored. The KConfig + * object points to the session management config file that was saved + * with @ref saveProperties + */ + void readProperties(KConfig *); + + + private slots: + void fileOpen(); + void fileSave(); + void fileSaveAs(); + void filePrint(); + void optionsConfigureKeys(); + void optionsConfigureToolbars(); + void optionsPreferences(); + void modemDisconnect(); + void showMobileGui(); + void newToolbarConfig(); + + void changeStatusbar(const QString& text); + void changeCaption(const QString& text); + + + private: + void setupAccel(); + void setupActions(); + + private: + CommandScheduler *mScheduler; + + KandyView *mView; + + QPrinter *mPrinter; + + KAction *mConnectAction; + KAction *mDisconnectAction; + + QString mFilename; + + KandyPrefsDialog *mPreferencesDialog; +}; + +#endif // KANDY_H diff --git a/kandy/src/kandy.kcfg b/kandy/src/kandy.kcfg new file mode 100644 index 000000000..a93f674b8 --- /dev/null +++ b/kandy/src/kandy.kcfg @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="kandyrc"/> + + <group name="Serial Port"> + <entry type="String" key="Serial Device"> + <label>Serial device</label> + <default>/dev/ttyS1</default> + </entry> + <entry type="String" key="Baud Rate"> + <label>Baud rate</label> + <default>115200</default> + </entry> + <entry type="String" key="Lock Directory"> + <label>Lock directory</label> + <default>/var/lock</default> + </entry> + <entry type="Bool" name="StartupModem"> + <label>Open modem on startup</label> + <default>false</default> + </entry> + <entry type="Bool" name="AutoSetClock"> + <label>Auto-set clock of mobile on connection</label> + <default>true</default> + </entry> + </group> + + <group name="Addressbook"> + <entry type="Bool" name="ExcludeHome"> + <label>Exclude home numbers</label> + <default>false</default> + </entry> + <entry type="Bool" name="ExcludeWork"> + <label>Exclude work numbers</label> + <default>false</default> + </entry> + <entry type="Bool" name="ExcludeMessaging"> + <label>Exclude messaging numbers</label> + <default>true</default> + </entry> + <entry type="Bool" name="ExcludeFax"> + <label>Exclude fax numbers</label> + <default>true</default> + </entry> + <entry type="Bool" name="ExcludeCell"> + <label>Exclude cell numbers</label> + <default>false</default> + </entry> + <entry type="Bool" name="ExcludeVideo"> + <label>Exclude video phone numbers</label> + <default>false</default> + </entry> + <entry type="Bool" name="ExcludeMailbox"> + <label>Exclude mailbox numbers</label> + <default>true</default> + </entry> + <entry type="Bool" name="ExcludeModem"> + <label>Exclude modem numbers</label> + <default>true</default> + </entry> + <entry type="Bool" name="ExcludeCar"> + <label>Exclude car phone numbers</label> + <default>false</default> + </entry> + <entry type="Bool" name="ExcludeISDN"> + <label>Exclude ISDN numbers</label> + <default>false</default> + </entry> + <entry type="Bool" name="ExcludePager"> + <label>Exclude pager numbers</label> + <default>true</default> + </entry> + + <entry type="Bool" name="UseHomeSuff"> + <label>Use home suffix</label> + <default>false</default> + </entry> + <entry type="Bool" name="UseWorkSuff"> + <label>Use work suffix</label> + <default>true</default> + </entry> + <entry type="Bool" name="UseMessagingSuff"> + <label>Use messaging suffix</label> + <default>false</default> + </entry> + <entry type="Bool" name="UseFaxSuff"> + <label>Use fax suffix</label> + <default>false</default> + </entry> + <entry type="Bool" name="UseCellSuff"> + <label>Use mobile suffix</label> + <default>true</default> + </entry> + <entry type="Bool" name="UseVideoSuff"> + <label>Use video suffix</label> + <default>false</default> + </entry> + <entry type="Bool" name="UseMailboxSuff"> + <label>Use mailbox suffix</label> + <default>false</default> + </entry> + <entry type="Bool" name="UseModemSuff"> + <label>Use modem suffix</label> + <default>false</default> + </entry> + <entry type="Bool" name="UseCarSuff"> + <label>Use car suffix</label> + <default>false</default> + </entry> + <entry type="Bool" name="UseISDNSuff"> + <label>Use ISDN suffix</label> + <default>false</default> + </entry> + <entry type="Bool" name="UsePagerSuff"> + <label>Use pager suffix</label> + <default>false</default> + </entry> + + <entry type="String" name="HomeSuff"> + <label>Home suffix</label> + <default></default> + </entry> + <entry type="String" name="WorkSuff"> + <label>Work suffix</label> + <default>"\"0B\""</default> + </entry> + <entry type="String" name="MessagingSuff"> + <label>Messaging suffix</label> + <default></default> + </entry> + <entry type="String" name="FaxSuff"> + <label>Fax suffix</label> + <default></default> + </entry> + <entry type="String" name="CellSuff"> + <label>Cell suffix</label> + <default>"\"17\""</default> + </entry> + <entry type="String" name="VideoSuff"> + <label>Video suffix</label> + <default></default> + </entry> + <entry type="String" name="MailboxSuff"> + <label>Mailbox suffix</label> + <default></default> + </entry> + <entry type="String" name="ModemSuff"> + <label>Modem suffix</label> + <default></default> + </entry> + <entry type="String" name="CarSuff"> + <label>Car suffix</label> + <default></default> + </entry> + <entry type="String" name="ISDNSuff"> + <label>ISDN suffix</label> + <default></default> + </entry> + <entry type="String" name="PagerSuff"> + <label>Pager suffix</label> + <default></default> + </entry> + + </group> + + <group name="Windows"> + <entry type="Bool" name="StartupTerminalWin"> + <label>Open terminal window on startup</label> + <default>false</default> + </entry> + <entry type="Bool" name="StartupMobileWin"> + <label>Open mobile window on startup</label> + <default>true</default> + </entry> + </group> + +</kcfg> diff --git a/kandy/src/kandy_client.cpp b/kandy/src/kandy_client.cpp new file mode 100644 index 000000000..ece43f5da --- /dev/null +++ b/kandy/src/kandy_client.cpp @@ -0,0 +1,48 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <kapplication.h> +#include <dcopclient.h> +#include <qdatastream.h> +#include <qstring.h> + +int main(int argc, char **argv) +{ + KApplication app(argc, argv, "kandy_client", false); + + // get our DCOP client and attach so that we may use it + DCOPClient *client = app.dcopClient(); + client->attach(); + + // do a 'send' for now + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + if (argc > 1) + ds << QString(argv[1]); + else + ds << QString("http://www.kde.org"); + client->send("kandy", "KandyIface", "openURL(QString)", data); + + return app.exec(); +} diff --git a/kandy/src/kandyiface.h b/kandy/src/kandyiface.h new file mode 100644 index 000000000..3b45bd013 --- /dev/null +++ b/kandy/src/kandyiface.h @@ -0,0 +1,39 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KANDYIFACE_H +#define KANDYIFACE_H + +#include <dcopobject.h> + +class KandyIface : virtual public DCOPObject +{ + K_DCOP + public: + + k_dcop: + virtual void syncPhonebooks() = 0; + virtual void exit() = 0; +}; + +#endif // KANDYIFACE_H diff --git a/kandy/src/kandymobileui.rc b/kandy/src/kandymobileui.rc new file mode 100644 index 000000000..aad843734 --- /dev/null +++ b/kandy/src/kandymobileui.rc @@ -0,0 +1,8 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kandy" version="1"> +<MenuBar> + <Menu name="show"><text>&Show</text> + <Action name="show_terminal" /> + </Menu> +</MenuBar> +</kpartgui> diff --git a/kandy/src/kandyprefs.kcfgc b/kandy/src/kandyprefs.kcfgc new file mode 100644 index 000000000..1be429c46 --- /dev/null +++ b/kandy/src/kandyprefs.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=kandy.kcfg +ClassName=KandyPrefs +Singleton=true +Mutators=true +#Inherits=KPimPrefs +#IncludeFiles=libkdepim/kpimprefs.h +MemberVariables=public +#GlobalEnums=true +ItemAccessors=true +SetUserTexts=true diff --git a/kandy/src/kandyprefsdialog.cpp b/kandy/src/kandyprefsdialog.cpp new file mode 100644 index 000000000..d25688ff9 --- /dev/null +++ b/kandy/src/kandyprefsdialog.cpp @@ -0,0 +1,369 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlayout.h> +#include <qlabel.h> +#include <qgroupbox.h> +#include <qbuttongroup.h> +#include <qlineedit.h> +#include <qfont.h> +#include <qslider.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qcombobox.h> +#include <qvbox.h> +#include <qhbox.h> +#include <qspinbox.h> +#include <qdatetime.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> +#include <kfontdialog.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kcolordialog.h> +#include <kiconloader.h> +#include <kiconeffect.h> + +#include "kandyprefs.h" + +#include "kandyprefsdialog.h" +#include "kandyprefsdialog.moc" + + +KandyPrefsDialog::KandyPrefsDialog(QWidget *parent, char *name, bool modal) : + KPrefsDialog(KandyPrefs::self(),parent,name,modal) +{ + setupSerialTab(); + setupAddressbookTab(); + setupWindowsTab(); +} + + +KandyPrefsDialog::~KandyPrefsDialog() +{ + delete serialDevice; + delete lockDir; + delete openOnStartup; + delete startupTerminal; + delete startupMobile; +} + +void KandyPrefsDialog::setupSerialTab() +{ + QFrame *topFrame = addPage(i18n("Serial Interface"),0, + DesktopIcon("connect_no",KIcon::SizeMedium)); + + QGridLayout *topLayout = new QGridLayout(topFrame,6,2); + topLayout->setSpacing(spacingHint()); + topLayout->setMargin(marginHint()); + + // Define serial device + serialDevice = addWidString( KandyPrefs::self()->serialDeviceItem(), + topFrame ); + topLayout->addWidget(serialDevice->label(),0,0); + topLayout->addWidget(serialDevice->lineEdit(),0,1); + + // Define baud rate + baudRate = addWidString( KandyPrefs::self()->baudRateItem(), topFrame ); + topLayout->addWidget( baudRate->label(), 1, 0 ); + topLayout->addWidget( baudRate->lineEdit(), 1, 1 ); + + // Define location of LOCK file + lockDir = addWidString( KandyPrefs::self()->lockDirectoryItem(), + topFrame ); + topLayout->addWidget(lockDir->label(),2,0); + topLayout->addWidget(lockDir->lineEdit(),2,1); + + // Define startup modem behavior + openOnStartup = addWidBool( KandyPrefs::self()->startupModemItem(), + topFrame ); + topLayout->addWidget(openOnStartup->checkBox(),3,0); + + // Define clock setting hevahior + autoSetClock = addWidBool( KandyPrefs::self()->autoSetClockItem(), + topFrame ); + topLayout->addWidget(autoSetClock->checkBox(),4,0); + + topLayout->setRowStretch(5,1); +} + +void KandyPrefsDialog::setupAddressbookTab() +{ + QFrame *topFrame = addPage(i18n("Address Book"), 0, + DesktopIcon("kaddressbook", KIcon::SizeMedium)); + + QGridLayout *topLayout = new QGridLayout(topFrame, 13, 4); + topLayout->setSpacing(spacingHint()); + topLayout->setMargin(marginHint()); + + excHome = addWidBool ( KandyPrefs::self()->excludeHomeItem(), topFrame ); + topLayout->addWidget(excHome->checkBox(), 0, 0); + + excWork = addWidBool ( KandyPrefs::self()->excludeWorkItem(), topFrame ); + topLayout->addWidget(excWork->checkBox(), 1, 0); + + excMsg = addWidBool ( KandyPrefs::self()->excludeMessagingItem(), topFrame ); + topLayout->addWidget(excMsg->checkBox(), 2, 0); + + excFax = addWidBool ( KandyPrefs::self()->excludeFaxItem(), topFrame ); + topLayout->addWidget(excFax->checkBox(), 3, 0); + + excCell = addWidBool ( KandyPrefs::self()->excludeCellItem(), topFrame ); + topLayout->addWidget(excCell->checkBox(), 4, 0); + + excVideo = addWidBool ( KandyPrefs::self()->excludeVideoItem(), topFrame ); + topLayout->addWidget(excVideo->checkBox(), 5, 0); + + excBbs = addWidBool ( KandyPrefs::self()->excludeMailboxItem(), topFrame ); + topLayout->addWidget(excBbs->checkBox(), 6, 0); + + excModem = addWidBool ( KandyPrefs::self()->excludeModemItem(), topFrame ); + topLayout->addWidget(excModem->checkBox(), 7, 0); + + excCar = addWidBool ( KandyPrefs::self()->excludeCarItem(), topFrame ); + topLayout->addWidget(excCar->checkBox(), 8, 0); + + excISDN = addWidBool ( KandyPrefs::self()->excludeISDNItem(), topFrame ); + topLayout->addWidget(excISDN->checkBox(), 9, 0); + + excPager = addWidBool ( KandyPrefs::self()->excludePagerItem(), topFrame ); + topLayout->addWidget(excPager->checkBox(), 10, 0); + + + useHomeSuff = addWidBool ( KandyPrefs::self()->useHomeSuffItem(), topFrame ); + topLayout->addWidget(useHomeSuff->checkBox(), 0, 1); + + useWorkSuff = addWidBool ( KandyPrefs::self()->useWorkSuffItem(), topFrame ); + topLayout->addWidget(useWorkSuff->checkBox(), 1, 1); + + useMessagingSuff = addWidBool ( KandyPrefs::self()->useMessagingSuffItem(), topFrame ); + topLayout->addWidget(useMessagingSuff->checkBox(), 2, 1); + + useFaxSuff = addWidBool ( KandyPrefs::self()->useFaxSuffItem(), topFrame ); + topLayout->addWidget(useFaxSuff->checkBox(), 3, 1); + + useCellSuff = addWidBool ( KandyPrefs::self()->useCellSuffItem(), topFrame ); + topLayout->addWidget(useCellSuff->checkBox(), 4, 1); + + useVideoSuff = addWidBool ( KandyPrefs::self()->useVideoSuffItem(), topFrame ); + topLayout->addWidget(useVideoSuff->checkBox(), 5, 1); + + useMailboxSuff = addWidBool ( KandyPrefs::self()->useMailboxSuffItem(), topFrame ); + topLayout->addWidget(useMailboxSuff->checkBox(), 6, 1); + + useModemSuff = addWidBool ( KandyPrefs::self()->useModemSuffItem(), topFrame ); + topLayout->addWidget(useModemSuff->checkBox(), 7, 1); + + useCarSuff = addWidBool ( KandyPrefs::self()->useCarSuffItem(), topFrame ); + topLayout->addWidget(useCarSuff->checkBox(), 8, 1); + + useISDNSuff = addWidBool ( KandyPrefs::self()->useISDNSuffItem(), topFrame ); + topLayout->addWidget(useISDNSuff->checkBox(), 9, 1); + + usePagerSuff = addWidBool ( KandyPrefs::self()->usePagerSuffItem(), topFrame ); + topLayout->addWidget(usePagerSuff->checkBox(), 10, 1); + + + HomeSuff = addWidString( KandyPrefs::self()->homeSuffItem(), topFrame ); + topLayout->addWidget(HomeSuff->label(), 0, 2); + topLayout->addWidget(HomeSuff->lineEdit(), 0, 3); + + WorkSuff = addWidString( KandyPrefs::self()->workSuffItem(), topFrame ); + topLayout->addWidget(WorkSuff->label(), 1, 2); + topLayout->addWidget(WorkSuff->lineEdit(), 1, 3); + + MessagingSuff = addWidString( KandyPrefs::self()->messagingSuffItem(), topFrame ); + topLayout->addWidget(MessagingSuff->label(), 2, 2); + topLayout->addWidget(MessagingSuff->lineEdit(), 2, 3); + + FaxSuff = addWidString( KandyPrefs::self()->faxSuffItem(), topFrame ); + topLayout->addWidget(FaxSuff->label(), 3, 2); + topLayout->addWidget(FaxSuff->lineEdit(), 3, 3); + + CellSuff = addWidString( KandyPrefs::self()->cellSuffItem(), topFrame ); + topLayout->addWidget(CellSuff->label(), 4, 2); + topLayout->addWidget(CellSuff->lineEdit(), 4, 3); + + VideoSuff = addWidString( KandyPrefs::self()->videoSuffItem(), topFrame ); + topLayout->addWidget(VideoSuff->label(), 5, 2); + topLayout->addWidget(VideoSuff->lineEdit(), 5, 3); + + MailboxSuff = addWidString( KandyPrefs::self()->mailboxSuffItem(), topFrame ); + topLayout->addWidget(MailboxSuff->label(), 6, 2); + topLayout->addWidget(MailboxSuff->lineEdit(), 6, 3); + + ModemSuff = addWidString( KandyPrefs::self()->modemSuffItem(), topFrame ); + topLayout->addWidget(ModemSuff->label(), 7, 2); + topLayout->addWidget(ModemSuff->lineEdit(), 7, 3); + + CarSuff = addWidString( KandyPrefs::self()->carSuffItem(), topFrame ); + topLayout->addWidget(CarSuff->label(), 8, 2); + topLayout->addWidget(CarSuff->lineEdit(), 8, 3); + + ISDNSuff = addWidString( KandyPrefs::self()->iSDNSuffItem(), topFrame ); + topLayout->addWidget(ISDNSuff->label(), 9, 2); + topLayout->addWidget(ISDNSuff->lineEdit(), 9, 3); + + PagerSuff = addWidString( KandyPrefs::self()->pagerSuffItem(), topFrame ); + topLayout->addWidget(PagerSuff->label(), 10, 2); + topLayout->addWidget(PagerSuff->lineEdit(), 10, 3); + + + topLayout->setRowStretch(11, 1); + + if ( !KandyPrefs::self()->useHomeSuff() ) + { + HomeSuff->lineEdit()->setEnabled( false ); + HomeSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->useWorkSuff() ) + { + WorkSuff->lineEdit()->setEnabled( false ); + WorkSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->useMessagingSuff() ) + { + MessagingSuff->lineEdit()->setEnabled( false ); + MessagingSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->useFaxSuff() ) + { + FaxSuff->lineEdit()->setEnabled( false ); + FaxSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->useCellSuff() ) + { + CellSuff->lineEdit()->setEnabled( false ); + CellSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->useVideoSuff() ) + { + VideoSuff->lineEdit()->setEnabled( false ); + VideoSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->useMailboxSuff() ) + { + MailboxSuff->lineEdit()->setEnabled( false ); + MailboxSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->useModemSuff() ) + { + ModemSuff->lineEdit()->setEnabled( false ); + ModemSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->useCarSuff() ) + { + CarSuff->lineEdit()->setEnabled( false ); + CarSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->useISDNSuff() ) + { + ISDNSuff->lineEdit()->setEnabled( false ); + ISDNSuff->label()->setEnabled( false ); + } + if ( !KandyPrefs::self()->usePagerSuff() ) + { + PagerSuff->lineEdit()->setEnabled( false ); + PagerSuff->label()->setEnabled( false ); + } + + + connect( useHomeSuff->checkBox(), SIGNAL(toggled(bool)), + HomeSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useHomeSuff->checkBox(), SIGNAL(toggled(bool)), + HomeSuff->label(), SLOT(setEnabled(bool)) ); + + connect( useWorkSuff->checkBox(), SIGNAL(toggled(bool)), + WorkSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useWorkSuff->checkBox(), SIGNAL(toggled(bool)), + WorkSuff->label(), SLOT(setEnabled(bool)) ); + + connect( useMessagingSuff->checkBox(), SIGNAL(toggled(bool)), + MessagingSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useMessagingSuff->checkBox(), SIGNAL(toggled(bool)), + MessagingSuff->label(), SLOT(setEnabled(bool)) ); + + connect( useFaxSuff->checkBox(), SIGNAL(toggled(bool)), + FaxSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useFaxSuff->checkBox(), SIGNAL(toggled(bool)), + FaxSuff->label(), SLOT(setEnabled(bool)) ); + + connect( useCellSuff->checkBox(), SIGNAL(toggled(bool)), + CellSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useCellSuff->checkBox(), SIGNAL(toggled(bool)), + CellSuff->label(), SLOT(setEnabled(bool)) ); + + connect( useVideoSuff->checkBox(), SIGNAL(toggled(bool)), + VideoSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useVideoSuff->checkBox(), SIGNAL(toggled(bool)), + VideoSuff->label(), SLOT(setEnabled(bool)) ); + + connect( useMailboxSuff->checkBox(), SIGNAL(toggled(bool)), + MailboxSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useMailboxSuff->checkBox(), SIGNAL(toggled(bool)), + MailboxSuff->label(), SLOT(setEnabled(bool)) ); + + connect( useModemSuff->checkBox(), SIGNAL(toggled(bool)), + ModemSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useModemSuff->checkBox(), SIGNAL(toggled(bool)), + ModemSuff->label(), SLOT(setEnabled(bool)) ); + + connect( useCarSuff->checkBox(), SIGNAL(toggled(bool)), + CarSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useCarSuff->checkBox(), SIGNAL(toggled(bool)), + CarSuff->label(), SLOT(setEnabled(bool)) ); + + connect( useISDNSuff->checkBox(), SIGNAL(toggled(bool)), + ISDNSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( useISDNSuff->checkBox(), SIGNAL(toggled(bool)), + ISDNSuff->label(), SLOT(setEnabled(bool)) ); + + connect( usePagerSuff->checkBox(), SIGNAL(toggled(bool)), + PagerSuff->lineEdit(), SLOT(setEnabled(bool)) ); + connect( usePagerSuff->checkBox(), SIGNAL(toggled(bool)), + PagerSuff->label(), SLOT(setEnabled(bool)) ); +} + +void KandyPrefsDialog::setupWindowsTab() +{ + QFrame *topFrame = addPage(i18n("Windows"),0, + DesktopIcon("window_list",KIcon::SizeMedium)); + + QGridLayout *topLayout = new QGridLayout(topFrame,6,2); + topLayout->setSpacing(spacingHint()); + topLayout->setMargin(marginHint()); + + startupTerminal = addWidBool( KandyPrefs::self()->startupTerminalWinItem(), + topFrame); + topLayout->addWidget(startupTerminal->checkBox(),0,0); + + startupMobile = addWidBool( KandyPrefs::self()->startupMobileWinItem(), + topFrame ); + topLayout->addWidget(startupMobile->checkBox(),1,0); + + topLayout->setRowStretch(2, 1); +} diff --git a/kandy/src/kandyprefsdialog.h b/kandy/src/kandyprefsdialog.h new file mode 100644 index 000000000..5d63331c5 --- /dev/null +++ b/kandy/src/kandyprefsdialog.h @@ -0,0 +1,102 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef _KANDYPREFSDIALOG_H +#define _KANDYPREFSDIALOG_H + +#include <qframe.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qradiobutton.h> +#include <qpushbutton.h> + +#include <kdialogbase.h> + +#include <libkdepim/kprefsdialog.h> + +/** + Dialog to change the kandy configuration. +*/ +class KandyPrefsDialog : public KPrefsDialog +{ + Q_OBJECT + public: + /** Initialize dialog and pages */ + KandyPrefsDialog(QWidget *parent=0,char *name=0,bool modal=false); + ~KandyPrefsDialog(); + + protected: + void setupSerialTab(); + void setupAddressbookTab(); + void setupWindowsTab(); + private: + KPrefsWidString *serialDevice; + KPrefsWidString *baudRate; + KPrefsWidString *lockDir; + KPrefsWidBool *openOnStartup; + KPrefsWidBool *autoSetClock; + + KPrefsWidBool *excHome; + KPrefsWidBool *excWork; + KPrefsWidBool *excMsg; + KPrefsWidBool *excFax; + KPrefsWidBool *excCell; + KPrefsWidBool *excVideo; + KPrefsWidBool *excBbs; + KPrefsWidBool *excModem; + KPrefsWidBool *excCar; + KPrefsWidBool *excISDN; + KPrefsWidBool *excPager; + + KPrefsWidBool *useHomeSuff; + KPrefsWidBool *useWorkSuff; + KPrefsWidBool *useMessagingSuff; + KPrefsWidBool *useFaxSuff; + KPrefsWidBool *useCellSuff; + KPrefsWidBool *useVideoSuff; + KPrefsWidBool *useMailboxSuff; + KPrefsWidBool *useModemSuff; + KPrefsWidBool *useCarSuff; + KPrefsWidBool *useISDNSuff; + KPrefsWidBool *usePagerSuff; + + KPrefsWidString *HomeSuff; + KPrefsWidString *WorkSuff; + KPrefsWidString *MessagingSuff; + KPrefsWidString *FaxSuff; + KPrefsWidString *CellSuff; + KPrefsWidString *VideoSuff; + KPrefsWidString *MailboxSuff; + KPrefsWidString *ModemSuff; + KPrefsWidString *CarSuff; + KPrefsWidString *ISDNSuff; + KPrefsWidString *PagerSuff; + + KPrefsWidBool *startupTerminal; + KPrefsWidBool *startupMobile; + KPrefsWidString *DisplayWidth; +}; + +#endif diff --git a/kandy/src/kandyui.rc b/kandy/src/kandyui.rc new file mode 100644 index 000000000..0555c499e --- /dev/null +++ b/kandy/src/kandyui.rc @@ -0,0 +1,8 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kandy" version="2"> +<MenuBar> + <Menu name="show"><text>&Show</text> + <Action name="show_mobilegui" /> + </Menu> +</MenuBar> +</kpartgui> diff --git a/kandy/src/kandyview.cpp b/kandy/src/kandyview.cpp new file mode 100644 index 000000000..5b9f06194 --- /dev/null +++ b/kandy/src/kandyview.cpp @@ -0,0 +1,319 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <unistd.h> + +#include <qpainter.h> +#include <qlayout.h> +#include <qhbox.h> +#include <qvbox.h> +#include <qtextedit.h> +#include <qlistview.h> +#include <qdom.h> +#include <qtextstream.h> +#include <qfile.h> +#include <qlineedit.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qpushbutton.h> + +#include <kurl.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kinputdialog.h> +#include <kdialog.h> + +#include "modem.h" +#include "cmdpropertiesdialog.h" +#include "commanditem.h" +#include "atcommand.h" +#include "commandscheduler.h" +#include "kandyprefs.h" + +#include "kandyview.h" +#include "kandyview.moc" + +KandyView::KandyView(CommandScheduler *scheduler,QWidget *parent) + : QWidget(parent) +{ + mModified = false; + mScheduler = scheduler; + + QBoxLayout *topLayout = new QVBoxLayout( this ); + + QSplitter *mainSplitter = new QSplitter( Horizontal, this ); + topLayout->addWidget( mainSplitter ); + + QWidget *commandBox = new QWidget( mainSplitter ); + + QBoxLayout *commandLayout = new QVBoxLayout( commandBox ); + commandLayout->setMargin( KDialog::marginHint() ); + commandLayout->setSpacing( KDialog::spacingHint() ); + + mCommandList = new QListView( commandBox ); + mCommandList->addColumn( i18n( "Name" ) ); + mCommandList->addColumn( i18n( "Command" ) ); + mCommandList->addColumn( i18n( "Hex" ) ); + commandLayout->addWidget( mCommandList ); + + connect( mCommandList, SIGNAL( doubleClicked(QListViewItem*) ), + SLOT( executeCommand() ) ); + + QPushButton *buttonAdd = new QPushButton( i18n("Add..."), commandBox ); + commandLayout->addWidget( buttonAdd ); + connect( buttonAdd, SIGNAL( clicked() ), SLOT( addCommand() ) ); + + QPushButton *buttonEdit = new QPushButton( i18n("Edit..."), commandBox ); + commandLayout->addWidget( buttonEdit ); + connect( buttonEdit, SIGNAL( clicked() ), SLOT( editCommand() ) ); + + QPushButton *buttonDelete = new QPushButton( i18n("Delete"), commandBox ); + commandLayout->addWidget( buttonDelete ); + connect( buttonDelete, SIGNAL( clicked() ), SLOT( deleteCommand() ) ); + + QPushButton *buttonExecute = new QPushButton( i18n("Execute"), commandBox ); + commandLayout->addWidget( buttonExecute ); + connect( buttonExecute, SIGNAL( clicked() ), SLOT( executeCommand() ) ); + + QSplitter *ioSplitter = new QSplitter( Vertical, mainSplitter ); + + QWidget *inBox = new QWidget( ioSplitter ); + + QBoxLayout *inLayout = new QVBoxLayout( inBox ); + + QLabel *inLabel = new QLabel( i18n("Input:"), inBox ); + inLabel->setMargin( 2 ); + inLayout->addWidget( inLabel ); + + mInput = new QTextEdit( inBox ); + inLayout->addWidget( mInput ); + + QWidget *outBox = new QWidget( ioSplitter ); + + QBoxLayout *outLayout = new QVBoxLayout( outBox ); + + QLabel *outLabel = new QLabel( i18n( "Output:"), outBox ); + outLabel->setMargin( 2 ); + outLayout->addWidget( outLabel ); + + mOutput = new QTextEdit( outBox ); + mOutput->setReadOnly( true ); + outLayout->addWidget( mOutput ); + + QVBox *resultBox = new QVBox( mainSplitter ); + + QLabel *resultLabel = new QLabel( i18n("Result:"), resultBox ); + resultLabel->setMargin( 2 ); + + mResultView = new QTextEdit( resultBox ); + mResultView->setReadOnly( true ); + + connect (mInput,SIGNAL(returnPressed()),SLOT(processLastLine())); + + connect(mScheduler->modem(),SIGNAL(gotLine(const char *)), + SLOT(appendOutput(const char *))); + + connect(mScheduler,SIGNAL(result(const QString &)), + mResultView,SLOT(setText(const QString &))); + connect(mScheduler,SIGNAL(commandProcessed(ATCommand *)), + SLOT(setResult(ATCommand *))); +} + +KandyView::~KandyView() +{ +} + + +void KandyView::print(QPainter *, int, int) +{ + // do the actual printing, here + // p->drawText(etc..) +} + +void KandyView::importPhonebook() +{ +#if 0 + createMobileGui(); + connect (mMobileGui,SIGNAL(phonebookRead()),mMobileGui,SLOT(writeKab())); + mMobileGui->readPhonebook(); +#endif +} + +void KandyView::slotSetTitle(const QString& title) +{ + emit signalChangeCaption(title); +} + +void KandyView::processLastLine() +{ + int para = 0; + int row = 0; + mInput->getCursorPosition( ¶, &row ); + + if ( para > 0 ) { + mLastInput = mInput->text( para - 1 ); + + kdDebug(5960) << "processLastLine(): " << mLastInput << endl; + + mScheduler->execute(mLastInput); + } +} + +void KandyView::appendOutput(const char *line) +{ +// kdDebug(5960) << "OUT: " << line << endl; + mOutput->append(line); + mOutput->setCursorPosition(mOutput->paragraphs()-1,0); +} + +void KandyView::setResult(ATCommand *command) +{ + if (command == 0) { + kdDebug(5960) << "KandyView::setResult(): Error! No command." << endl; + mResultView->setText(i18n("Error")); + return; + } + +// kdDebug(5960) << "KandyView::setResult(): " << endl << mResult << endl +// << mLastCommand->processOutput(mResult) << endl; + + mResultView->setText(command->cmdName() + ":\n" + command->processOutput()); +} + +void KandyView::addCommand() +{ + ATCommand *cmd = new ATCommand(mLastInput); + + CmdPropertiesDialog *dlg = new CmdPropertiesDialog(cmd,this,"cmdprop",true); + + int result = dlg->exec(); + + if (result == QDialog::Accepted) { + new CommandItem(mCommandList,cmd); + mScheduler->commandSet()->addCommand(cmd); + setModified(); + } else { + delete cmd; + } +} + +void KandyView::editCommand() +{ + QListViewItem *item = mCommandList->currentItem(); + if (item) { + CommandItem *cmdItem = (CommandItem *)item; + ATCommand *cmd = cmdItem->command(); + + CmdPropertiesDialog *dlg = new CmdPropertiesDialog(cmd,this,"cmdprop",true); + + int result = dlg->exec(); + + if (result == QDialog::Accepted) { + cmdItem->setItemText(); + setModified(); + } + } +} + +void KandyView::executeCommand() +{ + CommandItem *item = (CommandItem *)(mCommandList->currentItem()); + if (item) { + ATCommand *cmd = item->command(); + QPtrList<ATParameter> paraList = cmd->parameters(); + for(uint i=0;i<paraList.count();++i) { + ATParameter *p = paraList.at(i); + if (p->userInput()) { + bool ok = false; + QString value = KInputDialog::getText(QString::null, + i18n("Enter value for %1:").arg(p->name()),QString::null,&ok,this); + if (!ok) + return; + p->setValue(value); + } + } + kdDebug(5960) << "KandyView::executeCommand(): " << cmd->cmd() << endl; + mScheduler->execute(cmd); + } +} + +void KandyView::deleteCommand() +{ + CommandItem *item = dynamic_cast<CommandItem *>(mCommandList->currentItem()); + if (item) { + mScheduler->commandSet()->deleteCommand(item->command()); + delete item; + setModified(); + } +} + +bool KandyView::loadFile(const QString& filename) +{ + mCommandList->clear(); + + if (!mScheduler->loadProfile(filename)) return false; + + QPtrList<ATCommand> *cmds = mScheduler->commandSet()->commandList(); + + for(uint i=0;i<cmds->count();++i) { + new CommandItem(mCommandList,cmds->at(i)); + } + + KConfig *config = KGlobal::config(); + config->setGroup("General"); + config->writeEntry("CurrentProfile",filename); + + setModified(false); + + return true; +} + +bool KandyView::saveFile(const QString& filename) +{ + if (!mScheduler->saveProfile(filename)) return false; + + KConfig *config = KGlobal::config(); + config->setGroup("General"); + config->writeEntry("CurrentProfile",filename); + + setModified(false); + + return true; +} + +void KandyView::setModified(bool modified) +{ + if (modified != mModified) { + mModified = modified; + emit modifiedChanged(mModified); + } +} + +bool KandyView::isModified() +{ + return mModified; +} diff --git a/kandy/src/kandyview.h b/kandy/src/kandyview.h new file mode 100644 index 000000000..259ee6c78 --- /dev/null +++ b/kandy/src/kandyview.h @@ -0,0 +1,124 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KANDYVIEW_H +#define KANDYVIEW_H + +#include <qwidget.h> + +class QPainter; +class QTextStream; +class QDataStream; +class QDomDocument; +class QDomElement; +class QTextEdit; +class QListView; + +class KURL; + +class Modem; +class ATCommand; +class MobileGui; +class CommandScheduler; +class CmdPropertiesDialog; + +/** + This is the main view class for Kandy. + + @short Main view + @author Cornelius Schumacher <schumacher@kde.org> +*/ +class KandyView : public QWidget +{ + Q_OBJECT + public: + /** + * Default constructor + */ + KandyView(CommandScheduler *,QWidget *parent); + + /** + * Destructor + */ + virtual ~KandyView(); + + /** + Import phonebook from mobile phone and save it to Kab. This function + returns before the job is actually done. + */ + void importPhonebook(); + + /** + * Print this view to any medium -- paper or not + */ + void print(QPainter *, int height, int width); + + bool loadFile(const QString& filename); + bool saveFile(const QString& filename); + + void setModified(bool modified=true); + bool isModified(); + + public slots: + void addCommand(); + void executeCommand(); + void deleteCommand(); + void editCommand(); + + signals: + /** + * Use this signal to change the content of the statusbar + */ + void signalChangeStatusbar(const QString& text); + + /** + * Use this signal to change the content of the caption + */ + void signalChangeCaption(const QString& text); + + void modifiedChanged(bool); + + protected slots: + void appendOutput(const char *line); + + void setResult(ATCommand *); + + private slots: + void slotSetTitle(const QString& title); + void processLastLine(); + + private: + QString mLastInput; + + CommandScheduler *mScheduler; + + bool mModified; + + QListView *mCommandList; + + QTextEdit *mInput; + QTextEdit *mOutput; + QTextEdit *mResultView; +}; + +#endif // KANDYVIEW_H diff --git a/kandy/src/main.cpp b/kandy/src/main.cpp new file mode 100644 index 000000000..9343c1ece --- /dev/null +++ b/kandy/src/main.cpp @@ -0,0 +1,158 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qfile.h> + +#include <kapplication.h> +#include <dcopclient.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> + +#include "modem.h" +#include "kandy.h" +#include "mobilemain.h" +#include "mobilegui.h" +#include "commandscheduler.h" +#include "kandyprefs.h" + +static const char description[] = + I18N_NOOP("Communicating with your mobile phone."); + +static const char version[] = "0.5.1"; + +static KCmdLineOptions options[] = +{ + { "terminal", I18N_NOOP("Show terminal window"), 0 }, + { "mobilegui", I18N_NOOP("Show mobile GUI"), 0 }, + { "nogui", I18N_NOOP("Do not show GUI"), 0 }, + { "+[profile]", I18N_NOOP("Filename of command profile file"), 0 }, + KCmdLineLastOption // End of options. +}; + +void initModem(Modem *modem) +{ + kdDebug() << "Opening serial Device: " + << KandyPrefs::serialDevice() + << endl; + + modem->setSpeed( KandyPrefs::baudRate().toUInt() ); + modem->setData(8); + modem->setParity('N'); + modem->setStop(1); + +#if 0 + if (!modem->dsrOn()) { + KMessageBox::sorry(this, i18n("Modem is off."), i18n("Modem Error")); + modem->close(); + return; + } + if (!modem->ctsOn()) { + KMessageBox::sorry(this, i18n("Modem is busy."), i18n("Modem Error")); + modem->close(); + return; + } +#endif + +#if 0 + modem->writeLine(""); + usleep(250000); + modem->flush(); + modem->writeLine("ATZ"); +#endif +} + +int main(int argc, char **argv) +{ + KAboutData about("kandy", I18N_NOOP("Kandy"), version, description, + KAboutData::License_GPL, "(C) 2001 Cornelius Schumacher",0, + "http://kandy.kde.org/"); + about.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" ); + about.addAuthor( "Heiko Falk", 0, "hf2@ls12.cs.uni-dortmund.de" ); + KCmdLineArgs::init(argc,argv,&about); + KCmdLineArgs::addCmdLineOptions(options); + + KApplication app; + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + // register ourselves as a dcop client + app.dcopClient()->registerAs(app.name(),false); + + Modem *modem = new Modem(KandyPrefs::self()); + CommandScheduler *scheduler = new CommandScheduler(modem); + + // see if we are starting with session management + if (app.isRestored()) { + // TODO: do session management +// RESTORE(Kandy) + } else + { + // no session.. just start up normally + Kandy *k = new Kandy(scheduler); + + MobileMain *m = new MobileMain(scheduler, KandyPrefs::self()); + + if (!args->isSet("gui")) { + } else { + if (KandyPrefs::startupTerminalWin() || + args->isSet("terminal")) { + k->show(); + } + if (KandyPrefs::startupMobileWin() || + args->isSet("mobilegui")) { + m->show(); + } + } + + if (args->count() == 1) { + k->load(QFile::decodeName(args->arg(0))); + } else if (args->count() > 1) { + args->usage(); + } + + args->clear(); + + QObject::connect(k,SIGNAL(showMobileWin()),m,SLOT(show())); + QObject::connect(m,SIGNAL(showTerminalWin()),k,SLOT(show())); + QObject::connect(m,SIGNAL(showPreferencesWin()), + k,SLOT(optionsPreferences())); + + QObject::connect( m->view(), SIGNAL( connectModem() ), k, + SLOT( modemConnect() ) ); + QObject::connect( m->view(), SIGNAL( disconnectModem() ), k, + SLOT( modemDisconnect() ) ); + + QObject::connect( modem, SIGNAL( errorMessage( const QString & ) ), + k, SLOT( showErrorMessage( const QString & ) ) ); + + initModem( modem ); + + if ( KandyPrefs::startupModem() ) + m->view()->toggleConnection(); + } + + return app.exec(); +} diff --git a/kandy/src/mobilegui.cpp b/kandy/src/mobilegui.cpp new file mode 100644 index 000000000..374660902 --- /dev/null +++ b/kandy/src/mobilegui.cpp @@ -0,0 +1,1671 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <time.h> + +#include <qlabel.h> +#include <qlistview.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qmessagebox.h> + +#include <qtextedit.h> +#include <qgroupbox.h> +#include <qpushbutton.h> + +#include <kdebug.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kapplication.h> +#include <kstatusbar.h> + +#include <kabc/stdaddressbook.h> + +#include "modem.h" +#include "atcommand.h" +#include "commandscheduler.h" + +#include "mobilegui.h" +#include "mobilegui.moc" +#include "mobilemain.h" + + +class SyncEntry +{ + public: + SyncEntry() + { + mOn = true; + mToBeUpdated = false; + mToBeInserted = false; + } + + bool mOn; + bool mToBeUpdated; + bool mToBeInserted; +}; + + +class SyncEntryKab : public SyncEntry +{ + public: + SyncEntryKab( bool on, const QString &index, const QString &name, + const QString &phone ) + { + mOn = on; + + mIndex = index; + mName = name; + mPhone = phone; + + mKABindex = -1; + mPhoneNumberIndex = -1; + } + + QString mIndex; + QString mName; + QString mPhone; + + KABC::Addressee mAddressee; + int mKABindex; + int mPhoneNumberIndex; +}; + + +class SyncEntryMobile : public SyncEntry +{ + public: + SyncEntryMobile( bool on, const QString &index, const QString &phone, + const QString &name ) + { + mOn = on; + mToBeDeleted = false; + + mIndex = index; + mName = name; + mPhone = phone; + } + + QString mIndex; + QString mName; + QString mPhone; + + bool mToBeDeleted; +}; + + +class SyncEntryCommon : public SyncEntry +{ + public: + SyncEntryCommon( bool on, SyncEntryKab *kabEntry, + SyncEntryMobile *mobileEntry ) + { + mOn = on; + mKabEntry = kabEntry; + mMobileEntry = mobileEntry; + } + + SyncEntryKab *mKabEntry; + SyncEntryMobile *mMobileEntry; +}; + + +class AddressSyncer +{ + public: + AddressSyncer() + { + mKabEntries.setAutoDelete( true ); + mMobileEntries.setAutoDelete( true ); + mCommonEntries.setAutoDelete( true ); + } + + QPtrList<SyncEntryKab> mKabEntries; + QPtrList<SyncEntryMobile> mMobileEntries; + QPtrList<SyncEntryCommon> mCommonEntries; +}; + + +class PhoneBookItem : public QCheckListItem +{ + public: + PhoneBookItem( QListView *v ) : + QCheckListItem( v, "", QCheckListItem::CheckBox ) + { + mSyncEntry = 0; + } + + PhoneBookItem( QListView *v, SyncEntry *syncEntry, const QString &name, + const QString &phone, const QString &index ) : + QCheckListItem( v, index, QCheckListItem::CheckBox ) + { + mSyncEntry = syncEntry; + + setText( 0, name ); + setText( 1, phone ); + setText( 2, index ); + } + + SyncEntry *syncEntry() { return mSyncEntry; } + + private: + SyncEntry *mSyncEntry; +}; + + +/* + * Constructs a MobileGui which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +MobileGui::MobileGui( CommandScheduler *scheduler, KandyPrefs *kprefs, + QWidget* parent, const char* name, WFlags fl ) : + DCOPObject( "KandyIface" ), MobileGui_base( parent, name, fl ) +{ + // Setup links to related classes + mScheduler = scheduler; + mSyncer = new AddressSyncer; + mPrefs = kprefs; + mparent = parent; + + // Setup mobile phone specific data + mMobManufacturer = ""; + mMobModel = ""; + mPBStartIndex = 0; + mPBLength = 0; + mPBNameLength = 0; + mPBIndexOccupied.resize( 0, false ); + mMobHasFD = false; + mMobHasLD = false; + mMobHasME = false; + mMobHasMT = false; + mMobHasTA = false; + mMobHasOW = false; + mMobHasMC = false; + mMobHasRC = false; + + // Setup status for asynchronous control flow + mLastWriteId = ""; + mComingFromToggleConnection = false; + mComingFromReadPhonebook = false; + mComingFromSyncPhonebooks = false; + mComingFromExit = false; + + // Setup initial state of phone books + setKabState( UNLOADED ); + setMobState( UNLOADED ); + + // Setup signal handlers + connect( mScheduler, SIGNAL( commandProcessed( ATCommand * ) ), + SLOT( processResult( ATCommand * ) ) ); + connect( mScheduler->modem(), SIGNAL( gotLine( const char * ) ), + SLOT( termAddOutput( const char * ) ) ); +} + + +MobileGui::~MobileGui() +{ + delete mSyncer; +} + + +void MobileGui::exit() +{ + warnKabState( UNLOADED ); + + mComingFromExit = true; + if ( !warnMobState( UNLOADED ) ) { + mComingFromExit = false; + kapp->quit(); + } +} + + +void MobileGui::readModelInformation() +{ + // Read generic manufacturer and model information + mScheduler->executeId( "+cgmi" ); + mScheduler->executeId( "+cgmm" ); + mScheduler->executeId( "+cgmr" ); + mScheduler->executeId( "+cgsn" ); + + // Read information about additional phonebook memories + ATCommand *cmd = new ATCommand( "+cpbs=?" ); + cmd->setAutoDelete( true ); + mScheduler->execute( cmd ); + + // Select SIM phonebook by default + cmd = new ATCommand( "+cpbs=" ); + cmd->setAutoDelete( true ); + cmd->addParameter( new ATParameter( "SM" ) ); + mScheduler->execute( cmd ); + + // Read phonebook properties + mScheduler->executeId( "+cpbr=?" ); + mScheduler->executeId( "+cpbs?" ); + + // Set clock + if ( (*mPrefs).autoSetClock() ) + setClock(); +} + + +void MobileGui::readPhonebook() +{ + if ( mMobState == LOADED ) + return; + + mComingFromReadPhonebook = true; + if ( !warnMobState( LOADED ) ) { + mComingFromReadPhonebook = false; + QString tmp = ""; + + ATCommand *cmd = new ATCommand( "+cpbr=" ); + cmd->setAutoDelete( true ); + cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex ) ) ); + cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex + + mPBLength - 1 ) ) ); + + mScheduler->execute( cmd ); + + emit statusMessage( i18n( "Reading mobile phonebook..." ) ); + } +} + + +void MobileGui::writePhonebook() +{ + bool ModemCommandScheduled = false; + + + if ( mMobState != MODIFIED ) + return; + + PushButton12->setEnabled( false ); + + + // + // Remove all entries from data structures which are marked as + // deleted but which are not found on the mobile phone + // + + for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) { + SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i ); + + + if ( entry->mToBeDeleted ) + if ( entry->mIndex.isEmpty() ) { + // The current entry has to be deleted but doesn't come from + // the mobile phone. Hence, it was inserted during phonebook + // synchronisation or so. + // => It is sufficient to remove it from mMobileEntries, no + // ATCommand for deletion needs to be scheduled. + mSyncer->mMobileEntries.remove( i ); + i--; + } else { + // The current entry has to be deleted and stems from the + // mobile phone. First thing to do is to free its associated + // index. This way, its index can be reused for entries which + // have be newly inserted to the mobile phone and we can save + // an explicit ATCommand for deletion and save time & battery + // energy. + uint theIndex = entry->mIndex.toUInt(); + mPBIndexOccupied[ theIndex - mPBStartIndex ] = false; + } + } + + + // + // Write all elements which need an update to the mobile phone + // + + for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) { + SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i ); + QString id; + + + // Only process changed items of the mobile phonebook in + // order to save time. + if ( entry->mToBeUpdated || entry->mToBeInserted ) { + QString tmp = ""; + + + if ( entry->mToBeUpdated ) { + id = "+cpbw=" + entry->mIndex; + } else { + int index = firstFreeIndex(); + + + mPBIndexOccupied[ index ] = true; + id = "+cpbw=" + tmp.setNum( index + mPBStartIndex ); + } + mLastWriteId = id; + entry->mToBeUpdated = false; + entry->mToBeInserted = false; + + ATCommand *cmd = new ATCommand( id ); + cmd->setAutoDelete( true ); + cmd->addParameter( new ATParameter( quote( entry->mPhone ) ) ); + + if ( entry->mPhone.left( 1 ) == "+" ) + cmd->addParameter( new ATParameter( "145" ) ); + else + cmd->addParameter( new ATParameter( "129" ) ); + + cmd->addParameter( new ATParameter( + quote( string2GSM( entry->mName ) ) ) ); + + mScheduler->execute( cmd ); + ModemCommandScheduled = true; + } + } + + + // + // As a final step, we need to check again all entries which should be + // deleted. If entries exist stemming from the mobile phone and whose + // index-position was not reused for updating or inserting other entries in + // the previous loop, we need to issue an explicit ATCommand for its deletion. + // + + for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) { + SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i ); + + + if ( entry->mToBeDeleted ) { + uint theIndex = entry->mIndex.toUInt(); + + + if ( !mPBIndexOccupied[ theIndex - mPBStartIndex ] ) { + // Index of item to be deleted still is 0, so that index position + // wasn't reused. We must delete it explicitly. + QString id = "+cpbw=" + entry->mIndex; + + + mLastWriteId = id; + ATCommand *cmd = new ATCommand( id ); + cmd->setAutoDelete( true ); + + mScheduler->execute( cmd ); + ModemCommandScheduled = true; + } + + // Remove entry from internal data structures + mSyncer->mMobileEntries.remove( i ); + i--; + } + } + + if ( ModemCommandScheduled ) + emit statusMessage( i18n( "Writing mobile phonebook..." ) ); + else + writePhonebookPostProcessing(); +} + + +void MobileGui::writePhonebookPostProcessing() +{ + mLastWriteId = ""; + emit transientStatusMessage( i18n( "Wrote mobile phonebook." ) ); + PushButton12->setEnabled( true ); + setMobState( LOADED ); + updateMobileBook(); + + if ( mComingFromToggleConnection ) { + mComingFromToggleConnection = false; + disconnectGUI(); + } else + if ( mComingFromReadPhonebook ) { + mComingFromReadPhonebook = false; + QString tmp = ""; + + ATCommand *cmd = new ATCommand( "+cpbr=" ); + cmd->setAutoDelete( true ); + cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex ) ) ); + cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex + + mPBLength - 1 ) ) ); + + mScheduler->execute( cmd ); + + emit statusMessage( i18n( "Reading mobile phonebook..." ) ); + } else + if ( mComingFromExit ) { + mComingFromExit = false; + kapp->quit(); + } +} + + +void MobileGui::setClock() +{ + char *timeStr = new char[50]; + QString id = "+cclk="; + ATCommand *cmd = new ATCommand( id ); + + + cmd->setAutoDelete( true ); + + time_t tloc; + time( &tloc ); + struct tm *theTime = localtime( &tloc ); + strftime( timeStr, 50, "%y/%m/%d,%T+00", theTime ); + + QString Time = timeStr; + cmd->addParameter( new ATParameter( quote( Time ) ) ); + + mScheduler->execute( cmd ); + + delete[] timeStr; +} + + +void MobileGui::readKabc() +{ + if ( mKabState == LOADED ) + return; + + warnKabState( LOADED ); + + emit statusMessage( i18n( "Reading KDE address book..." ) ); + + mSyncer->mKabEntries.clear(); + + KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true ); + KABC::AddressBook::Iterator it; + int kabIndex = 0; + + for ( it = addressBook->begin(); it != addressBook->end(); + it++, kabIndex++ ) { + QString index, name; + KABC::PhoneNumber phoneNumber; + KABC::PhoneNumber::List phoneNumbers = (*it).phoneNumbers(); + KABC::PhoneNumber::List::Iterator it2; + int phoneNumberIndex = 0; + + + // Scan all numbers associated with a KAB entry + for ( it2 = phoneNumbers.begin(); it2 != phoneNumbers.end(); + it2++, phoneNumberIndex++ ) { + bool excludeNumber = false; + phoneNumber = (*it2); + QString phone = phoneNumber.number(); + + + if ( (*mPrefs).excludeHome() && + ( phoneNumber.type() & KABC::PhoneNumber::Home ) ) + excludeNumber = true; + if ( (*mPrefs).excludeWork() && + ( phoneNumber.type() & KABC::PhoneNumber::Work ) ) + excludeNumber = true; + if ( (*mPrefs).excludeMessaging() && + ( phoneNumber.type() & KABC::PhoneNumber::Msg ) ) + excludeNumber = true; + if ( (*mPrefs).excludeFax() && + ( phoneNumber.type() & KABC::PhoneNumber::Fax ) ) + excludeNumber = true; + if ( (*mPrefs).excludeCell() && + ( phoneNumber.type() & KABC::PhoneNumber::Cell ) ) + excludeNumber = true; + if ( (*mPrefs).excludeVideo() && + ( phoneNumber.type() & KABC::PhoneNumber::Video ) ) + excludeNumber = true; + if ( (*mPrefs).excludeMailbox() && + ( phoneNumber.type() & KABC::PhoneNumber::Bbs ) ) + excludeNumber = true; + if ( (*mPrefs).excludeModem() && + ( phoneNumber.type() & KABC::PhoneNumber::Modem ) ) + excludeNumber = true; + if ( (*mPrefs).excludeCar() && + ( phoneNumber.type() & KABC::PhoneNumber::Car ) ) + excludeNumber = true; + if ( (*mPrefs).excludeISDN() && + ( phoneNumber.type() & KABC::PhoneNumber::Isdn ) ) + excludeNumber = true; + if ( (*mPrefs).excludePager() && + ( phoneNumber.type() & KABC::PhoneNumber::Pager ) ) + excludeNumber = true; + + if ( excludeNumber == false ) { + SyncEntryKab *kabEntry; + + + index = ""; + name = (*it).familyName(); + + KABC::AddressBook::Iterator it3; + KABC::Addressee::List tmp; + bool firstCharIsUnique = true; + for ( it3 = addressBook->begin(); it3 != addressBook->end(); ++it3 ) + if ( ( (*it3).familyName() == name ) && ( it3 != it ) ) { + tmp.append( (*it3) ); + if ( (*it3).givenName()[0] == (*it).givenName()[0] ) + firstCharIsUnique = false; + } + + // There are several KAB entries with the same family name. + // So, we need to append the given name in order to + // distinguish them. + if ( ( tmp.size() > 0 ) && !(*it).givenName().isEmpty() ) { + name += ", "; + + if ( firstCharIsUnique ) + name += (*it).givenName()[0] + "."; + else + name += (*it).givenName(); + } + + // Truncate name field if it's too long for mobile phone + if ( name.length() > mPBNameLength ) + name = name.remove( mPBNameLength, name.length() - mPBNameLength ); + + // Append Suffix to name if specified in preferences + if ( (*mPrefs).useHomeSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Home ) ) + formatPBName( &name, (*mPrefs).homeSuff() ); + else + if ( (*mPrefs).useWorkSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Work ) ) + formatPBName( &name, (*mPrefs).workSuff() ); + else + if ( (*mPrefs).useMessagingSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Msg ) ) + formatPBName( &name, (*mPrefs).messagingSuff() ); + else + if ( (*mPrefs).useFaxSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Fax ) ) + formatPBName( &name, (*mPrefs).faxSuff() ); + else + if ( (*mPrefs).useCellSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Cell ) ) + formatPBName( &name, (*mPrefs).cellSuff() ); + else + if ( (*mPrefs).useVideoSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Video ) ) + formatPBName( &name, (*mPrefs).videoSuff() ); + else + if ( (*mPrefs).useMailboxSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Bbs ) ) + formatPBName( &name, (*mPrefs).mailboxSuff() ); + else + if ( (*mPrefs).useModemSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Modem ) ) + formatPBName( &name, (*mPrefs).modemSuff() ); + else + if ( (*mPrefs).useCarSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Car ) ) + formatPBName( &name, (*mPrefs).carSuff() ); + else + if ( (*mPrefs).useISDNSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Isdn ) ) + formatPBName( &name, (*mPrefs).iSDNSuff() ); + else + if ( (*mPrefs).usePagerSuff() && + ( phoneNumber.type() & KABC::PhoneNumber::Pager ) ) + formatPBName( &name, (*mPrefs).pagerSuff() ); + + kabEntry = new SyncEntryKab( true, index, name, phone ); + kabEntry->mKABindex = kabIndex; + kabEntry->mPhoneNumberIndex = phoneNumberIndex; + + kabEntry->mAddressee = (*it); + mSyncer->mKabEntries.append( kabEntry ); + } + } + } + + // Display KAB entries + updateKabBook(); + + emit transientStatusMessage( i18n( "Read KDE address book." ) ); + + setKabState( LOADED ); +} + + +QString MobileGui::decodeSuffix( const QString &suffix ) +{ + QString theSuffix = suffix; + + + // Check whether suffix is quoted. If so, it should be interpreted + // as Hex-Number of a special GSM character. + if ( ( theSuffix.left( 1 ) == "\"" ) && ( theSuffix.right( 1 ) == "\"" ) ) { + QString tmp = ""; + char suffixNumber = (char) dequote( suffix ).toUInt( 0, 16 ); + tmp += suffixNumber; + + theSuffix = GSM2String( tmp ); + } + + return theSuffix; +} + + +void MobileGui::formatPBName( QString *name, QString suffix ) +{ + QString theSuffix = decodeSuffix( suffix ); + + + if ( name->length() + theSuffix.length() > mPBNameLength ) { + // Truncate name field if it's too long for mobile phone + unsigned int toolong = name->length() + theSuffix.length() - mPBNameLength; + (*name) = name->remove( name->length() - toolong, toolong ); + } else + if ( name->length() + theSuffix.length() < mPBNameLength ) + // Add white spaces so that suffix is right justified + while ( name->length() + theSuffix.length() != mPBNameLength ) + (*name) += ' '; + + (*name) += theSuffix; +} + + +QString MobileGui::stripWhiteSpaces( const QString &theString ) +{ + int pos = 0; + int len = theString.length(); + + + for ( unsigned int i = 0; i < theString.length(); i++ ) + if ( theString[ i ].latin1() == ' ' ) { + pos++; + len--; + } else + break; + + if ( len == 0 ) + return ""; + + for ( int i = theString.length() - 1; i >= 0; i-- ) + if ( theString[ i ].latin1() == ' ' ) + len--; + else + break; + + return theString.mid( pos, len ); +} + + +void MobileGui::writeKabc() +{ + if ( mKabState != MODIFIED ) + return; + + KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true ); + KABC::Ticket *ticket = addressBook->requestSaveTicket(); + + if ( !ticket ) { + kdDebug() << "Error! No ticket to save." << endl; + return; + } + + + for ( uint i = 0; i < mSyncer->mKabEntries.count(); i++ ) { + SyncEntryKab *kabEntry = mSyncer->mKabEntries.at( i ); + QString phoneNumber = kabEntry->mPhone; + + + if ( kabEntry->mToBeUpdated ) { + // Find the entry in the KAB which has to be updated + KABC::AddressBook::Iterator it = addressBook->begin(); + for ( int KABindex = 0; KABindex != kabEntry->mKABindex; + it++, KABindex++ ) ; + + // Find the correct phonenumber of the phonebook entry + KABC::PhoneNumber::List phoneNumbers = (*it).phoneNumbers(); + KABC::PhoneNumber::List::Iterator it2 = phoneNumbers.begin(); + for ( int phoneNumberIndex = 0; + phoneNumberIndex != kabEntry->mPhoneNumberIndex; + it2++, phoneNumberIndex++ ) ; + + (*it2).setNumber( phoneNumber ); + (*it).insertPhoneNumber( (*it2) ); + } else + + if ( kabEntry->mToBeInserted ) { + int phoneType = 0; + bool goon = true; + KABC::AddressBook::Iterator it; + bool equivalentEntryFound = false; + QString name = kabEntry->mName; + + + // + // Identify Type of Phonenumber using possibly appended suffixes. + // If a suffix is found, remove it from the name. + // + if ( goon && (*mPrefs).useHomeSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).homeSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Home; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).useWorkSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).workSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Work; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).useMessagingSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).messagingSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Msg; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).useFaxSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).faxSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Fax; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).useCellSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).cellSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Cell; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).useVideoSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).videoSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Video; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).useMailboxSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).mailboxSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Bbs; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).useModemSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).modemSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Modem; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).useCarSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).carSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Car; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).useISDNSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).iSDNSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Isdn; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + if ( goon && (*mPrefs).usePagerSuff() ) { + QString theSuffix = decodeSuffix( (*mPrefs).pagerSuff() ); + if ( name.right( theSuffix.length() ) == theSuffix ) { + phoneType = KABC::PhoneNumber::Pager; + name = stripWhiteSpaces( + name.left( name.length() - theSuffix.length() ) ); + goon = false; + } + } + + + // + // Search for a KAB entry whose name, if formatted in exactly the + // same way as was done in readKabc, is equal to the actual name. + // + + for ( it = addressBook->begin(); it != addressBook->end(); it++ ) { + QString kabName = (*it).familyName(); + KABC::AddressBook::Iterator it3; + KABC::Addressee::List tmp; + bool firstCharIsUnique = true; + unsigned int minLength; + + + for ( it3 = addressBook->begin(); it3 != addressBook->end(); it3++ ) + if ( ( (*it3).familyName() == kabName ) && ( it3 != it ) ) { + tmp.append( (*it3) ); + if ( (*it3).givenName()[0] == (*it).givenName()[0] ) + firstCharIsUnique = false; + } + + // There are several KAB entries with the same family name. + // So, we need to append the given name in order to + // distinguish them. + if ( ( tmp.size() > 0 ) && !(*it).givenName().isEmpty() ) { + kabName += ", "; + + if ( firstCharIsUnique ) + kabName += (*it).givenName()[0] + "."; + else + kabName += (*it).givenName(); + } + + // Truncate name field if it's too long for mobile phone + if ( kabName.length() > mPBNameLength ) + kabName = kabName.remove( mPBNameLength, + kabName.length() - mPBNameLength ); + + minLength = kabName.length(); + if ( name.length() < minLength ) + minLength = name.length(); + + if ( name.left( minLength ) == kabName.left( minLength ) ) { + (*it).insertPhoneNumber( KABC::PhoneNumber( phoneNumber, + phoneType ) ); + + equivalentEntryFound = true; + break; + } + } + + // + // If no equivalent entry was found in KAB, we need to generate + // a complete new entry. + // + + if ( !equivalentEntryFound ) { + KABC::Addressee entry; + QStringList *fields = new QStringList; + + + *fields = QStringList::split( ',', name ); + + if ( fields->count() > 1 ) { + // Name string contains comma separated entry so that we + // need to build family and given names out of them. + QString givenName = ""; + + + entry.setFamilyName( stripWhiteSpaces( (*fields)[ 0 ] ) ); + + for ( unsigned int i = 1; i < fields->count(); i++ ) + givenName += stripWhiteSpaces( (*fields)[ i ] ) + " "; + entry.setGivenName( stripWhiteSpaces( givenName ) ); + } else + // Name string contains only one string without comma. + entry.setFamilyName( stripWhiteSpaces( name ) ); + + entry.insertPhoneNumber( KABC::PhoneNumber( phoneNumber, phoneType ) ); + + addressBook->insertAddressee( entry ); + } + } + + kabEntry->mToBeUpdated = false; + kabEntry->mToBeInserted = false; + } + + addressBook->save( ticket ); + + emit transientStatusMessage( i18n( "Wrote KDE address book." ) ); + + setKabState( LOADED ); +} + + +void MobileGui::refreshStatus() +{ + mScheduler->executeId( "+cbc" ); + mScheduler->executeId( "+csq" ); +} + + +void MobileGui::processResult( ATCommand *command ) +{ + if ( command->id() == "+cbc" ) + mBatteryChargeLabel->setText( command->resultField( 1 ) + " %" ); + else + if ( command->id() == "+csq" ) + mSignalQualityLabel->setText( command->resultField( 0 ) ); + else + if ( command->id() == "+cgmi" ) { + mMobManufacturer = command->resultField( 0 ); + mManufacturerLabel->setText( mMobManufacturer ); + } else + if ( command->id() == "+cgmm" ) { + mMobModel = command->resultField( 0 ); + mModelLabel->setText( mMobModel ); + } else + if ( command->id() == "+cgmr" ) + mGSMVersionLabel->setText( command->resultField( 0 ) ); + else + if ( command->id() == "+cgsn" ) + mSerialNumberLabel->setText( command->resultField( 0 ) ); + else + if ( command->id() == "+cpbr=?" ) + { + QStringList tmpList = QStringList::split( "-", command->resultField( 0 ) ); + QString tmpString = tmpList.first().right( tmpList.first().length() - 1 ); + mPBStartIndex = tmpString.toUInt(); + mPBNameLength = command->resultField( 2 ).toUInt(); + } else + if ( command->id() == "+cpbs?" ) { + mPBLength = command->resultField( 2 ).toUInt(); + + // Allocate and initialize memory for the buckets of indices + mPBIndexOccupied.resize( mPBLength, false ); + for ( unsigned int i = 0; i < mPBLength; i++ ) + mPBIndexOccupied[ i ] = false; + } else + if ( command->id() == "+cpbr=" ) { + fillPhonebook( command ); + + if ( mComingFromSyncPhonebooks ) { + mComingFromSyncPhonebooks = false; + mergePhonebooks(); + } + } else + if ( command->id() == mLastWriteId ) + writePhonebookPostProcessing(); + else + if ( command->id() == "+cpbs=?" ) { + QPtrList<QStringList> *list = command->resultFields(); + QStringList *fields = list->first(); + + + while( fields ) { + for ( unsigned int i = 0; i < fields->count(); i++ ) { + QString memory = dequote( (*fields)[ i ] ); + + + if ( memory == "FD" ) + mMobHasFD = true; + else + if ( memory == "LD" ) + mMobHasLD = true; + else + if ( memory == "ME" ) + mMobHasME = true; + else + if ( memory == "MT" ) + mMobHasMT = true; + else + if ( memory == "TA" ) + mMobHasTA = true; + else + if ( ( memory == "OW" ) || + ( ( memory == "ON" ) && ( mMobManufacturer == "SIEMENS" ) ) ) + mMobHasOW = true; + else + if ( ( mMobManufacturer == "SIEMENS" ) && ( memory == "MC" ) ) + mMobHasMC = true; + else + if ( ( mMobManufacturer == "SIEMENS" ) && ( memory == "RC" ) ) + mMobHasRC = true; + } + + fields = list->next(); + } + } +} + + +QString MobileGui::noSpaces( const QString &theString ) +{ + QString result = ""; + + + for ( unsigned int i = 0; i < theString.length(); i++ ) + if ( theString[ i ].latin1() != ' ' ) + result += theString[ i ]; + + return result; +} + + +int MobileGui::firstFreeIndex() +{ + unsigned int i; + + + if ( mPBIndexOccupied.capacity() == 0 ) + return 0; + + for ( i = 1; i < mPBLength; i++ ) + if ( !mPBIndexOccupied[ i ] ) + break; + + if ( i < mPBLength ) + return i; + + return 0; +} + + +QString MobileGui::string2GSM( const QString &theString ) +{ + QString result = ""; + + + for ( unsigned int i = 0; i < theString.length(); i++ ) + switch ( theString[ i ].latin1() ) { + case 'Ä': result += '['; break; + case 'ä': result += '{'; break; + case 'Ö': result += 92; break; + case 'ö': result += '|'; break; + case 'Ü': result += '^'; break; + case 'ü': result += '~'; break; + case 'ß': result += 30; break; + case 'è': result += 4; break; + case 'é': result += 5; break; + + default: result += theString[ i ]; + } + + return result; +} + + +QString MobileGui::GSM2String( const QString &theString ) +{ + QString result = ""; + + + for ( unsigned int i = 0; i < theString.length(); i++ ) + switch ( theString[ i ].latin1() ) { + case '[': result += 'Ä'; break; + case '{': result += 'ä'; break; + case 92: result += 'Ö'; break; + case '|': result += 'ö'; break; + case '^': result += 'Ü'; break; + case '~': result += 'ü'; break; + case 30: result += 'ß'; break; + case 4: result += 'è'; break; + case 5: result += 'é'; break; + + default: result += theString[ i ]; + } + + return result; +} + + +void MobileGui::fillPhonebook( ATCommand *cmd ) +{ + mSyncer->mMobileEntries.clear(); + + QPtrList<QStringList> *list = cmd->resultFields(); + QStringList *fields = list->first(); + + while( fields ) { + if ( fields->count() != 4 ) + kdDebug() << "Error! Unexpected number of address fields." << endl; + else { + QString index = (*fields)[0]; + QString phone = (*fields)[1]; + QString type = (*fields)[2]; + QString name = GSM2String( (*fields)[3] ); + + SyncEntryMobile *phoneEntry = new SyncEntryMobile( true, dequote( index ), + dequote( phone ), + dequote( name ) ); + mPBIndexOccupied[ index.toUInt() - mPBStartIndex ] = true; + mSyncer->mMobileEntries.append( phoneEntry ); + } + fields = list->next(); + } + + // Display mobile entries + updateMobileBook(); + + emit transientStatusMessage(i18n("Read mobile phonebook.")); + emit phonebookRead(); + + setMobState( LOADED ); +} + + +QString MobileGui::quote( const QString &str ) +{ + if ( ( str.left(1) == "\"" ) && ( str.right(1) == "\"" ) ) + return str; + + return "\"" + str + "\""; +} + + +QString MobileGui::dequote( const QString &str ) +{ + int pos = 0; + int len = str.length(); + + + if ( str.left(1) == "\"" ) { + pos = 1; + len --; + } + + if ( str.right(1) == "\"" ) + len--; + + return str.mid( pos, len ); +} + + +void MobileGui::savePhonebook() +{ + if ( mMobState == UNLOADED ) + return; + + QString fileName = KFileDialog::getSaveFileName( "phonebook.csv" ); + QFile outFile( fileName ); + + if ( outFile.open( IO_WriteOnly ) ) { + QTextStream t( &outFile ); // use a text stream + + for( uint i = 0; i < mSyncer->mMobileEntries.count(); i++) { + SyncEntryMobile *e = mSyncer->mMobileEntries.at( i ); + + + if ( !e->mToBeDeleted ) + t << e->mIndex << "," << e->mPhone << "," << e->mName << endl; + } + + outFile.close(); + } +} + + +void MobileGui::deleteMobPhonebook() +{ + + // + // Process all elements selected in the GUI + // + + PhoneBookItem *item = (PhoneBookItem *) mMobileBook->firstChild(); + while ( item ) { + if ( item->isOn() ) { + SyncEntryMobile *mobileItem = (SyncEntryMobile *) item->syncEntry(); + + + // Deselect current item + item->setOn( false ); + mobileItem->mOn = false; + + // Mark current item as deleted + mobileItem->mToBeDeleted = true; + } + + item = (PhoneBookItem *) item->nextSibling(); + } + + // Update GUI + updateMobileBook(); + setMobState( MODIFIED ); +} + + +void MobileGui::mergePhonebooks() +{ + uint i; + + + // + // Transfer current Selection State from GUI to mSyncer + // + + PhoneBookItem *item = (PhoneBookItem *) mKabBook->firstChild(); + while ( item ) { + item->syncEntry()->mOn = item->isOn(); + item = (PhoneBookItem *) item->nextSibling(); + } + + item = (PhoneBookItem *) mMobileBook->firstChild(); + while ( item ) { + item->syncEntry()->mOn = item->isOn(); + item = (PhoneBookItem *) item->nextSibling(); + } + + mSyncer->mCommonEntries.clear(); + + + // + // Put KDE Address Book list into Common List + // + + for ( i = 0; i < mSyncer->mKabEntries.count(); i++ ) + if ( mSyncer->mKabEntries.at( i )->mOn ) { + mSyncer->mCommonEntries.append( + new SyncEntryCommon( true, mSyncer->mKabEntries.at( i ), 0 ) ); + mSyncer->mKabEntries.at( i )->mOn = false; + } + + + // + // Put Mobile Address Book list into Common List; Merge equivalent entries + // + + for ( i = 0; i < mSyncer->mMobileEntries.count(); i++ ) { + SyncEntryMobile *mobileEntry = mSyncer->mMobileEntries.at( i ); + bool equivalentEntryFound = false; + uint j; + + + if( !mobileEntry->mToBeDeleted ) + for ( j = 0; j < mSyncer->mCommonEntries.count(); j++ ) { + SyncEntryCommon *theCommonEntry = mSyncer->mCommonEntries.at( j ); + + + if ( theCommonEntry->mKabEntry && + ( theCommonEntry->mKabEntry->mName == mobileEntry->mName ) ) { + theCommonEntry->mMobileEntry = mobileEntry; + equivalentEntryFound = true; + + if ( noSpaces( theCommonEntry->mKabEntry->mPhone ) == + mobileEntry->mPhone ) { + mobileEntry->mOn = false; + break; + } else { + // Conflict: 2 Entries have same name but different numbers. + // Prompt user. + QString text = "<qt><b>" + i18n( "Kab Entry:" ) + "</b><br>"; + text += " " + theCommonEntry->mKabEntry->mName + " " + + theCommonEntry->mKabEntry->mPhone + "<br>"; + text += "<b>" + i18n( "Mobile Entry:" ) + "</b><br>"; + text += " " + mobileEntry->mName + " " + mobileEntry->mPhone; + text += "</qt>"; + + QMessageBox *msg = + new QMessageBox( i18n( "Conflicting Entries" ), text, + QMessageBox::Warning, 1, 2, 0, this ); + msg->setButtonText( 1, i18n( "Use Kab Entry" ) ); + msg->setButtonText( 2, i18n( "Use Mobile Entry" ) ); + + switch ( msg->exec() ) { + case 1: + // Use KDE Address Book Entry + mobileEntry->mPhone = theCommonEntry->mKabEntry->mPhone; + mobileEntry->mName = theCommonEntry->mKabEntry->mName; + mobileEntry->mOn = true; + mobileEntry->mToBeUpdated = true; + + setMobState( MODIFIED ); + break; + + case 2: + // Use Mobile Address Book Entry + theCommonEntry->mKabEntry->mPhone = mobileEntry->mPhone; + theCommonEntry->mKabEntry->mName = mobileEntry->mName; + theCommonEntry->mKabEntry->mOn = true; + theCommonEntry->mKabEntry->mToBeUpdated = true; + + mobileEntry->mOn = false; + + setKabState( MODIFIED ); + break; + } + } + } + } + + if ( !equivalentEntryFound && mobileEntry->mOn ) { + // No equivalent entry exists; generate a new one. + mSyncer->mCommonEntries.append( + new SyncEntryCommon( true, 0, mobileEntry ) ); + mobileEntry->mOn = false; + } + } + + + // + // Create new KAB and Mobile Entries + // + + for ( i = 0; i < mSyncer->mCommonEntries.count(); i++ ) { + SyncEntryCommon *entry = mSyncer->mCommonEntries.at( i ); + SyncEntryKab *kabEntry = entry->mKabEntry; + SyncEntryMobile *mobileEntry = entry->mMobileEntry; + + + if ( kabEntry && !mobileEntry ) { + // Create Mobile Entry + entry->mMobileEntry = new SyncEntryMobile( true, "", kabEntry->mPhone, + kabEntry->mName ); + entry->mMobileEntry->mToBeInserted = true; + mSyncer->mMobileEntries.append( entry->mMobileEntry ); + + setMobState( MODIFIED ); + } else + if ( mobileEntry && !kabEntry ) { + // Create KAB Entry + entry->mKabEntry = new SyncEntryKab( true, mobileEntry->mIndex, + mobileEntry->mName, + mobileEntry->mPhone ); + entry->mKabEntry->mToBeInserted = true; + mSyncer->mKabEntries.append( entry->mKabEntry ); + + setKabState( MODIFIED ); + } + } + + + // + // Update GUI + // + + updateKabBook(); + updateMobileBook(); + + emit transientStatusMessage( i18n( "Synced phonebooks." ) ); + PushButton8_3->setEnabled( true ); +} + + +void MobileGui::syncPhonebooks() +{ + PushButton8_3->setEnabled( false ); + + if ( mKabState == UNLOADED ) + readKabc(); + if ( mMobState == UNLOADED ) { + mComingFromSyncPhonebooks = true; + readPhonebook(); + } else + mergePhonebooks(); +} + + +void MobileGui::updateKabBook() +{ + mKabBook->clear(); + + for ( uint i = 0; i < mSyncer->mKabEntries.count(); i++ ) { + SyncEntryKab *kabEntry = mSyncer->mKabEntries.at( i ); + PhoneBookItem *item = new PhoneBookItem( mKabBook, kabEntry, + kabEntry->mName, kabEntry->mPhone, + kabEntry->mIndex ); + item->setOn( kabEntry->mOn ); + } +} + + +void MobileGui::updateMobileBook() +{ + mMobileBook->clear(); + + for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) { + SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i ); + + if ( !entry->mToBeDeleted ) { + PhoneBookItem *item = new PhoneBookItem( mMobileBook, entry, entry->mName, + entry->mPhone, entry->mIndex ); + item->setOn( entry->mOn ); + } + } +} + + +void MobileGui::toggleConnection() +{ + if ( mConnectButton->text() == i18n( "Connect" ) ) { + emit connectModem(); + + readModelInformation(); + refreshStatus(); + + mConnectButton->setText( tr2i18n( "Disconnect" ) ); + PushButton1->setEnabled( true ); + PushButton5_3->setEnabled( true ); + + mABTab->setEnabled( true ); + setKabState( UNLOADED ); + setMobState( UNLOADED ); + + ((MobileMain *) mparent)->statusBar()->changeItem( i18n(" Connected "), 1 ); + } else { + warnKabState( UNLOADED ); + + mComingFromToggleConnection = true; + if ( !warnMobState( UNLOADED ) ) { + mComingFromToggleConnection = false; + disconnectGUI(); + } + } +} + + +void MobileGui::disconnectGUI() +{ + emit disconnectModem(); + + mManufacturerLabel->setText( "x" ); + mModelLabel->setText( "x" ); + mGSMVersionLabel->setText( "x" ); + mSerialNumberLabel->setText( "x" ); + + mBatteryChargeLabel->setText( "xx %" ); + mSignalQualityLabel->setText( "x" ); + + mConnectButton->setText( tr2i18n( "Connect" ) ); + PushButton1->setEnabled( false ); + PushButton5_3->setEnabled( false ); + + mKabBook->clear(); + mMobileBook->clear(); + setKabState( UNLOADED ); + setMobState( UNLOADED ); + + mABTab->setEnabled( false ); + + mMobHasFD = false; + mMobHasLD = false; + mMobHasME = false; + mMobHasMT = false; + mMobHasTA = false; + mMobHasOW = false; + mMobHasMC = false; + mMobHasRC = false; + + mPBIndexOccupied.resize( 0, false ); + + ((MobileMain *) mparent)->statusBar()->changeItem( i18n(" Disconnected "), + 1 ); +} + + +void MobileGui::termAddOutput( const char *line ) +{ + mTermIO->append( line ); + mTermIO->setCursorPosition( mTermIO->paragraphs() - 1, 0 ); +} + + +void MobileGui::setKabState( ABState newState ) +{ + switch ( mKabState ) { + case UNLOADED: + groupBox3->setTitle( tr2i18n( "KDE Address Book" ) ); + mReadKabButton->setEnabled( true ); + PushButton8->setEnabled( false ); + break; + + case LOADED: + if ( newState == MODIFIED ) { + groupBox3->setTitle( tr2i18n( "KDE Address Book (modified)" ) ); + mReadKabButton->setEnabled( true ); + PushButton8->setEnabled( true ); + } else + if ( newState == UNLOADED ) { + groupBox3->setTitle( tr2i18n( "KDE Address Book" ) ); + mReadKabButton->setEnabled( true ); + PushButton8->setEnabled( false ); + } + break; + + case MODIFIED: + if ( newState != MODIFIED ) { + groupBox3->setTitle( tr2i18n( "KDE Address Book" ) ); + mReadKabButton->setEnabled( true ); + PushButton8->setEnabled( false ); + } + break; + } + + mKabState = newState; +} + + +void MobileGui::warnKabState( ABState newState ) +{ + if ( ( mKabState == MODIFIED ) && ( newState != MODIFIED ) ) { + QString text = "<qt><b>" + i18n( "Warning" ) + "</b><br>"; + text += i18n( "The KDE address book contains unsaved changes." ) + + "<br></qt>"; + + QMessageBox *msg = new QMessageBox( i18n( "Unsaved Changes" ), text, + QMessageBox::Critical, 1, 2, 0, this ); + msg->setButtonText( 1, i18n( "Save" ) ); + msg->setButtonText( 2, i18n( "Discard" ) ); + + switch ( msg->exec() ) { + case 1: + // Save Changes first + writeKabc(); + break; + + case 2: + break; + } + } +} + + +void MobileGui::setMobState( ABState newState ) +{ + switch ( mMobState ) { + case UNLOADED: + if ( newState == UNLOADED ) { + groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) ); + PushButton3->setEnabled( true ); + PushButton12->setEnabled( false ); + PushButton4_2->setEnabled( false ); + MobDeleteButton->setEnabled( false ); + } else + if ( newState == LOADED ) { + groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) ); + PushButton3->setEnabled( true ); + PushButton12->setEnabled( false ); + PushButton4_2->setEnabled( true ); + MobDeleteButton->setEnabled( true ); + } + break; + + case LOADED: + if ( newState == MODIFIED ) { + groupBox4->setTitle( tr2i18n( "Mobile Phone Book (modified)" ) ); + PushButton3->setEnabled( true ); + PushButton12->setEnabled( true ); + PushButton4_2->setEnabled( true ); + MobDeleteButton->setEnabled( true ); + } else + if ( newState == UNLOADED ) { + groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) ); + PushButton3->setEnabled( true ); + PushButton12->setEnabled( false ); + PushButton4_2->setEnabled( false ); + MobDeleteButton->setEnabled( false ); + } + break; + + case MODIFIED: + if ( newState == UNLOADED ) { + groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) ); + PushButton3->setEnabled( true ); + PushButton12->setEnabled( false ); + PushButton4_2->setEnabled( false ); + MobDeleteButton->setEnabled( false ); + } else + if ( newState == LOADED ) { + groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) ); + PushButton3->setEnabled( true ); + PushButton12->setEnabled( false ); + PushButton4_2->setEnabled( true ); + MobDeleteButton->setEnabled( true ); + } + break; + } + + mMobState = newState; +} + + +bool MobileGui::warnMobState( ABState newState ) +{ + if ( ( mMobState == MODIFIED ) && ( newState != MODIFIED ) ) + { + QString text = "<qt><b>" + i18n( "Warning" ) + "</b><br>"; + text += i18n( "The mobile phone book contains unsaved changes." ) + + "<br></qt>"; + + QMessageBox *msg = new QMessageBox( i18n( "Unsaved Changes" ), text, + QMessageBox::Critical, 1, 2, 0, this ); + msg->setButtonText( 1, i18n( "Save" ) ); + msg->setButtonText( 2, i18n( "Discard" ) ); + + switch ( msg->exec() ) { + case 1: + // Save Changes first + writePhonebook(); + return true; + break; + + case 2: + return false; + break; + } + } + + return false; +} diff --git a/kandy/src/mobilegui.h b/kandy/src/mobilegui.h new file mode 100644 index 000000000..b3dbd33ff --- /dev/null +++ b/kandy/src/mobilegui.h @@ -0,0 +1,136 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef MOBILEGUI_H +#define MOBILEGUI_H + +#include <kandyiface.h> + +#include "mobilegui_base.h" +#include "kandyprefs.h" +#include "qvaluevector.h" + + +class CommandScheduler; +class ATCommand; +class AddressSyncer; + + +class MobileGui : public MobileGui_base, virtual public KandyIface +{ + Q_OBJECT + + public: + MobileGui( CommandScheduler *, KandyPrefs *kprefs, QWidget* parent=0, + const char* name=0, WFlags fl=0 ); + ~MobileGui(); + + void exit(); + + signals: + void sendCommand( const QString & ); + void phonebookRead(); + + void statusMessage( const QString & ); + void transientStatusMessage( const QString & ); + void connectModem(); + void disconnectModem(); + + public slots: + void readModelInformation(); + void readPhonebook(); + void savePhonebook(); + void refreshStatus(); + void writePhonebook(); + void readKabc(); + void writeKabc(); + void setClock(); + void mergePhonebooks(); + void syncPhonebooks(); + void termAddOutput( const char *line ); + void toggleConnection(); + void deleteMobPhonebook(); + + protected slots: + void processResult( ATCommand * ); + + private: + /* Links to related classes */ + CommandScheduler *mScheduler; + AddressSyncer *mSyncer; + KandyPrefs *mPrefs; + QWidget *mparent; + + /* String Formatting Routines */ + QString quote( const QString & ); + QString dequote( const QString & ); + void formatPBName( QString *, QString ); + QString noSpaces( const QString & ); + int firstFreeIndex(); + QString string2GSM( const QString & ); + QString GSM2String( const QString & ); + QString decodeSuffix( const QString & ); + QString stripWhiteSpaces( const QString & ); + + /* Routines for GUI updates */ + void updateKabBook(); + void updateMobileBook(); + void disconnectGUI(); + + /* Phone specific items */ + QString mMobManufacturer; + QString mMobModel; + unsigned int mPBStartIndex; + unsigned int mPBLength; + unsigned int mPBNameLength; + QValueVector<bool> mPBIndexOccupied; + bool mMobHasFD; + bool mMobHasLD; + bool mMobHasME; + bool mMobHasMT; + bool mMobHasTA; + bool mMobHasOW; + bool mMobHasMC; + bool mMobHasRC; + + /* Routines and Flags for asynchronous control flow */ + QString mLastWriteId; + bool mComingFromToggleConnection; + bool mComingFromReadPhonebook; + bool mComingFromSyncPhonebooks; + bool mComingFromExit; + void writePhonebookPostProcessing(); + + /* Routines and elements for current state of phone books */ + enum ABState { UNLOADED, LOADED, MODIFIED }; + ABState mKabState, mMobState; + void setKabState( ABState ); + void warnKabState( ABState ); + void setMobState( ABState ); + bool warnMobState( ABState ); + + /* Misc */ + void fillPhonebook( ATCommand * ); +}; + +#endif // MOBILEGUI_H diff --git a/kandy/src/mobilegui_base.ui b/kandy/src/mobilegui_base.ui new file mode 100644 index 000000000..6361e5477 --- /dev/null +++ b/kandy/src/mobilegui_base.ui @@ -0,0 +1,583 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>MobileGui_base</class> +<widget class="QWidget"> + <property name="name"> + <cstring>MobileGui_base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>865</width> + <height>473</height> + </rect> + </property> + <property name="caption"> + <string>Mobile Device</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>GroupBox2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Model Information</string> + </property> + <grid> + + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>Model:</string> + </property> + </widget> + + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>TextLabel3_2</cstring> + </property> + <property name="text"> + <string>Serial number:</string> + </property> + </widget> + + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>mManufacturerLabel</cstring> + </property> + <property name="text"> + <string>x</string> + </property> + </widget> + + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>mGSMVersionLabel</cstring> + </property> + <property name="text"> + <string>x</string> + </property> + </widget> + + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>mSerialNumberLabel</cstring> + </property> + <property name="text"> + <string>x</string> + </property> + </widget> + + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>mModelLabel</cstring> + </property> + <property name="text"> + <string>x</string> + </property> + </widget> + + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel3</cstring> + </property> + <property name="text"> + <string>Manufacturer:</string> + </property> + </widget> + + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>GSM version:</string> + </property> + </widget> + + <spacer row="0" column="2"> + <property name="name"> + <cstring>spacer42</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QTabWidget" row="1" column="0" colspan="2"> + <property name="name"> + <cstring>mTabWidget</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>mABTab</cstring> + </property> + <attribute name="title"> + <string>Address Books</string> + </attribute> + <property name="Enabled"> + <bool>false</bool> + </property> + <grid> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>KDE Address Book</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView" row="0" column="0" rowspan="3" colspan="1"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Phone</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>mKabBook</cstring> + </property> + <property name="resizeMode"> + <enum>AllColumns</enum> + </property> + </widget> + <widget class="QPushButton" row="0" column="1"> + <property name="name"> + <cstring>mReadKabButton</cstring> + </property> + <property name="text"> + <string>Read</string> + </property> + </widget> + <spacer row="2" column="1"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>PushButton8</cstring> + </property> + <property name="text"> + <string>Write</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox" row="0" column="1"> + <property name="name"> + <cstring>groupBox4</cstring> + </property> + <property name="title"> + <string>Mobile Phone Book</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="0" column="1"> + <property name="name"> + <cstring>PushButton3</cstring> + </property> + <property name="text"> + <string>Read</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>PushButton12</cstring> + </property> + <property name="text"> + <string>Write</string> + </property> + </widget> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="2" column="1"> + <property name="name"> + <cstring>PushButton4_2</cstring> + </property> + <property name="text"> + <string>Save to File...</string> + </property> + </widget> + <widget class="QPushButton" row="4" column="1"> + <property name="name"> + <cstring>MobDeleteButton</cstring> + </property> + <property name="text"> + <string>Delete</string> + </property> + </widget> + <widget class="QListView" row="0" column="0" rowspan="5" colspan="1"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Phone</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>mMobileBook</cstring> + </property> + <property name="resizeMode"> + <enum>AllColumns</enum> + </property> + </widget> + </grid> + </widget> + <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout21</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>PushButton8_3</cstring> + </property> + <property name="text"> + <string>Sync</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>321</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>mTerminalTab</cstring> + </property> + <attribute name="title"> + <string>Terminal</string> + </attribute> + <grid> + <widget class="QTextEdit" row="0" column="0"> + <property name="name"> + <cstring>mTermIO</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + </widget> + <widget class="QGroupBox" row="0" column="1"> + <property name="name"> + <cstring>GroupBox1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Status</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mStatus</cstring> + </property> + <property name="text"> + <string>Battery charge:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel5</cstring> + </property> + <property name="text"> + <string>Signal quality:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>mSignalQualityLabel</cstring> + </property> + <property name="text"> + <string>x</string> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>mBatteryChargeLabel</cstring> + </property> + <property name="text"> + <string>xx %</string> + </property> + </widget> + <spacer row="2" column="0" colspan="5"> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="3" column="0"> + <property name="name"> + <cstring>mConnectButton</cstring> + </property> + <property name="text"> + <string>Connect</string> + </property> + </widget> + <spacer row="3" column="2"> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + </spacer> + <widget class="QPushButton" row="3" column="3"> + <property name="name"> + <cstring>PushButton1</cstring> + </property> + <property name="text"> + <string>Refresh</string> + </property> + <property name="Enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QPushButton" row="3" column="4"> + <property name="name"> + <cstring>PushButton5_3</cstring> + </property> + <property name="text"> + <string>Set Clock</string> + </property> + <property name="Enabled"> + <bool>false</bool> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>mReadKabButton</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>readKabc()</slot> + </connection> + <connection> + <sender>PushButton8</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>writeKabc()</slot> + </connection> + <connection> + <sender>PushButton3</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>readPhonebook()</slot> + </connection> + <connection> + <sender>PushButton12</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>writePhonebook()</slot> + </connection> + <connection> + <sender>PushButton4_2</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>savePhonebook()</slot> + </connection> + <connection> + <sender>PushButton5_3</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>setClock()</slot> + </connection> + <connection> + <sender>PushButton8_3</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>syncPhonebooks()</slot> + </connection> + <connection> + <sender>PushButton1</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>refreshStatus()</slot> + </connection> + <connection> + <sender>mConnectButton</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>toggleConnection()</slot> + </connection> + <connection> + <sender>MobDeleteButton</sender> + <signal>clicked()</signal> + <receiver>MobileGui_base</receiver> + <slot>deleteMobPhonebook()</slot> + </connection> +</connections> +<tabstops> + <tabstop>mKabBook</tabstop> + <tabstop>mReadKabButton</tabstop> + <tabstop>PushButton8</tabstop> + <tabstop>mMobileBook</tabstop> + <tabstop>PushButton3</tabstop> + <tabstop>PushButton12</tabstop> + <tabstop>PushButton4_2</tabstop> + <tabstop>MobDeleteButton</tabstop> + <tabstop>PushButton5_3</tabstop> + <tabstop>PushButton1</tabstop> + <tabstop>PushButton8_3</tabstop> +</tabstops> +<slots> + <slot>readKabc()</slot> + <slot>readModelInformation()</slot> + <slot>readPhonebook()</slot> + <slot>refreshStatus()</slot> + <slot>savePhonebook()</slot> + <slot>setClock()</slot> + <slot>syncPhonebooks()</slot> + <slot>writeKabc()</slot> + <slot>writePhonebook()</slot> + <slot>termAddOutput( const char *line )</slot> + <slot>toggleConnection()</slot> + <slot>deleteMobPhonebook()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kandy/src/mobilemain.cpp b/kandy/src/mobilemain.cpp new file mode 100644 index 000000000..118ee7f4e --- /dev/null +++ b/kandy/src/mobilemain.cpp @@ -0,0 +1,191 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <kglobal.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmenubar.h> +#include <kkeydialog.h> +#include <kaccel.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kedittoolbar.h> +#include <kurldrag.h> + +#include <kstdaccel.h> +#include <kaction.h> +#include <kstdaction.h> + +#include <qpushbutton.h> + +#include "mobilegui.h" + +#include "mobilemain.h" +#include <kstatusbar.h> +#include "mobilemain.moc" + +MobileMain::MobileMain(CommandScheduler *scheduler, KandyPrefs *prefs) + : KMainWindow( 0, "MobileMain" ) +{ + mView = new MobileGui(scheduler, prefs, this); + setCentralWidget(mView); + setupActions(); + + statusBar()->insertItem(i18n(" Disconnected "),1,0,true); + connect(mView,SIGNAL(statusMessage(const QString &)), + SLOT(showStatusMessage(const QString &))); + connect(mView,SIGNAL(transientStatusMessage(const QString &)), + SLOT(showTransientStatusMessage(const QString &))); + + statusBar()->show(); + + setAutoSaveSettings(); +} + +MobileMain::~MobileMain() +{ +} + +void MobileMain::setupActions() +{ + KStdAction::quit(this, SLOT(close()), actionCollection()); + + new KAction(i18n("Terminal"),0,this,SLOT(showTerminal()), + actionCollection(),"show_terminal"); + + createStandardStatusBarAction(); + setStandardToolBarMenuEnabled(true); + + KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection()); + KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection()); + KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection()); + + createGUI("kandymobileui.rc"); +} + +void MobileMain::saveProperties(KConfig */*config*/) +{ + // the 'config' object points to the session managed + // config file. anything you write here will be available + // later when this app is restored +} + +void MobileMain::readProperties(KConfig */*config*/) +{ + // the 'config' object points to the session managed + // config file. this function is automatically called whenever + // the app is being restored. read in here whatever you wrote + // in 'saveProperties' +} + +void MobileMain::dragEnterEvent(QDragEnterEvent *event) +{ + // do nothing + KMainWindow::dragEnterEvent(event); + + // accept uri drops only +// event->accept(KURLDrag::canDecode(event)); +} + +void MobileMain::dropEvent(QDropEvent *event) +{ + // this is a very simplistic implementation of a drop event. we + // will only accept a dropped URL. the Qt dnd code can do *much* + // much more, so please read the docs there + + // do nothing + KMainWindow::dropEvent(event); +} + +void MobileMain::optionsConfigureKeys() +{ + KKeyDialog::configure( actionCollection(), this ); +} + +void MobileMain::optionsConfigureToolbars() +{ + // use the standard toolbar editor + saveMainWindowSettings( KGlobal::config(), autoSaveGroup() ); + KEditToolbar dlg(actionCollection()); + connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(newToolbarConfig())); + dlg.exec(); +} + +void MobileMain::newToolbarConfig() +{ + // recreate our GUI + createGUI("kandymobileui.rc"); + applyMainWindowSettings( KGlobal::config(), autoSaveGroup() ); +} + +void MobileMain::optionsPreferences() +{ + emit showPreferencesWin(); +} + +void MobileMain::showStatusMessage(const QString& text) +{ + // display the text on the statusbar + statusBar()->message(text); +} + +void MobileMain::showTransientStatusMessage(const QString& text) +{ + // display the text on the statusbar for 2 s. + statusBar()->message(text,2000); +} + +void MobileMain::changeCaption(const QString& text) +{ + // display the text on the caption + setCaption(text); +} + +bool MobileMain::queryClose() +{ +#if 0 + if (m_view->isModified()) { + switch (KMessageBox::warningYesNoCancel(this, + i18n("Save changes to profile %1?").arg(mFilename))) { + case KMessageBox::Yes : + fileSave(); + return true; + case KMessageBox::No : + return true; + default: // cancel + return false; + } + } else { + return true; + } +#endif + return true; +} + +void MobileMain::showTerminal() +{ + emit showTerminalWin(); +} diff --git a/kandy/src/mobilemain.h b/kandy/src/mobilemain.h new file mode 100644 index 000000000..091d0de0e --- /dev/null +++ b/kandy/src/mobilemain.h @@ -0,0 +1,109 @@ +/* + This file is part of Kandy. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef MOBILEMAIN_H +#define MOBILEMAIN_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <kapplication.h> +#include <kmainwindow.h> + +#include "kandyprefs.h" + +class CommandScheduler; + +/** + * This class serves as the main window for MobileMain. It handles the + * menus, toolbars, and status bars. + * + * @short Main window class + * @author Cornelius Schumacher <schumacher@kde.org> + * @version 0.1 + */ +class MobileMain : public KMainWindow +{ + Q_OBJECT + public: + /** + * Default Constructor + */ + MobileMain(CommandScheduler *, KandyPrefs *prefs); + + /** + * Default Destructor + */ + virtual ~MobileMain(); + + MobileGui *view() { return mView; }; + + signals: + void showTerminalWin(); + void showPreferencesWin(); + + protected: + /** + * Overridden virtuals for Qt drag 'n drop (XDND) + */ + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dropEvent(QDropEvent *event); + + bool queryClose(); + + protected: + /** + * This function is called when it is time for the app to save its + * properties for session management purposes. + */ + void saveProperties(KConfig *); + + /** + * This function is called when this app is restored. The KConfig + * object points to the session management config file that was saved + * with @ref saveProperties + */ + void readProperties(KConfig *); + + + private slots: + void showTerminal(); + void optionsConfigureKeys(); + void optionsConfigureToolbars(); + void optionsPreferences(); + void newToolbarConfig(); + + void showStatusMessage(const QString& text); + void showTransientStatusMessage(const QString& text); + void changeCaption(const QString& text); + + + private: + void setupActions(); + + private: + MobileGui *mView; +}; + +#endif // MOBILEMAIN_H diff --git a/kandy/src/modem.cpp b/kandy/src/modem.cpp new file mode 100644 index 000000000..3341ad589 --- /dev/null +++ b/kandy/src/modem.cpp @@ -0,0 +1,703 @@ +/* + KMLOCfg + + A utility to configure the ELSA MicroLink(tm) Office modem. + + Copyright (C) 2000 Oliver Gantz <Oliver.Gantz@epost.de> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + ------ + ELSA and MicroLink are trademarks of ELSA AG, Aachen. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <termios.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <pwd.h> +#include <errno.h> + +#include <qglobal.h> + +#include <klocale.h> +#include <kdebug.h> + +#include "modem.h" + + +#ifndef CSOH +#define CSOH 01 +#endif + +#ifndef CSTX +#define CSTX 02 +#endif + +#ifndef CEOT +#define CEOT 04 +#endif + +#ifndef CACK +#define CACK 06 +#endif + +#ifndef CNAK +#define CNAK 025 +#endif + +#ifndef CCAN +#define CCAN 030 +#endif + + + +Modem::Modem( KandyPrefs *kprefs, QObject *parent, const char *name ) : + QObject(parent, name) +{ + mOpen = false; + + prefs = kprefs; + + timer = new QTimer( this, "modemtimer" ); + Q_CHECK_PTR( timer ); + connect( timer, SIGNAL( timeout() ), SLOT( timerDone() ) ); + + init(); + xreset(); +} + + +Modem::~Modem() +{ + close(); +} + + +void Modem::setSpeed( int speed ) +{ + switch ( speed ) { + case 300: + cspeed = B300; + break; + case 600: + cspeed = B600; + break; + case 1200: + cspeed = B1200; + break; + case 2400: + cspeed = B2400; + break; + case 4800: + cspeed = B4800; + break; + case 9600: + cspeed = B9600; + break; + case 19200: + cspeed = B19200; + break; + case 38400: + cspeed = B38400; + break; + case 57600: + cspeed = B57600; + break; + case 115200: + cspeed = B115200; + break; + case 230400: + cspeed = B230400; + break; + default: +#ifdef MODEM_DEBUG + fprintf(stderr, "Modem: setSpeed(): fallback to default speed.\n"); +#endif + cspeed = B38400; + } +} + + +void Modem::setData( int data ) +{ + cflag &= ~CSIZE; + + switch ( data ) { + case 5: + cflag |= CS5; + break; + case 6: + cflag |= CS6; + break; + case 7: + cflag |= CS7; + break; + default: + cflag |= CS8; + } +} + + +void Modem::setParity( char parity ) +{ + cflag &= ~( PARENB | PARODD ); + + if ( parity == 'E' ) + cflag |= PARENB; + else if ( parity == 'O' ) + cflag |= PARENB | PARODD; +} + + +void Modem::setStop( int stop ) +{ + if (stop == 2) + cflag |= CSTOPB; + else + cflag &= ~CSTOPB; +} + + +bool Modem::open() +{ + struct termios tty; + + + close(); + + if ( !lockDevice() ) + return false; + + QCString dev = QFile::encodeName( (*prefs).serialDevice() ); + const char *fdev = dev.data(); + if ( ( fd = ::open( fdev, O_RDWR | O_NOCTTY | O_NONBLOCK ) ) == -1 ) { + emit errorMessage( i18n( "Unable to open device '%1'. " + "Please check that you have sufficient permissions." ) + .arg( fdev ) ); + return false; + } + + tcflush( fd, TCIOFLUSH ); + if ( tcgetattr( fd, &init_tty ) == -1 ) { + int errnumber = errno; + emit errorMessage( i18n( "Communication setup failed (tcgetattr code: %1)" ) + .arg(strerror(errnumber)) ); + ::close( fd ); + fd = 0; + return false; + } + + memset( &tty, 0, sizeof( tty ) ); + tty.c_iflag = IGNBRK | IGNPAR; + tty.c_oflag = 0; + tty.c_cflag = cflag; + tty.c_lflag = 0; + cfsetospeed( &tty, cspeed ); + cfsetispeed( &tty, cspeed ); + tcdrain( fd ); + + if ( tcsetattr( fd, TCSANOW, &tty ) == -1 ) { + emit errorMessage( i18n( "tcsetattr() failed." ) ); + ::close( fd ); + fd = 0; + return false; + } + + sn = new QSocketNotifier( fd, QSocketNotifier::Read, this, + "modemsocketnotifier" ); + Q_CHECK_PTR( sn ); + connect( sn, SIGNAL( activated( int ) ), SLOT( readChar( int ) ) ); + + mOpen = true; + + return true; +} + + +void Modem::close() +{ + timer->stop(); + + delete sn; + sn = 0; + + if ( fd ) { + tcflush( fd, TCIOFLUSH ); + tcsetattr( fd, TCSANOW, &init_tty ); + ::close( fd ); + fd = 0; + } + + xreset(); + + unlockDevice(); + + mOpen = false; +} + + +void Modem::flush() +{ + if ( fd ) { + tcflush( fd, TCIOFLUSH ); + bufpos = 0; + } +} + +#ifdef HAVE_LOCKDEV +#include <lockdev.h> +#endif + +bool Modem::lockDevice() +{ + if ( is_locked ) + return true; + +#ifdef HAVE_LOCKDEV + is_locked = !dev_lock( (*prefs).serialDevice().local8Bit() ); + if (!is_locked) + emit errorMessage( i18n( "Unable to lock device '%1'." ).arg( + (*prefs).serialDevice() )); + return is_locked; +#else + ssize_t count; + pid_t pid; + int lfd; + struct passwd *pw; + QStringList pathList; + QString fileName, content; + + pathList = QStringList::split( "/", (*prefs).serialDevice() ); + fileName = (*prefs).lockDirectory() + "/LCK.." + pathList.last(); + + if ( !access( QFile::encodeName( fileName ).data(), F_OK ) ) { + char buf[256]; + + + if ( ( lfd = ::open( QFile::encodeName( fileName ), O_RDONLY ) ) < 0 ) { + emit errorMessage( i18n( "Unable to open lock file '%1'.") + .arg( fileName ) ); + return false; + } + + count = read( lfd, buf, 79 ); + + if ( count < 0 ) { + emit errorMessage( i18n( "Unable to read lock file '%1'.") + .arg( fileName ) ); + ::close( lfd ); + return false; + } + buf[ count ] = 0; + ::close( lfd ); + + count = sscanf( buf, "%d", &pid ); + if ( ( count != 1 ) || ( pid <= 0 ) ) { + emit errorMessage( i18n( "Unable to get PID from file '%1'.") + .arg( fileName ) ); + return false; + } + + if ( !kill( (pid_t) pid, 0 ) ) { + emit errorMessage( i18n( "Process with PID %1, which is locking the device, is still running.") + .arg( pid ) ); + return false; + } + + if ( errno != ESRCH ) { + emit errorMessage( i18n( "Unable to emit signal to PID of existing lock file.") ); + return false; + } + } + + if ( ( lfd = creat( QFile::encodeName( fileName ).data(), 0644 ) ) == -1 ) { + emit errorMessage( i18n( "Unable to create lock file '%1'. " + "Please check that you have sufficient permissions.") + .arg( fileName ) ); + return false; + } + + pid = (int) getpid(); + pw = getpwuid( getuid() ); + content.sprintf( "%08d %s %s", pid, "kandy", pw->pw_name ); + write( lfd, QFile::encodeName( content ).data(), content.length() ); + ::close( lfd ); + + is_locked = true; + + return true; +#endif +} + + +void Modem::unlockDevice() +{ +#ifdef HAVE_LOCKDEV + dev_unlock( (*prefs).serialDevice().local8Bit(), getpid() ); +#else + if ( is_locked ) { + QStringList pathList = QStringList::split( "/", (*prefs).serialDevice() ); + + QFile::remove( (*prefs).lockDirectory() + "/LCK.." + pathList.last() ); + is_locked = false; + } +#endif +} + + +bool Modem::dsrOn() +{ + int flags; + + + if ( !fd ) { +#ifdef MODEM_DEBUG + fprintf( stderr, "Modem: dsrOn(): File not open.\n" ); +#endif + return false; + } + + if ( ioctl( fd, TIOCMGET, &flags ) == -1 ) { +#ifdef MODEM_DEBUG + fprintf( stderr, "Modem: dsrOn(): ioctl() failed.\n" ); +#endif + return false; + } + + return ( flags & TIOCM_DSR ) != 0; +} + + +bool Modem::ctsOn() +{ + int flags; + + + if ( !fd ) { +#ifdef MODEM_DEBUG + fprintf( stderr, "Modem: ctsOn(): File not open.\n" ); +#endif + return false; + } + + if ( ioctl( fd, TIOCMGET, &flags ) == -1) { +#ifdef MODEM_DEBUG + fprintf( stderr, "Modem: ctsOn(): ioctl() failed.\n" ); +#endif + return false; + } + + return ( flags & TIOCM_CTS ) != 0; +} + + +void Modem::writeChar( const char c ) +{ + write( fd, (const void *) &c, 1 ); +} + + +void Modem::writeLine( const char *line ) +{ + kdDebug() << "Modem::writeLine(): " << line << endl; + + write( fd, (const void *) line, strlen( line ) ); + writeChar( '\r' ); +} + + +void Modem::timerStart( int msec ) +{ + timer->start( msec, true ); +} + + +void Modem::receiveXModem( bool crc ) +{ + disconnect( sn, 0, this, 0 ); + connect( sn, SIGNAL( activated( int ) ), SLOT( readXChar( int ) ) ); + + xcrc = crc; + + if ( xcrc ) { + writeChar( 'C' ); + xstate = 1; + timerStart( 3000 ); + } else { + writeChar( CNAK ); + xstate = 5; + timerStart( 10000 ); + } + + xblock = 1; +} + + +void Modem::abortXModem() +{ + timer->stop(); + writeChar( CCAN ); + xreset(); + emit xmodemDone( false ); +} + + +void Modem::timerDone() +{ +#ifdef MODEM_DEBUG + fprintf( stderr, "Modem: timeout, xstate = %d.\n", xstate ); +#endif + + switch ( xstate ) { + case 0: /* non-XModem mode */ + emit timeout(); + break; + + case 1: /* 1st 'C' sent */ + case 2: /* 2nd 'C' sent */ + case 3: /* 3rd 'C' sent */ + writeChar( 'C' ); + xstate++; + timerStart( 1000 ); /* Should be 3000 in original XModem */ + break; + + case 4: /* 4th 'C' sent */ + xcrc = false; + + case 5: /* 1st <NAK> sent */ + case 6: /* 2nd <NAK> sent */ + case 7: /* 3rd <NAK> sent */ + case 8: /* 4th <NAK> sent */ + case 9: /* 5th <NAK> sent */ + writeChar( CNAK ); + xstate++; + timerStart( 1000 ); /* Should be 10000 in original XModem */ + break; + + case 10: /* 6th <NAK> sent */ + xreset(); + emit xmodemDone( false ); + break; + + default: /* pending XModem block */ + writeChar( CNAK ); + xstate = 5; + timerStart( 1000 ); /* Should be 10000 in original XModem */ + } +} + + +void Modem::readChar( int ) +{ + uchar c; + + + while ( read( fd, (void *) &c, 1 ) == 1 ) { + if ( c == '\n' ) { + buffer[ bufpos ] = 0; + bufpos = 0; + emit gotLine( (const char *) buffer ); + break; + } else + if ( ( bufpos < 1000 ) && ( c != '\r' ) ) + buffer[ bufpos++ ] = c; + } +} + + +void Modem::readXChar( int ) +{ + uchar c; + static uchar crc_hi, block, cblock; + + + while ( read( fd, (void *) &c, 1 ) == 1 ) { + switch ( xstate ) { + case 1: /* 1st 'C' sent */ + case 2: /* 2nd 'C' sent */ + case 3: /* 3rd 'C' sent */ + case 4: /* 4th 'C' sent */ + case 5: /* 1st <NAK> sent */ + case 6: /* 2nd <NAK> sent */ + case 7: /* 3rd <NAK> sent */ + case 8: /* 4th <NAK> sent */ + case 9: /* 5th <NAK> sent */ + case 10: /* 6th <NAK> sent */ + if ( c == CSOH ) { + timerStart( 1000 ); + xsize = 128; + xstate = 11; + } else + if ( c == CSTX ) { + timerStart( 1000 ); + xsize = 1024; + xstate = 11; + } else + if ( c == CEOT ) { + timer->stop(); + writeChar( CACK ); + xreset(); + emit xmodemDone( true ); + } else + timerStart( 1000 ); + break; + + case 11: /* <SOH> or <STX> received */ + timerStart( 1000 ); + block = c; + xstate++; + break; + + case 12: /* block number received */ + timerStart( 1000 ); + cblock = c; + xstate++; + bufpos = 0; + break; + + case 13: /* complement block number received */ + timerStart( 1000 ); + buffer[ bufpos++ ] = c; + if ( bufpos == xsize ) { + bufpos = 0; + xstate++; + if ( !xcrc ) + xstate++; + } + break; + + case 14: /* data block received */ + timerStart( 1000 ); + crc_hi = c; + xstate++; + break; + + case 15: /* crc high-byte received */ + timerStart( 10000 ); + xstate = 4; + if ( (uchar) ( block ^ cblock ) != 0xff ) { + writeChar( CNAK ); + break; + } + if ( block+1 == xblock ) { + writeChar( CACK ); + break; + } + if ( block != xblock ) { + timer->stop(); + writeChar( CCAN ); + xreset(); + emit xmodemDone( false ); + break; + } + if ( xcrc ) { + if ( ( (ushort) crc_hi << 8 | (ushort) c ) != calcCRC() ) { + writeChar( CNAK ); + break; + } + } else { + if ( c != calcChecksum() ) { + writeChar( CNAK ); + break; + } + } + writeChar( CACK ); + xblock++; + emit gotXBlock( buffer, xsize ); + break; + + default: + break; + } + } +} + + +void Modem::init() +{ + is_locked = false; + + fd = 0; + sn = 0; + + cspeed = B38400; + + // No flow control + cflag = CS8 | CREAD | CLOCAL; + // cflag = CS8 | CREAD | CLOCAL | CRTSCTS; + + bufpos = 0; +} + + +void Modem::xreset() +{ + bufpos = 0; + + xstate = 0; + xcrc = false; + xblock = 0; + xsize = 0; + + if ( sn ) { + disconnect( sn, 0, this, 0 ); + connect( sn, SIGNAL( activated( int ) ), SLOT( readChar( int ) ) ); + } +} + + +uchar Modem::calcChecksum() +{ + int i; + uchar c = 0; + + + for ( i = 0; i < xsize; i++ ) + c += buffer[ i ]; + + return c; +} + + +ushort Modem::calcCRC() +{ + int i, j; + ushort c = 0; + + + for ( i = 0; i < xsize; i++ ) { + c ^= (ushort) buffer[ i ] << 8; + for ( j = 0; j < 8; j++ ) + if ( c & 0x8000 ) + c = c << 1 ^ 0x1021; + else + c <<= 1; + } + + return c; +} + +#include "modem.moc" diff --git a/kandy/src/modem.h b/kandy/src/modem.h new file mode 100644 index 000000000..ecb0cfe91 --- /dev/null +++ b/kandy/src/modem.h @@ -0,0 +1,124 @@ +/* + KMLOCfg + + A utility to configure the ELSA MicroLink(tm) Office modem. + + Copyright (C) 2000 Oliver Gantz <Oliver.Gantz@epost.de> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + ------ + ELSA and MicroLink are trademarks of ELSA AG, Aachen. +*/ + +#ifndef MODEM_H +#define MODEM_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <termios.h> + +#include <qobject.h> +#include <qstring.h> +#include <qtimer.h> +#include <qsocketnotifier.h> +#include <qfile.h> + +#include "kandyprefs.h" + + + + +class Modem : public QObject +{ + Q_OBJECT +public: + Modem(KandyPrefs *kprefs, QObject *parent = 0, const char *name = 0); + virtual ~Modem(); + + void setSpeed(int speed); + void setData(int data); + void setParity(char parity); + void setStop(int stop); + + bool open(); + void close(); + + bool isOpen() { return mOpen; } + + void flush(); + + bool lockDevice(); + void unlockDevice(); + + bool dsrOn(); + bool ctsOn(); + + void writeChar(const char c); + void writeLine(const char *line); + + void timerStart(int msec); + + void receiveXModem(bool crc); + void abortXModem(); + +private slots: + void timerDone(); + + void readChar(int); + void readXChar(int); + +private: + bool mOpen; + + void init(); + void xreset(); + + uchar calcChecksum(); + ushort calcCRC(); + + bool is_locked; + struct termios init_tty; + + speed_t cspeed; + tcflag_t cflag; + + int fd; + QTimer *timer; + QSocketNotifier *sn; + + uchar buffer[1024]; + int bufpos; + + int xstate; + bool xcrc; + uchar xblock; + int xsize; + + KandyPrefs *prefs; + +signals: + void gotLine(const char *); + void gotXBlock(const uchar *, int); + void xmodemDone(bool); + void timeout(); + + void errorMessage( const QString & ); +}; + + +#endif // MODEM_H diff --git a/kandy/src/uninstall.desktop b/kandy/src/uninstall.desktop new file mode 100644 index 000000000..e1e3e1732 --- /dev/null +++ b/kandy/src/uninstall.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +Hidden=true |