Difference between revisions of "Development/Tutorials/Saving and loading"

Jump to: navigation, search
(All the info on KSaveFile)
(A bit of planning ahead)
Line 5: Line 5:
 
series=Beginner Tutorial|
 
series=Beginner Tutorial|
  
name=Loading and saving files|
+
name=Loading and saving files (Under construction [[User:milliams]])|
  
 
pre=[[Development/Tutorials/Using_KActions|Tutorial 3 - KActions]]|
 
pre=[[Development/Tutorials/Using_KActions|Tutorial 3 - KActions]]|
  
next=TODO (milliams)|  
+
next=KCmdLineArgs (TODO [[User:milliams]])|  
  
 
reading=KIO::{{class|NetAccess}} {{qt|QFile}}
 
reading=KIO::{{class|NetAccess}} {{qt|QFile}}
Line 301: Line 301:
 
  make install
 
  make install
 
  $HOME/bin/tutorial4
 
  $HOME/bin/tutorial4
 +
 +
==Moving On==
 +
Now you can move on to KCmdLineArgs (TODO [[User:milliams]]).
 +
 +
[[Category:C++]]

Revision as of 20:32, 26 December 2007


Contents

Development/Tutorials/Saving_and_loading


Loading and saving files (Under construction User:milliams)
Tutorial Series   Beginner Tutorial
Previous   Tutorial 3 - KActions
What's Next   KCmdLineArgs (TODO User:milliams)
Further Reading   KIO::NetAccess QFile

Abstract

Now that we have a basic text editor interface, it's time to make it do something useful.At the most basic a text editor needs to be able to load files from disc, save files that you've created or edited and create new files.

KDE provides a number of classes for working with files which make life a lot easier for developers. The KIO library allows you to easily access files through network-transparent protocols as well as providing standard file dialogs.

Introtokdetutorial4.png

The Code

main.cpp

  1. include <KApplication>
  2. include <KAboutData>
  3. include <KCmdLineArgs>
  1. 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) 2007 Developer") );
 KCmdLineArgs::init( argc, argv, &aboutData );
 KApplication app;

 MainWindow* window = new MainWindow();
 window->show();
 return app.exec();

} main.cpp hasn't changed from tutorial 3 except to change any reference to tutorial 3 to tutorial 4.

mainwindow.h

  1. ifndef MAINWINDOW_H
  2. define MAINWINDOW_H
  1. include <KXmlGuiWindow>
  2. include <KTextEdit>

class MainWindow : public KXmlGuiWindow {

 Q_OBJECT //new from tutorial3
 
 public:
   MainWindow(QWidget *parent=0);
 
 private:
   KTextEdit* textArea;
   void setupActions();
   QString fileName; //new
 private slots: //new
   void newFile(); //new
   void openFile(); //new
   void saveFile(); //new
   void saveFileAs(); //new
   void saveFileAs(const QString &outputFileName); //new

};

  1. endif

Since we want to add the ability to load and save files, we must add the functions which will do the work. Since the functions will be called through Qt's signal/slot mechanism we must specify that these functions are slots as we do on line 19. Since we are using slots in this header file, we must also add the Q_OBJECT macro.

We also want to keep track of the filename of the currently opened file so we create a QString fileName.

mainwindow.cpp

  1. include "mainwindow.h"
  1. include <KApplication>
  2. include <KAction>
  3. include <KLocale>
  4. include <KActionCollection>
  5. include <KStandardAction>
  6. include <KFileDialog> //new
  7. include <KMessageBox> //new
  8. include <KIO/NetAccess> //new
  9. include <KSaveFile> //new
  10. include <QTextStream> //new

MainWindow::MainWindow(QWidget *parent)

   : KXmlGuiWindow(parent),
     fileName(QString()) //new

{

 textArea = new KTextEdit;
 setCentralWidget(textArea);

 setupActions();

}

