P7: Inainte si inapoi
In acest exemplu sintem pregatiti sa marim functionalitatea lui
P5 in ideea de a invata cum sa folosim
citeva clase standard KDE care ar trebui folosite in aproape toate
aplicatiile.
#include <kapp.h>
#include "p7.h"
int main( int argc, char **argv )
{
KApplication a( argc, argv, "p7" );
MainWindow *mywindow=new MainWindow("Tutorial - p7");
mywindow->resize( 300, 200 );
a.setMainWidget( mywindow );
mywindow->show();
return a.exec();
}
main.cpp
#include <dcopobject.h>
class p7Iface : virtual public DCOPObject
{
K_DCOP
k_dcop:
virtual void setURL( QString s )=0;
};
p7Iface.h
#include "p7Iface.h"
#include <kmainwindow.h>
#include <kurl.h>
#include <kparts/browserextension.h>
#include <qvaluestack.h>
class QLineEdit;
class KHTMLPart;
class MainWindow : public KMainWindow, virtual public p7Iface
{
Q_OBJECT
public:
MainWindow ( const char * titulo );
virtual void setURL ( const QString url );
public slots:
void fileSetDefaultPage();
void changeLocation();
void bookLocation();
void gotoPreviousPage();
void openURLRequest(const KURL &url, const KParts::URLArgs &);
private:
QLineEdit *location;
KHTMLPart *browser;
QValueStack <QString> history;
};
p7.h
#include "p7.h"
#include <qvbox.h>
#include <qlineedit.h>
#include <dcopclient.h>
#include <kfiledialog.h>
#include <kapp.h>
#include <kmenubar.h>
#include <ktoolbar.h>
#include <klocale.h>
#include <kpopupmenu.h>
#include <khtml_part.h>
#include <kdebug.h>
#include <kconfig.h>
#include <kiconloader.h>
MainWindow::MainWindow(const char * name) : KMainWindow(0L, name),
DCOPObject("browser")
{
setCaption("KDE Tutorial - p7");
QPopupMenu * filemenu = new QPopupMenu;
filemenu->insertItem( i18n( "&Set default page" ),
this, SLOT( fileSetDefaultPage() ) );
filemenu->insertItem(i18n("&Quit"), kapp, SLOT(quit()));
QString about =
i18n("p7 1.0\n\n"
"(C) 1999-2002 Antonio Larrosa Jimenez\n"
"larrosa@kde.org\t\tantlarr@supercable.es\n"
"Malaga (Spain)\n\n"
"Simple KDE Tutorial\n"
"This tutorial comes with ABSOLUTELY NO WARRANTY \n"
"This is free software, and you are welcome to redistribute it\n"
"under certain conditions\n");
QPopupMenu *helpmenu = helpMenu(about);
KMenuBar * menu = menuBar();
menu->insertItem( i18n( "&File" ), filemenu);
menu->insertSeparator();
menu->insertItem(i18n( "&Help" ), helpmenu);
KToolBar *toolbar=new KToolBar(this);
toolbar->insertButton(BarIcon("reload"), TOOLBAR_ID_ADDBOOKMARK,
SIGNAL(clicked(int)),this,
SLOT(bookLocation()),TRUE,
i18n("Add to Bookmarks"));
toolbar->insertButton(BarIcon("back"), TOOLBAR_ID_BACK,
SIGNAL(clicked(int)),this,
SLOT(gotoPreviousPage()),
FALSE, i18n("Back to previous page"));
toolbar->insertButton(BarIcon("exit"), TOOLBAR_ID_QUIT,
SIGNAL(clicked(int)),kapp,SLOT(quit()),
TRUE,
i18n("Quit the application"));
addToolBar(toolbar);
QVBox * vbox = new QVBox ( this );
location = new QLineEdit ( vbox );
KConfig *config=kapp->config();
config->setGroup("Settings");
location->setText( config->readEntry( "defaultPage",
"http://localhost") );
connect(location , SIGNAL( returnPressed() ),
this, SLOT( changeLocation() ) );
browser=new KHTMLPart( vbox );
browser->openURL( location->text() );
connect(browser->browserExtension(),
SIGNAL(openURLRequest(const KURL &, const KParts::URLArgs &)),
this,
SLOT(openURLRequest(const KURL &, const KParts::URLArgs &)));
setCentralWidget( vbox );
DCOPClient *client = kapp->dcopClient();
client->attach();
client->registerAs("p7");
}
void MainWindow::changeLocation()
{
history.push(browser->url().url());
toolBar()->setItemEnabled(TOOLBAR_ID_BACK, TRUE);
browser->openURL(location->text());
}
void MainWindow::setURL( QString url )
{
location->setText( url );
changeLocation();
}
void MainWindow::openURLRequest(const KURL &url,
const KParts::URLArgs &)
{
setURL( url.url() );
}
void MainWindow::gotoPreviousPage()
{
location->setText( history.pop() );
if (history.isEmpty())
toolBar()->setItemEnabled( TOOLBAR_ID_BACK, FALSE);
browser->openURL( location->text() );
}
void MainWindow::bookLocation()
{
DCOPClient *client=kapp->dcopClient();
QByteArray params;
QDataStream stream(params, IO_WriteOnly);
stream << location->text();
if (!client->send("p8-*", "bookmarkList", "add(QString)", params))
kdDebug << "Error with DCOP\n";
}
void MainWindow::fileSetDefaultPage()
{
KConfig *config=kapp->config();
config->setGroup("Settings");
config->writeEntry("defaultPage", browser->url().url());
}
p7.cpp
Primul lucru pe care il facem este sa adaugam interfata DCOP la P7
pentru a fi folosita de P8
(urmatoarea generatie de lista de semne de carte). Este asemanator cu
P6 de aceea nu-l voi mai comenta.
#define TOOLBAR_ID_ADDBOOKMARK 1
#define TOOLBAR_ID_BACK 2
#define TOOLBAR_ID_QUIT 3
Sintem la inceputul fisierului p7.cpp. Aici definim citiva
identificatori pentru butoanele barei de unelte. Asta nu este intotdeauna
necesar. Puteti crea bare de unelte (toolbars) lasind clasa barei
de unelte sa atribuie identificatori impliciti.
Dar vom activa/dezactiva butoane de pe bara de unelte, asa ca este mai clar
sa facem in felul acesta.
MainWindow::MainWindow(const char * name) : KMainWindow(0L, name),
DCOPObject("browser")
{
QPopupMenu * filemenu = new QPopupMenu;
filemenu->insertItem( i18n( "&Set default page" ),
this, SLOT( fileSetDefaultPage() ) );
Clasa MainWindow acum mosteneste p7Iface, asa ca trebuie
sa apelam si constructorul DCOPObject. Vom numi obiectul
browser. In meniul File mai adaugam un element
pe care il vom folosi sa setam pagina actuala ca pagina implicita cind
vom mai rula aplicatia. Astfel vom invata si cum sa salvam
variabilele de configurare.
KToolBar *toolbar=new KToolBar(this);
Folosind clasa KToolBar vom crea o bara de unelte care va
avea o infatisare standard cu un mic indicator de
care se poate apuca si muta bara in afara ferestrei sau repozitiona
in alta parte etc.
toolbar->insertButton(BarIcon("reload"),
TOOLBAR_ID_ADDBOOKMARK,
SIGNAL(clicked(int)),this,SLOT(bookLocation()),
TRUE,
i18n("Add to Bookmarks"));
toolbar->insertButton(BarIcon("back"), TOOLBAR_ID_BACK,
SIGNAL(clicked(int)),this,SLOT(gotoPreviousPage()),
FALSE, i18n("Back to previous page"));
toolbar->insertButton(BarIcon("exit"), TOOLBAR_ID_QUIT,
SIGNAL(clicked(int)),kapp,SLOT(quit()),
TRUE,
i18n("Quit the application"));
O sa adaugam trei butoane. Primul il vom folosi in locul acelui buton
mare (si urit) pe care l-am folosit in
P5. Al doilea buton il vom
folosi ca sa ne ducem la pagina precedenta si al treilea ca sa inchidem
aplicatia. (Retineti: se recomanda sa nu se foloseasca un
in bara de unelte un buton pentru terminarea aplicatiei. Ce facem noi
nu este o aplicatie reala si de aceea vom omite acest
avertisment serios).
BarIcon("reload") este o functie care cauta automat iconita
reload (oriunde s-ar afla: $KDEDIR/share/toolbar sau
$KDEDIR/share/apps/<appname>/toolbar) si intoarce un obiect
valid QPixmap cu acea iconita.
Urmatorul parametru este identificatorul pe care o sa-l folosim mai tirziu
pentru a ne referi la acest buton. Paramentrul al treilea este semnalul
pe care il conectam la obiectul care il va primi, urmat de slotul care
va fi apelat. Retineti ca nu intotdeauna trebuie sa dam un identificator
valid. Putem sa folosim 0. Folosim identificatori pentru a
activa/dezactiva un buton, asa cum vom face cu butonul back.
addToolBar(toolbar);
Am terminat de construit bara de unelte, asa ca o adaugam la widget-ul
principal cu addToolBar. addToolBar nu urmeaza
aceeasi logica ca setMenu, deoarece nu suntem obligati sa
folosim o singura bara de unelte (ca in cazul meniurilor) de aceea nu
setam, ci adaugam bara.
KConfig *config=kapp->config();
config->setGroup("Settings");
location->setText( config->readEntry( "defaultPage",
"http://localhost") );
Stim deja ce este kapp dar nu am folosit pina acum metoda
config(). Aceasta metoda va intoarce obiectul KConfig
al aplicatiei. KConfig este folosit pentru a salva variabilele de
configurare ale unei aplicatii. El salveaza automat inregistrarile
cu informatii de configurare în fisierul de configurare al aplicatiei
si le reincarca atunci cind aplicatia este rulata din nou.
O data ce avem obiectul de configurare, setam grupul activ in care lucram
ca fiind Settings. Grupurile sunt folosite pentru a structura
mai bine fisierele de configurare.
In cele din urma in loc sa folosim "http://localhost" ca
pagina implicita, citim din fisierul de configurare.
defaultPage este numele inregistrarii pe care vrem sa o citim,
"http://localhost" este valoarea implicita care va fi intoarsa in
cazul in care fisierul de configurare nu contine valoarea pentru
defaultPage.
Puteti citi valori intregi cu KConfig::readNumEntry,
valori de adevar cu KConfig::readBoolEntry etc.
DCOPClient *client = kapp->dcopClient();
client->attach();
client->registerAs("p7");
Atasam aplicatia la serverul DCOP si o inregistram ca
p7, deoarece vrem ca P8
sa o poata apela sa seteze o pagina.
void MainWindow::setURL( QString url )
{
location->setText( url );
changeLocation();
}
Acest membru este folosit sa seteze legatura. Acum functia poate fi
apelata de catre interfata DCOP sau cind utilizatorul da clic pe o
legatura. Setam prima data textul pentru a afisa legatura si apelam functia
changeLocation.
void MainWindow::changeLocation()
{
history.push(browser->url());
toolBar()->setItemEnabled(TOOLBAR_ID_BACK, TRUE);
browser->openURL(location->text());
}
changeLocation (care este folosit si de semnalul
enterPressed() al obiectului location) este folosit
pentru a incarca o pagina noua atunci cind legatura este setata
in bara de locatie. Am facut in asa fel pentru a implementa
in P7 functia de istoric de navigare.
Observam ca am definit in P7 un obiect history de
tipul QValueStack<QString>. QValueStack este o
clasa Qt care implementeaza o stiva, folosind template ca tip de
date. Diferenta intre QValueStack si QStack consta in
faptul ca prima stocheaza valorile elementelor creind o copie a fiecarui
element pe care il adaugati, in timp ce a doua doar salveaza pointeri la acele
elemente. Trebuie sa aveti grija sa nu stergeti elementul cit timp mai
este pe stiva.
Intrucit clasa QString partajeaza datele pentru toate copiile sirului
de caractere pina cind este efectuata o modificare intr-una din ele,
nu prezinta o problema sa efectuati copii ale legaturilor.
Acum obtinem bara de unelte implicita (daca sint mai multe, putem sa
le obtinem pe celelalte utilizind un identificator ca parametru la
toolBar) si activam butonul back pentru
a permite utilizatorului sa il apese.
In final incarcam noua legatura in widget-ul browser
preluind legatura din bara de locatie.
void MainWindow::gotoPreviousPage()
{
location->setText( history.pop() );
Cind utilizatorul doreste sa se intoarca in pagina anterioara, preluam
ultimul element inserat in stiva de istoric si il plasam in bara de
locatie. Sirul de caractere este sters din stiva, astfel ca data viitoare
cind extragem de pe stiva vom prelua locatia anterioara si tot asa pina
cind stiva devine goala.
if (history.isEmpty())
toolBar()->setItemEnabled(TOOLBAR_ID_BACK, FALSE);
browser->openURL( location->text());
}
Daca stiva este goala, dezactivam butonul back. O data ce am
adaugat un alt element butonul este activat din nou de metoda
changeLocation(). Apoi deschidem in navigator locatia
extrasa.
void MainWindow::fileSetDefaultPage()
{
KConfig *config=kapp->config();
config->setGroup("Settings");
config->writeEntry( "defaultPage", browser->url() );
}
In cele din urma, implementam metoda care este conectata la elementul
din meniu Set default page. Aceasta metoda salveaza
locatia curenta in fisierul de configurare al aplicatiei.
Mai intii preluam obiectul KConfig si setam grupul Settings
cum am facut in constructor. Apoi scriem o noua inregistrare cu ajutorul
functiei writeEntry.
Primul parametru este numele cheii si al doilea reprezinta valoarea la
care setam cheia. Este de mentionat ca multumita metodelor supraincarcate
putem utiliza writeEntry cu diferite tipuri de date ca al doilea
parametru (int, bool, float, QString,
QStringList, QFont etc.).
Acum am ajuns la finalul acestui tutorial, dar intii trebuie sa efectuam
o mica schimbare la P8 astfel incit
sa comunice cu P7. Aceasta are ca scop setarea paginii curente
in momentul selectarii unei locatii din lista semnelor de carte.
|