Development/Tutorials/Saving and loading (es): Difference between revisions
(links update) |
No edit summary |
||
(5 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
{{TutorialBrowser_(es)| | {{TutorialBrowser_(es)| | ||
Line 26: | Line 26: | ||
===main.cpp=== | ===main.cpp=== | ||
< | <syntaxhighlight lang="cpp-qt" line> | ||
#include <KApplication> | #include <KApplication> | ||
#include <KAboutData> | #include <KAboutData> | ||
Line 47: | Line 47: | ||
return app.exec(); | return app.exec(); | ||
} | } | ||
</ | </syntaxhighlight> | ||
<tt>main.cpp</tt> no ha cambiado desde el tutorial 3, excepto el cambio de cualquier referencia de tutorial 3 a tutorial 4. | <tt>main.cpp</tt> no ha cambiado desde el tutorial 3, excepto el cambio de cualquier referencia de tutorial 3 a tutorial 4. | ||
===mainwindow.h=== | ===mainwindow.h=== | ||
< | <syntaxhighlight lang="cpp-qt" line> | ||
#ifndef MAINWINDOW_H | #ifndef MAINWINDOW_H | ||
#define MAINWINDOW_H | #define MAINWINDOW_H | ||
Line 79: | Line 79: | ||
#endif | #endif | ||
</ | </syntaxhighlight> | ||
Como queremos añadir la posibilidad de cargar y guardar archivos, debemos añadir las funciones que realizarán el trabajo. Ya que invocaremos a las funciones mediante el mecanismo de Qt [http://doc.trolltech.com/latest/signalsandslots.html signal/slot], debemos especificar que dichas funciones son slots, por lo que lo hacemos en la linea 19. Como estamos usando slots en el archivo cabecera, debemos también añadir la macro [http://doc.trolltech.com/latest/qobject.html#Q_OBJECT <tt>Q_OBJECT</tt>]. | Como queremos añadir la posibilidad de cargar y guardar archivos, debemos añadir las funciones que realizarán el trabajo. Ya que invocaremos a las funciones mediante el mecanismo de Qt [http://doc.trolltech.com/latest/signalsandslots.html signal/slot], debemos especificar que dichas funciones son slots, por lo que lo hacemos en la linea 19. Como estamos usando slots en el archivo cabecera, debemos también añadir la macro [http://doc.trolltech.com/latest/qobject.html#Q_OBJECT <tt>Q_OBJECT</tt>]. | ||
Line 85: | Line 85: | ||
===mainwindow.cpp=== | ===mainwindow.cpp=== | ||
< | <syntaxhighlight lang="cpp-qt" line> | ||
#include "mainwindow.h" | #include "mainwindow.h" | ||
Line 195: | Line 195: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
===tutorial4ui.rc=== | ===tutorial4ui.rc=== | ||
< | <syntaxhighlight lang="xml" line> | ||
<?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||
<gui name="tutorial4" | <gui name="tutorial4" | ||
Line 219: | Line 219: | ||
</gui> | </gui> | ||
</ | </syntaxhighlight> | ||
Es idéntico a <tt>tutorial3ui.rc</tt> del tutorial 3 excepto <tt>name</tt>, que ha cambiado a 'tutorial4'. No necesitamos añadir ninguna información de las <tt>KStandardAction</tt> ya que la posición de esas acciones las maneja KDE automaticamente. | Es idéntico a <tt>tutorial3ui.rc</tt> del tutorial 3 excepto <tt>name</tt>, que ha cambiado a 'tutorial4'. No necesitamos añadir ninguna información de las <tt>KStandardAction</tt> ya que la posición de esas acciones las maneja KDE automaticamente. | ||
Line 228: | Line 228: | ||
Lo primero que hacemos es añadir | Lo primero que hacemos es añadir | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
fileName(QString()) | fileName(QString()) | ||
</ | </syntaxhighlight> | ||
al constructor de <tt>MainWindow</tt> en la linea 16. Esto asegura que <tt>fileName</tt> esté vacio desde el principio. | al constructor de <tt>MainWindow</tt> en la linea 16. Esto asegura que <tt>fileName</tt> esté vacio desde el principio. | ||
Line 240: | Line 240: | ||
La primera función que hemos definido es <tt>newFile()</tt>. | La primera función que hemos definido es <tt>newFile()</tt>. | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
void MainWindow::newFile() | void MainWindow::newFile() | ||
{ | { | ||
Line 246: | Line 246: | ||
textArea->clear(); | textArea->clear(); | ||
} | } | ||
</ | </syntaxhighlight> | ||
Con <tt>fileName.clear()</tt> ponemos la QString como "vacia" para reflejar el hecho de que el documento aún no está presente en disco. A continuación, <tt>textArea->clear()</tt> limpia el area de texto usando la misma función que conectaba con la <tt>KAction</tt> <tt>clear</tt> en el tutorial 3. | Con <tt>fileName.clear()</tt> ponemos la QString como "vacia" para reflejar el hecho de que el documento aún no está presente en disco. A continuación, <tt>textArea->clear()</tt> limpia el area de texto usando la misma función que conectaba con la <tt>KAction</tt> <tt>clear</tt> en el tutorial 3. | ||
Line 256: | Line 256: | ||
El prototipo de la función es: | El prototipo de la función es: | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
void MainWindow::saveFileAs(const QString &outputFileName) | void MainWindow::saveFileAs(const QString &outputFileName) | ||
</ | </syntaxhighlight> | ||
A continuación creamos nuestro objeto <tt>KSaveFile</tt> y lo abrimos con: | A continuación creamos nuestro objeto <tt>KSaveFile</tt> y lo abrimos con: | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
KSaveFile file(outputFileName); | KSaveFile file(outputFileName); | ||
file.open(); | file.open(); | ||
</ | </syntaxhighlight> | ||
Ahora que tenemos nuestro "file" para escribir, necesitamos convertir el texto del area de texto a un formato que pueda ser escrito en el archivo. Para hacer esto, creamos un {{qt|QByteArray}} y lo rellenamos con la versión en texto plano de lo que haya en el area de texto: | Ahora que tenemos nuestro "file" para escribir, necesitamos convertir el texto del area de texto a un formato que pueda ser escrito en el archivo. Para hacer esto, creamos un {{qt|QByteArray}} y lo rellenamos con la versión en texto plano de lo que haya en el area de texto: | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
QByteArray outputByteArray; | QByteArray outputByteArray; | ||
outputByteArray.append(textArea->toPlainText().toUtf8()); | outputByteArray.append(textArea->toPlainText().toUtf8()); | ||
</ | </syntaxhighlight> | ||
Ahora que tenemos nuestro <tt>QByteArray</tt>, lo usamos para escribir el archivo con <tt>KSaveFile::write()</tt>. Si estuvieramos usando un <tt>QFile</tt>, los cambios se reflejarían inmediatamente. Sin embargo, si se ha producido un problema parcial en la escritura, el archivo podría estar corrupto. Por esta razón, <tt>KSaveFile</tt> escribe primero en un archivo temporal y luego, en la llamada <tt>KSaveFile::Finalize</tt>, refleja los cambios en el archivo actual. | Ahora que tenemos nuestro <tt>QByteArray</tt>, lo usamos para escribir el archivo con <tt>KSaveFile::write()</tt>. Si estuvieramos usando un <tt>QFile</tt>, los cambios se reflejarían inmediatamente. Sin embargo, si se ha producido un problema parcial en la escritura, el archivo podría estar corrupto. Por esta razón, <tt>KSaveFile</tt> escribe primero en un archivo temporal y luego, en la llamada <tt>KSaveFile::Finalize</tt>, refleja los cambios en el archivo actual. | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
file.write(outputByteArray); | file.write(outputByteArray); | ||
file.finalize(); | file.finalize(); | ||
file.close(); | file.close(); | ||
</ | </syntaxhighlight> | ||
Por último, establecemos que <tt>fileName</tt> apunte al nombre del archivo que acabamos de guardar. | Por último, establecemos que <tt>fileName</tt> apunte al nombre del archivo que acabamos de guardar. | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
fileName = outputFileName; | fileName = outputFileName; | ||
</ | </syntaxhighlight> | ||
====saveFileAs()==== | ====saveFileAs()==== | ||
Line 286: | Line 286: | ||
Esta es la función a la que está conectado el slot <tt>saveAs</tt>. Simplemente llama a la función genérica <tt>saveFileAs(QString)</tt> pasandole el nombre del fichero devuelto por <tt>{{class|KFileDialog}}::[http://api.kde.org/4.0-api/kdelibs-apidocs/kio/html/classKFileDialog.html#8891356c249c5911e1ab15cc2739a89b getSaveFileName()]</tt>. | Esta es la función a la que está conectado el slot <tt>saveAs</tt>. Simplemente llama a la función genérica <tt>saveFileAs(QString)</tt> pasandole el nombre del fichero devuelto por <tt>{{class|KFileDialog}}::[http://api.kde.org/4.0-api/kdelibs-apidocs/kio/html/classKFileDialog.html#8891356c249c5911e1ab15cc2739a89b getSaveFileName()]</tt>. | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
void MainWindow::saveFileAs() | void MainWindow::saveFileAs() | ||
{ | { | ||
saveFileAs(KFileDialog::getSaveFileName()); | saveFileAs(KFileDialog::getSaveFileName()); | ||
} | } | ||
</ | </syntaxhighlight> | ||
Este es nuestro primer uso de la biblioteca KIO. La clase {{class|KFileDialog}} proporciona diferentes funciones estáticas para mostrar cuadros de dialgo estandar, usados en todas las aplicaciones de KDE. La llamada a <tt>KFileDialog::getSaveFileName()</tt> mostrará un diálogo donde el usuario puede seleccionar en nombre del archivo a guardar o elegir un nuevo nombre. La función devuelve el nombre del archivo, con el cual luego llamamos a <tt>saveFileAs(QString)</tt>. | Este es nuestro primer uso de la biblioteca KIO. La clase {{class|KFileDialog}} proporciona diferentes funciones estáticas para mostrar cuadros de dialgo estandar, usados en todas las aplicaciones de KDE. La llamada a <tt>KFileDialog::getSaveFileName()</tt> mostrará un diálogo donde el usuario puede seleccionar en nombre del archivo a guardar o elegir un nuevo nombre. La función devuelve el nombre del archivo, con el cual luego llamamos a <tt>saveFileAs(QString)</tt>. | ||
Line 297: | Line 297: | ||
====saveFile()==== | ====saveFile()==== | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
void MainWindow::saveFile() | void MainWindow::saveFile() | ||
{ | { | ||
Line 309: | Line 309: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
No hay nada destacable o nuevo en esta función, solamente la lógica para decidir si se muestra el dialogo para guardar el archivo. Si <tt>fileName</tt> no está vacio, el archivo es guardado como <tt>fileName</tt>. Si lo está, se muestra el diálogo para permitir al usuario elegir el nombre del archivo. | No hay nada destacable o nuevo en esta función, solamente la lógica para decidir si se muestra el dialogo para guardar el archivo. Si <tt>fileName</tt> no está vacio, el archivo es guardado como <tt>fileName</tt>. Si lo está, se muestra el diálogo para permitir al usuario elegir el nombre del archivo. | ||
Line 318: | Line 318: | ||
Primero debemos preguntar al usuario por en nombre del archivo que desea abrir. Esto lo hacemos usando otra de las funciones de <tt>KFileDialog</tt>, <tt>getOpenFileName()</tt>: | Primero debemos preguntar al usuario por en nombre del archivo que desea abrir. Esto lo hacemos usando otra de las funciones de <tt>KFileDialog</tt>, <tt>getOpenFileName()</tt>: | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
QString fileNameFromDialog = KFileDialog::getOpenFileName(); | QString fileNameFromDialog = KFileDialog::getOpenFileName(); | ||
</ | </syntaxhighlight> | ||
Luego usamos la biblioteca KIO para recuperar nuestro archivo. Esto nos permite abrir el archivo con QFile incluso si está almacenado en una ubicación remota, como un sitio FTP. Hacemos la siguiente llamada a la función <tt>download()</tt> de la clase {{class|NetAccess}}: | Luego usamos la biblioteca KIO para recuperar nuestro archivo. Esto nos permite abrir el archivo con QFile incluso si está almacenado en una ubicación remota, como un sitio FTP. Hacemos la siguiente llamada a la función <tt>download()</tt> de la clase {{class|NetAccess}}: | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
KIO::NetAccess::download(fileNameFromDialog, tmpFile, this) | KIO::NetAccess::download(fileNameFromDialog, tmpFile, this) | ||
</ | </syntaxhighlight> | ||
El primer argumento es el nombre del archivo que queremos descargar. El segundo es un QString el cual, una vez se haya completado la descarga, contendrá la localización de la copia temporal del archivo. Es con <tt>tmpFile</tt> con quien trabajaremos a partir de ahora. | El primer argumento es el nombre del archivo que queremos descargar. El segundo es un QString el cual, una vez se haya completado la descarga, contendrá la localización de la copia temporal del archivo. Es con <tt>tmpFile</tt> con quien trabajaremos a partir de ahora. | ||
La función devuelve <tt>true</tt> o <tt>false</tt> dependiendo si la transferencia tuvo exito. Si falló, mostraremos un mensaje informando del error: | La función devuelve <tt>true</tt> o <tt>false</tt> dependiendo si la transferencia tuvo exito. Si falló, mostraremos un mensaje informando del error: | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
KMessageBox::error(this, KIO::NetAccess::lastErrorString()); | KMessageBox::error(this, KIO::NetAccess::lastErrorString()); | ||
</ | </syntaxhighlight> | ||
En caso contrario, continuamos con la apertura del archivo. | En caso contrario, continuamos con la apertura del archivo. | ||
Creamos un QFile pasando a su constructor el archivo temporal creado por <tt>NetAccess::download()</tt> y lo abrirmos en modo de solo lectura: | Creamos un QFile pasando a su constructor el archivo temporal creado por <tt>NetAccess::download()</tt> y lo abrirmos en modo de solo lectura: | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
QFile file(tmpFile); | QFile file(tmpFile); | ||
file.open(QIODevice::ReadOnly); | file.open(QIODevice::ReadOnly); | ||
</ | </syntaxhighlight> | ||
Para mostrar el contenido del archivo debemos usar un {{qt|QTextStream}}. Creamos uno pasandole el contenido de nuestro archivo a su constructor, y llamamos a la función de QFile <tt>readAll()</tt> para obtener el texto del archivo. Luego este texto se le pasa a la función <tt>setPlainText()</tt> de nuestra área de texto. | Para mostrar el contenido del archivo debemos usar un {{qt|QTextStream}}. Creamos uno pasandole el contenido de nuestro archivo a su constructor, y llamamos a la función de QFile <tt>readAll()</tt> para obtener el texto del archivo. Luego este texto se le pasa a la función <tt>setPlainText()</tt> de nuestra área de texto. | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
textArea->setPlainText(QTextStream(&file).readAll()); | textArea->setPlainText(QTextStream(&file).readAll()); | ||
</ | </syntaxhighlight> | ||
A continuación almacenamos la ruta de acceso del archivo que acabamos de abrir: | A continuación almacenamos la ruta de acceso del archivo que acabamos de abrir: | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
fileName = fileNameFromDialog; | fileName = fileNameFromDialog; | ||
</ | </syntaxhighlight> | ||
y por último, eliminamos el archivo temporal que fué creado por <tt>NetAccess::download()</tt>: | y por último, eliminamos el archivo temporal que fué creado por <tt>NetAccess::download()</tt>: | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
KIO::NetAccess::removeTempFile(tmpFile); | KIO::NetAccess::removeTempFile(tmpFile); | ||
</ | </syntaxhighlight> | ||
==Make, instalar y ejecutar== | ==Make, instalar y ejecutar== | ||
===CMakeLists.txt=== | ===CMakeLists.txt=== | ||
< | <syntaxhighlight lang="ini" line> | ||
project(tutorial4) | project(tutorial4) | ||
Line 379: | Line 379: | ||
install(FILES tutorial4ui.rc | install(FILES tutorial4ui.rc | ||
DESTINATION ${DATA_INSTALL_DIR}/tutorial4) | DESTINATION ${DATA_INSTALL_DIR}/tutorial4) | ||
</ | </syntaxhighlight> | ||
Como ahora estamos usando la biblioteca KIO, debemos decirselo a CMAKE para que la enlace. Hacemos esto pasándole <tt>${KDE4_KIO_LIBS}</tt> a la función <tt>target_link_libraries()</tt> | Como ahora estamos usando la biblioteca KIO, debemos decirselo a CMAKE para que la enlace. Hacemos esto pasándole <tt>${KDE4_KIO_LIBS}</tt> a la función <tt>target_link_libraries()</tt> | ||
Latest revision as of 18:30, 15 July 2012
Serie | Tutorial para principiantes |
Requisitos previos | Tutorial 3 - KActions |
Siguiente | Tutorial 5 - Usar KCmdLineArgs |
Lectura avanzada | KIO::NetAccess QFile |
Resumen
Ahora que tenemos una interfaz básica del editor de textos, es hora de añadirle funcionalidad. Básicamente, un editor de textos debe abrir archivos desde disco, guardar archivos que has creado/editado y crear nuevos archivos.
KDE proporciona algunas clases para trabajar con archivos que hacen la vida mucho mas fácil a los desarrolladores. La biblioteca KIO te permite fácilmente tener acceso a archivos a través de protocolos de red transparentes, así como mediante cuadros de dialogo estándar.
El código
main.cpp
#include <KApplication>
#include <KAboutData>
#include <KCmdLineArgs>
#include "mainwindow.h"
int main (int argc, char *argv[])
{
KAboutData aboutData( "tutorial4", "tutorial4",
ki18n("Tutorial 4"), "1.0",
ki18n("A simple text area which can load and save."),
KAboutData::License_GPL,
ki18n("Copyright (c) 2008 Developer") );
KCmdLineArgs::init( argc, argv, &aboutData );
KApplication app;
MainWindow* window = new MainWindow();
window->show();
return app.exec();
}
main.cpp no ha cambiado desde el tutorial 3, excepto el cambio de cualquier referencia de tutorial 3 a tutorial 4.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <KXmlGuiWindow>
#include <KTextEdit>
class MainWindow : public KXmlGuiWindow
{
Q_OBJECT //nuevo respecto al tutorial3
public:
MainWindow(QWidget *parent=0);
private:
KTextEdit* textArea;
void setupActions();
QString fileName; //nuevo
private slots: //nuevo
void newFile(); //nuevo
void openFile(); //nuevo
void saveFile(); //nuevo
void saveFileAs(); //nuevo
void saveFileAs(const QString &outputFileName); //nuevo
};
#endif
Como queremos añadir la posibilidad de cargar y guardar archivos, debemos añadir las funciones que realizarán el trabajo. Ya que invocaremos a las funciones mediante el mecanismo de Qt signal/slot, debemos especificar que dichas funciones son slots, por lo que lo hacemos en la linea 19. Como estamos usando slots en el archivo cabecera, debemos también añadir la macro Q_OBJECT.
También queremos llevar un registro del nombre del archivo abierto actual, por lo que declaramos QString fileName.
mainwindow.cpp
#include "mainwindow.h"
#include <KApplication>
#include <KAction>
#include <KLocale>
#include <KActionCollection>
#include <KStandardAction>
#include <KFileDialog> //nuevo
#include <KMessageBox> //nuevo
#include <KIO/NetAccess> //nuevo
#include <KSaveFile> //nuevo
#include <QTextStream> //nuevo
MainWindow::MainWindow(QWidget *parent)
: KXmlGuiWindow(parent),
fileName(QString()) //nuevo
{
textArea = new KTextEdit;
setCentralWidget(textArea);
setupActions();
}
void MainWindow::setupActions()
{
KAction* clearAction = new KAction(this);
clearAction->setText(i18n("Limpiar"));
clearAction->setIcon(KIcon("document-new"));
clearAction->setShortcut(Qt::CTRL + Qt::Key_W);
actionCollection()->addAction("limpiar", clearAction);
connect(clearAction, SIGNAL(triggered(bool)),
textArea, SLOT(clear()));
KStandardAction::quit(kapp, SLOT(quit()),
actionCollection());
KStandardAction::open(this, SLOT(openFile()),
actionCollection()); //nuevo
KStandardAction::save(this, SLOT(saveFile()),
actionCollection()); //nuevo
KStandardAction::saveAs(this, SLOT(saveFileAs()),
actionCollection()); //nuevo
KStandardAction::openNew(this, SLOT(newFile()),
actionCollection()); //nuevo
setupGUI();
}
//Nuevo de aqui en adelante
void MainWindow::newFile()
{
fileName.clear();
textArea->clear();
}
void MainWindow::saveFileAs(const QString &outputFileName)
{
KSaveFile file(outputFileName);
file.open();
QByteArray outputByteArray;
outputByteArray.append(textArea->toPlainText().toUtf8());
file.write(outputByteArray);
file.finalize();
file.close();
fileName = outputFileName;
}
void MainWindow::saveFileAs()
{
saveFileAs(KFileDialog::getSaveFileName());
}
void MainWindow::saveFile()
{
if(!fileName.isEmpty())
{
saveFileAs(fileName);
}
else
{
saveFileAs();
}
}
void MainWindow::openFile()
{
QString fileNameFromDialog = KFileDialog::getOpenFileName();
QString tmpFile;
if(KIO::NetAccess::download(fileNameFromDialog, tmpFile, this))
{
QFile file(tmpFile);
file.open(QIODevice::ReadOnly);
textArea->setPlainText(QTextStream(&file).readAll());
fileName = fileNameFromDialog;
KIO::NetAccess::removeTempFile(tmpFile);
}
else
{
KMessageBox::error(this, KIO::NetAccess::lastErrorString());
}
}
tutorial4ui.rc
<?xml version="1.0" encoding="UTF-8"?>
<gui name="tutorial4"
version="1"
xmlns="http://www.kde.org/standards/kxmlgui/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0
http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd" >
<MenuBar>
<Menu name="file" >
<Action name="limpiar" />
</Menu>
</MenuBar>
<ToolBar name="mainToolBar" >
<text>Main Toolbar</text>
<Action name="limpiar" />
</ToolBar>
</gui>
Es idéntico a tutorial3ui.rc del tutorial 3 excepto name, que ha cambiado a 'tutorial4'. No necesitamos añadir ninguna información de las KStandardAction ya que la posición de esas acciones las maneja KDE automaticamente.
Explicación
Bien, ahora vamos a implementar el código que realizará el trabajo de cargar y guardar. Esto se lleva a cabo en mainwindow.cpp
Lo primero que hacemos es añadir
fileName(QString())
al constructor de MainWindow en la linea 16. Esto asegura que fileName esté vacio desde el principio.
Añadir las acciones
La primera cosa que vamos a hacer es proporcionar al usuario la interfaz para decirle a la aplicación que cargue o guarde un archivo. Como ya hicimos con la acción quit en el tutorial 3, usaremos KStandardActions. En las lineas 37-47 añadimos las acciones de la misma manera que la acción quit. Para cada una de ellas, la conectamos que el slot apropiado que hemos declarado en el archivo cabecera.
Crear un nuevo documento
La primera función que hemos definido es newFile().
void MainWindow::newFile()
{
fileName.clear();
textArea->clear();
}
Con fileName.clear() ponemos la QString como "vacia" para reflejar el hecho de que el documento aún no está presente en disco. A continuación, textArea->clear() limpia el area de texto usando la misma función que conectaba con la KAction clear en el tutorial 3.
Guardar un archivo
saveFileAs(QString)
Ahora vamos a escribir nuestro primer código que maneje archivos. Vamos a implementar una función que guardará el contenido del área de texto en un archivo con un nombre pasado como parámetro. KDE proporciona una clase llamada KSaveFile para guardar archivos de manera segura, que hereda de la clase de Qt QFile.
El prototipo de la función es:
void MainWindow::saveFileAs(const QString &outputFileName)
A continuación creamos nuestro objeto KSaveFile y lo abrimos con:
KSaveFile file(outputFileName);
file.open();
Ahora que tenemos nuestro "file" para escribir, necesitamos convertir el texto del area de texto a un formato que pueda ser escrito en el archivo. Para hacer esto, creamos un QByteArray y lo rellenamos con la versión en texto plano de lo que haya en el area de texto:
QByteArray outputByteArray;
outputByteArray.append(textArea->toPlainText().toUtf8());
Ahora que tenemos nuestro QByteArray, lo usamos para escribir el archivo con KSaveFile::write(). Si estuvieramos usando un QFile, los cambios se reflejarían inmediatamente. Sin embargo, si se ha producido un problema parcial en la escritura, el archivo podría estar corrupto. Por esta razón, KSaveFile escribe primero en un archivo temporal y luego, en la llamada KSaveFile::Finalize, refleja los cambios en el archivo actual.
file.write(outputByteArray);
file.finalize();
file.close();
Por último, establecemos que fileName apunte al nombre del archivo que acabamos de guardar.
fileName = outputFileName;
saveFileAs()
Esta es la función a la que está conectado el slot saveAs. Simplemente llama a la función genérica saveFileAs(QString) pasandole el nombre del fichero devuelto por KFileDialog::getSaveFileName().
void MainWindow::saveFileAs()
{
saveFileAs(KFileDialog::getSaveFileName());
}
Este es nuestro primer uso de la biblioteca KIO. La clase KFileDialog proporciona diferentes funciones estáticas para mostrar cuadros de dialgo estandar, usados en todas las aplicaciones de KDE. La llamada a KFileDialog::getSaveFileName() mostrará un diálogo donde el usuario puede seleccionar en nombre del archivo a guardar o elegir un nuevo nombre. La función devuelve el nombre del archivo, con el cual luego llamamos a saveFileAs(QString).
saveFile()
void MainWindow::saveFile()
{
if(!fileName.isEmpty())
{
saveFileAs(fileName);
}
else
{
saveFileAs();
}
}
No hay nada destacable o nuevo en esta función, solamente la lógica para decidir si se muestra el dialogo para guardar el archivo. Si fileName no está vacio, el archivo es guardado como fileName. Si lo está, se muestra el diálogo para permitir al usuario elegir el nombre del archivo.
Cargar un archivo
Por último, el tutorial 4 debe ser capaz de cargar archivos desde disco. El código para llevarlo a cabo se encuentra en la función MainWindow::openFile().
Primero debemos preguntar al usuario por en nombre del archivo que desea abrir. Esto lo hacemos usando otra de las funciones de KFileDialog, getOpenFileName():
QString fileNameFromDialog = KFileDialog::getOpenFileName();
Luego usamos la biblioteca KIO para recuperar nuestro archivo. Esto nos permite abrir el archivo con QFile incluso si está almacenado en una ubicación remota, como un sitio FTP. Hacemos la siguiente llamada a la función download() de la clase NetAccess:
KIO::NetAccess::download(fileNameFromDialog, tmpFile, this)
El primer argumento es el nombre del archivo que queremos descargar. El segundo es un QString el cual, una vez se haya completado la descarga, contendrá la localización de la copia temporal del archivo. Es con tmpFile con quien trabajaremos a partir de ahora.
La función devuelve true o false dependiendo si la transferencia tuvo exito. Si falló, mostraremos un mensaje informando del error:
KMessageBox::error(this, KIO::NetAccess::lastErrorString());
En caso contrario, continuamos con la apertura del archivo.
Creamos un QFile pasando a su constructor el archivo temporal creado por NetAccess::download() y lo abrirmos en modo de solo lectura:
QFile file(tmpFile);
file.open(QIODevice::ReadOnly);
Para mostrar el contenido del archivo debemos usar un QTextStream. Creamos uno pasandole el contenido de nuestro archivo a su constructor, y llamamos a la función de QFile readAll() para obtener el texto del archivo. Luego este texto se le pasa a la función setPlainText() de nuestra área de texto.
textArea->setPlainText(QTextStream(&file).readAll());
A continuación almacenamos la ruta de acceso del archivo que acabamos de abrir:
fileName = fileNameFromDialog;
y por último, eliminamos el archivo temporal que fué creado por NetAccess::download():
KIO::NetAccess::removeTempFile(tmpFile);
Make, instalar y ejecutar
CMakeLists.txt
project(tutorial4)
find_package(KDE4 REQUIRED)
include_directories(${KDE4_INCLUDES})
set(tutorial4_SRCS
main.cpp
mainwindow.cpp
)
kde4_add_executable(tutorial4 ${tutorial4_SRCS})
target_link_libraries(tutorial4 ${KDE4_KDEUI_LIBS}
${KDE4_KIO_LIBS})
install(TARGETS tutorial4 DESTINATION ${BIN_INSTALL_DIR})
install(FILES tutorial4ui.rc
DESTINATION ${DATA_INSTALL_DIR}/tutorial4)
Como ahora estamos usando la biblioteca KIO, debemos decirselo a CMAKE para que la enlace. Hacemos esto pasándole ${KDE4_KIO_LIBS} a la función target_link_libraries()
Con este archivo, puede construirse y ejecutar el tutorial de la misma forma que el tutorial 3. Para mas información, ve al tutorial 3.
mkdir build && cd build cmake .. -DCMAKE_INSTALL_PREFIX=$HOME make install $HOME/bin/tutorial4
Avanzando
Ahora puedes continuar con el Tutorial 5 - KCmdLineArgs