void MainWindow::setupActions() {

 KAction* clearAction = new KAction(this);
 clearAction->setText(i18n("Clear"));
 clearAction->setIcon(KIcon("document-new"));
 clearAction->setShortcut(Qt::CTRL + Qt::Key_W);
 actionCollection()->addAction("clear", clearAction);
 connect(clearAction, SIGNAL(triggered(bool)),
         textArea, SLOT(clear()));

 KStandardAction::quit(kapp, SLOT(quit()),
                       actionCollection());

 KStandardAction::open(this, SLOT(openFile()),
                       actionCollection()); //new

 KStandardAction::save(this, SLOT(saveFile()),
                       actionCollection()); //new

 KStandardAction::saveAs(this, SLOT(saveFileAs()),
                       actionCollection()); //new

 KStandardAction::openNew(this, SLOT(newFile()),
                       actionCollection()); //new

 setupGUI();

}

//New from here on

void MainWindow::newFile() {

 fileName.clear();
 textArea->clear();

}

void MainWindow::saveFileAs(const QString &outputFileName) {

 KSaveFile file(outputFileName);
 file.open();
 
 QByteArray outputByteArray;
 outputByteArray.append(textArea->toPlainText());
 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"?> <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> <gui name="tutorial4" version="1">

 <ToolBar name="mainToolBar" >
   <text>Main Toolbar</text>
   <Action name="clear" />
 </ToolBar>
 <MenuBar>
   <Menu name="file" >
     <Action name="clear" />
   </Menu>
 </MenuBar>

</gui> This is identical to tutorial3ui.rc from tutorial 3 except the name has changed to 'tutorial4'. We do not need to add any information about any of the KStandardActions since the placement of those actions is handled automatically by KDE.

Explanation

Okay, now to implement the code that will do the loading and saving.

The first thing we do is add fileName(QString()) to the MainWindow constructor list on line 16. This makes sure that fileName is empty right from the beginning.

Adding the actions

The first thing we are going to do is provide the outward interface for the user so they can tell the application to load and save. Like with the quit action in tutorial 3, we will use KStandardActions. On lines 37 to 47 we add the actions in the same way as for the quit action. For each one, we connect it to the appropriate slot that we declared in the header file.

Creating a new document

The first function we create is the newFile() function. void MainWindow::newFile() {

 fileName.clear();
 textArea->clear();

} fileName.clear() sets the fileName QString to be empty to reflect the fact that this document does not yet have a presence on disc. textArea->clear() then clears the central text area using the same function that we connected the clear KAction to in tutorial 3.

Saving a file

Now we get onto our first file handling code. We're going to implement a function which will save the contents of the text area to the file name given as a parameter. KDE provides a class for safely saving a file called KSaveFile which is derived from Qt's QFile.

The function's prototype is void MainWindow::saveFileAs(const QString &outputFileName)

We then create our KSaveFile object and open it with KSaveFile file(outputFileName); file.open();

Now that we have out file to write to, we need to format the text in the text area to a format which can be written to file. For this, we create a QByteArray and fill it with the plain text version of whatever is in the text area: QByteArray outputByteArray; outputByteArray.append(textArea->toPlainText()); Now that we have our QByteArray, we use it to write to the file with KSaveFile::write(). If we were using a normal QFile, this would make the changes immediately. However, if a problem occurred partway through writing, the file would become corrupted. For this reason, KSaveFile works by first writing to a temporary file and then, when you call KSaveFile::finalize() the changes are made to the actual file. file.write(outputByteArray); file.finalize(); file.close(); Finally, we set MainWindows's fileName member to point to the file name we just saved to.

Make, Install And Run

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)

Since we are now using the KIO library, we must tell CMake to link against it. We do this by passing ${KDE4_KIO_LIBS} to the target_link_libraries() function.

With this file, the tutorial can built and run in the same way as tutorial 3. For more information, see tutorial 3.

mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME
make install
$HOME/bin/tutorial4

Moving On

Now you can move on to KCmdLineArgs (TODO User:milliams).


KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V.Legal