Export translations SettingsGroupCategory:PhononContribute/List of KDE ModulesDevelopmentDevelopment/FAQs/General FAQDevelopment/FAQs/Technical FAQDevelopment/KDevelop-PG-Qt IntroductionDevelopment/ToolsDevelopment/TutorialsDevelopment/Tutorials/CommandLineArgumentsDevelopment/Tutorials/Common Programming MistakesDevelopment/Tutorials/First programDevelopment/Tutorials/First program/KDE4Development/Tutorials/First program/KF5Development/Tutorials/KDE3/Qt Designer and KDevelop 3.0 for BeginnersDevelopment/Tutorials/Metadata/Nepomuk/TipsAndTricksDevelopment/Tutorials/Physical SimulationDevelopment/Tutorials/Qt4 Ruby TutorialDevelopment/Tutorials/Qt4 Ruby Tutorial/Chapter 01Development/Tutorials/Qt4 Ruby Tutorial/Chapter 04Development/Tutorials/Qt4 Ruby Tutorial/Chapter 05Development/Tutorials/Qt4 Ruby Tutorial/Chapter 06Development/Tutorials/Qt4 Ruby Tutorial/Chapter 07Development/Tutorials/Qt4 Ruby Tutorial/Chapter 08Development/Tutorials/Qt4 Ruby Tutorial/Chapter 09Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14Development/Tutorials/Qt4 Ruby Tutorial/Chapter 2Development/Tutorials/Qt4 Ruby Tutorial/Chapter 3Development/Tutorials/Saving and loadingDevelopment/Tutorials/Setting UpDevelopment/Tutorials/Using ActionsDevelopment/Tutorials/Using KXmlGuiWindowDocumentation PrimerEdit MarkupGetting StartedHelp:ContentsHelp:ContributeHow To Convert a UserBase Manual to DocbookKDE FrameworksKDE Frameworks/Getting StartedKDE Frameworks/Getting Started/Source CodeKDE TechBase:AboutKDE TechBase:ContributorsKDE TechBase:General disclaimerKDE TechBase:Privacy policyOff-line TranslationProjects/Calligra/Plugin TutorialsToolboxTranslate a PageTranslation WorkflowTypographical GuidelinesUser:NeverendingoWelcome to KDE TechBaseLanguageaa - Afarab - Abkhazianabs - Ambonese Malayace - Achineseady - Adygheady-cyrl - Adyghe (Cyrillic script)aeb - Tunisian Arabicaeb-arab - Tunisian Arabic (Arabic script)aeb-latn - Tunisian Arabic (Latin script)af - Afrikaansak - Akanaln - Gheg Albanianalt - Southern Altaiam - Amharicami - Amisan - Aragoneseang - Old Englishanp - Angikaar - Arabicarc - Aramaicarn - Mapuchearq - Algerian Arabicary - Moroccan Arabicarz - Egyptian Arabicas - Assamesease - American Sign Languageast - Asturianatj - Atikamekwav - Avaricavk - Kotavaawa - Awadhiay - Aymaraaz - Azerbaijaniazb - South Azerbaijaniba - Bashkirban - Balinesebar - Bavarianbbc - Batak Tobabbc-latn - Batak Toba (Latin script)bcc - Southern Balochibcl - Central Bikolbe - Belarusianbe-tarask - Belarusian (Taraškievica orthography)bg - Bulgarianbgn - Western Balochibh - Bhojpuribho - Bhojpuribi - Bislamabjn - Banjarbm - Bambarabn - Banglabo - Tibetanbpy - Bishnupriyabqi - Bakhtiaribr - Bretonbrh - Brahuibs - Bosnianbtm - Batak Mandailingbto - Iriga Bicolanobug - Buginesebxr - Russia Buriatca - Catalancbk-zam - Chavacanocdo - Min Dong Chinesece - Chechenceb - Cebuanoch - Chamorrocho - Choctawchr - Cherokeechy - Cheyenneckb - Central Kurdishco - Corsicancps - Capiznoncr - Creecrh - Crimean Turkishcrh-cyrl - Crimean Tatar (Cyrillic script)crh-latn - Crimean Tatar (Latin script)cs - Czechcsb - Kashubiancu - Church Slaviccv - Chuvashcy - Welshda - Danishde - Germande-at - Austrian Germande-ch - Swiss High Germande-formal - German (formal address)din - Dinkadiq - Zazakidsb - Lower Sorbiandtp - Central Dusundty - Dotelidv - Divehidz - Dzongkhaee - Eweegl - Emilianel - Greekeml - Emiliano-Romagnoloen - Englishen-ca - Canadian Englishen-gb - British Englisheo - Esperantoes - Spanishes-419 - Latin American Spanishes-formal - español (formal)et - Estonianeu - Basqueext - Extremaduranfa - Persianff - Fulahfi - Finnishfit - Tornedalen Finnishfj - Fijianfo - Faroesefr - Frenchfrc - Cajun Frenchfrp - Arpitanfrr - Northern Frisianfur - Friulianfy - Western Frisianga - Irishgag - Gagauzgan - Gan Chinesegan-hans - Gan (Simplified)gan-hant - Gan (Traditional)gcr - Guianan Creolegd - Scottish Gaelicgl - Galicianglk - Gilakign - Guaranigom - Goan Konkanigom-deva - Goan Konkani (Devanagari script)gom-latn - Goan Konkani (Latin script)gor - Gorontalogot - Gothicgrc - Ancient Greekgsw - Swiss Germangu - Gujaratigv - Manxha - Hausahak - Hakka Chinesehaw - Hawaiianhe - Hebrewhi - Hindihif - Fiji Hindihif-latn - Fiji Hindi (Latin script)hil - Hiligaynonho - Hiri Motuhr - Croatianhrx - Hunsrikhsb - Upper Sorbianht - Haitian Creolehu - Hungarianhu-formal - magyar (formal)hy - Armenianhyw - Western Armenianhz - Hereroia - Interlinguaid - Indonesianie - Interlingueig - Igboii - Sichuan Yiik - Inupiaqike-cans - Eastern Canadian (Aboriginal syllabics)ike-latn - Eastern Canadian (Latin script)ilo - Ilokoinh - Ingushio - Idois - Icelandicit - Italianiu - Inuktitutja - Japanesejam - Jamaican Creole Englishjbo - Lojbanjut - Jutishjv - Javaneseka - Georgiankaa - Kara-Kalpakkab - Kabylekbd - Kabardiankbd-cyrl - Kabardian (Cyrillic script)kbp - Kabiyekg - Kongokhw - Khowarki - Kikuyukiu - Kirmanjkikj - Kuanyamakjp - Eastern Pwokk - Kazakhkk-arab - Kazakh (Arabic script)kk-cn - Kazakh (China)kk-cyrl - Kazakh (Cyrillic script)kk-kz - Kazakh (Kazakhstan)kk-latn - Kazakh (Latin script)kk-tr - Kazakh (Turkey)kl - Kalaallisutkm - Khmerkn - Kannadako - Koreanko-kp - Korean (North Korea)koi - Komi-Permyakkr - Kanurikrc - Karachay-Balkarkri - Kriokrj - Kinaray-akrl - Karelianks - Kashmiriks-arab - Kashmiri (Arabic script)ks-deva - Kashmiri (Devanagari script)ksh - Colognianku - Kurdishku-arab - Kurdish (Arabic script)ku-latn - Kurdish (Latin script)kum - Kumykkv - Komikw - Cornishky - Kyrgyzla - Latinlad - Ladinolb - Luxembourgishlbe - Laklez - Lezghianlfn - Lingua Franca Novalg - Gandali - Limburgishlij - Ligurianliv - Livonianlki - Lakilld - Ladinlmo - Lombardln - Lingalalo - Laoloz - Lozilrc - Northern Lurilt - Lithuanianltg - Latgalianlus - Mizoluz - Southern Lurilv - Latvianlzh - Literary Chineselzz - Lazmai - Maithilimap-bms - Basa Banyumasanmdf - Mokshamg - Malagasymh - Marshallesemhr - Eastern Marimi - Maorimin - Minangkabaumk - Macedonianml - Malayalammn - Mongolianmni - Manipurimnw - Monmo - Moldovanmr - Marathimrj - Western Marims - Malaymt - Maltesemus - Muscogeemwl - Mirandesemy - Burmesemyv - Erzyamzn - Mazanderanina - Naurunah - Nāhuatlnan - Min Nan Chinesenap - Neapolitannb - Norwegian Bokmålnds - Low Germannds-nl - Low Saxonne - Nepalinew - Newaring - Ndonganiu - Niueannl - Dutchnl-informal - Nederlands (informeel)nn - Norwegian Nynorskno - Norwegiannov - Novialnqo - N’Konrm - Normannso - Northern Sothonv - Navajony - Nyanjanys - Nyungaroc - Occitanolo - Livvi-Karelianom - Oromoor - Odiaos - Osseticpa - Punjabipag - Pangasinanpam - Pampangapap - Papiamentopcd - Picardpdc - Pennsylvania Germanpdt - Plautdietschpfl - Palatine Germanpi - Palipih - Norfuk / Pitkernpl - Polishpms - Piedmontesepnb - Western Punjabipnt - Ponticprg - Prussianps - Pashtopt - Portuguesept-br - Brazilian Portuguesequ - Quechuaqug - Chimborazo Highland Quichuargn - Romagnolrif - Riffianrm - Romanshrmy - Vlax Romanirn - Rundiro - Romanianroa-tara - Tarantinoru - Russianrue - Rusynrup - Aromanianruq - Megleno-Romanianruq-cyrl - Megleno-Romanian (Cyrillic script)ruq-latn - Megleno-Romanian (Latin script)rw - Kinyarwandasa - Sanskritsah - Sakhasat - Santalisc - Sardinianscn - Siciliansco - Scotssd - Sindhisdc - Sassarese Sardiniansdh - Southern Kurdishse - Northern Samisei - Serises - Koyraboro Sennisg - Sangosgs - Samogitiansh - Serbo-Croatianshi - Tachelhitshi-latn - Tachelhit (Latin script)shi-tfng - Tachelhit (Tifinagh script)shn - Shanshy-latn - Shawiya (Latin script)si - Sinhalasimple - Simple Englishsk - Slovakskr - Saraikiskr-arab - Saraiki (Arabic script)sl - Sloveniansli - Lower Silesiansm - Samoansma - Southern Samismn - Inari Samisn - Shonaso - Somalisq - Albaniansr - Serbiansr-ec - Serbian (Cyrillic script)sr-el - Serbian (Latin script)srn - Sranan Tongoss - Swatist - Southern Sothostq - Saterland Frisiansty - себертатарsu - Sundanesesv - Swedishsw - Swahiliszl - Silesianszy - Sakizayata - Tamiltay - Tayaltcy - Tulute - Telugutet - Tetumtg - Tajiktg-cyrl - Tajik (Cyrillic script)tg-latn - Tajik (Latin script)th - Thaiti - Tigrinyatk - Turkmentl - Tagalogtly - Talyshtn - Tswanato - Tongantpi - Tok Pisintr - Turkishtru - Turoyotrv - Tarokots - Tsongatt - Tatartt-cyrl - Tatar (Cyrillic script)tt-latn - Tatar (Latin script)tum - Tumbukatw - Twity - Tahitiantyv - Tuviniantzm - Central Atlas Tamazightudm - Udmurtug - Uyghurug-arab - Uyghur (Arabic script)ug-latn - Uyghur (Latin script)uk - Ukrainianur - Urduuz - Uzbekuz-cyrl - Uzbek (Cyrillic script)uz-latn - Uzbek (Latin script)ve - Vendavec - Venetianvep - Vepsvi - Vietnamesevls - West Flemishvmf - Main-Franconianvo - Volapükvot - Voticvro - Võrowa - Walloonwar - Waraywo - Wolofwuu - Wu Chinesexal - Kalmykxh - Xhosaxmf - Mingrelianxsy - Saisiyatyi - Yiddishyo - Yorubayue - Cantoneseza - Zhuangzea - Zeelandiczgh - Standard Moroccan Tamazightzh - Chinesezh-cn - Chinese (China)zh-hans - Simplified Chinesezh-hant - Traditional Chinesezh-hk - Chinese (Hong Kong)zh-mo - Chinese (Macau)zh-my - Chinese (Malaysia)zh-sg - Chinese (Singapore)zh-tw - Chinese (Taiwan)zu - Zuluqqq - Message documentationFormatExport for off-line translationExport in native format Fetch <languages/> {{TutorialBrowser| series=Beginner Tutorial| name=Loading and saving files| pre=[[Development/Tutorials/Using_Actions|Tutorial 3 - Actions]]| next=[[Development/Tutorials/CommandLineArguments|Tutorial 5 - Using Command Line Arguments]]| reading=[[Development/Tutorials/KIO Slaves/Using KIO Slaves in your Program|Tutorial: Using KIO Slaves in your Program]] KIO::{{class|NetAccess}} {{qt|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 data storage, save files that you've created/edited, and create new files. The KDE Frameworks provides a number of classes for working with files that make life a lot easier for developers. The KIO framework allows you to easily access files through network-transparent protocols. At the same time, Qt also provides standard file dialogs for opening and saving files. [[image:tutorial4-kf5.png|frame|center]] == The Code == ===main.cpp=== <syntaxhighlight lang="cpp-qt"> #include <cstdlib> #include <QApplication> #include <QCommandLineParser> #include <KAboutData> #include <KLocalizedString> #include "mainwindow.h" int main (int argc, char *argv[]) { QApplication app(argc, argv); KLocalizedString::setApplicationDomain("tutorial4"); KAboutData aboutData( // The program name used internally. (componentName) QStringLiteral("tutorial4"), // A displayable program name string. (displayName) i18n("Tutorial 4"), // The program version string. (version) QStringLiteral("1.0"), // Short description of what the app does. (shortDescription) i18n("A simple text area which can load and save."), // The license this code is released under KAboutLicense::GPL, // Copyright Statement (copyrightStatement = QString()) i18n("(c) 2015"), // Optional text shown in the About box. // Can contain any information desired. (otherText) i18n("Some text..."), // The program homepage string. (homePageAddress = QString()) QStringLiteral("http://example.com/"), // The bug report email address // (bugsEmailAddress = QLatin1String("submit@bugs.kde.org") QStringLiteral("submit@bugs.kde.org")); aboutData.addAuthor(i18n("Name"), i18n("Task"), QStringLiteral("your@email.com"), QStringLiteral("http://your.website.com"), QStringLiteral("OSC Username")); KAboutData::setApplicationData(aboutData); QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); MainWindow* window = new MainWindow(); window->show(); return app.exec(); } </syntaxhighlight> <tt>main.cpp</tt> hasn't changed from tutorial 3 except to change any reference from tutorial 3 to tutorial 4. ===mainwindow.h=== <syntaxhighlight lang="cpp-qt"> #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <KXmlGuiWindow> class KTextEdit; class KJob; class MainWindow : public KXmlGuiWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); private: void setupActions(); private slots: void newFile(); void openFile(); void saveFile(); void saveFileAs(); void saveFileAs(const QString &outputFileName); void downloadFinished(KJob* job); private: KTextEdit* textArea; QString fileName; }; #endif </syntaxhighlight> 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 [http://doc.qt.io/qt-5/signalsandslots.html signal/slot] mechanism we must specify that these functions are slots. Since we are using slots in this header file, we must also add the [http://doc.qt.io/qt-5/qobject.html#Q_OBJECT <tt>Q_OBJECT</tt>] macro. We also want to keep track of the filename of the currently opened file so we declare a <tt>[http://doc.qt.io/qt-5/qstring.html QString] fileName</tt>. ===mainwindow.cpp=== <syntaxhighlight lang="cpp-qt"> #include <QApplication> #include <QAction> #include <QSaveFile> #include <QFileDialog> #include <QTextStream> #include <QByteArray> #include <KTextEdit> #include <KLocalizedString> #include <KActionCollection> #include <KStandardAction> #include <KMessageBox> #include <KIO/Job> #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : KXmlGuiWindow(parent), fileName(QString()) { textArea = new KTextEdit(); setCentralWidget(textArea); setupActions(); } void MainWindow::setupActions() { QAction* clearAction = new QAction(this); clearAction->setText(i18n("&Clear")); clearAction->setIcon(QIcon::fromTheme("document-new")); actionCollection()->setDefaultShortcut(clearAction, Qt::CTRL + Qt::Key_W); actionCollection()->addAction("clear", clearAction); connect(clearAction, SIGNAL(triggered(bool)), textArea, SLOT(clear())); KStandardAction::quit(qApp, SLOT(quit()), actionCollection()); KStandardAction::open(this, SLOT(openFile()), actionCollection()); KStandardAction::save(this, SLOT(saveFile()), actionCollection()); KStandardAction::saveAs(this, SLOT(saveFileAs()), actionCollection()); KStandardAction::openNew(this, SLOT(newFile()), actionCollection()); setupGUI(Default, "tutorial4ui.rc"); } void MainWindow::newFile() { fileName.clear(); textArea->clear(); } void MainWindow::saveFileAs(const QString &outputFileName) { if (!outputFileName.isNull()) { QSaveFile file(outputFileName); file.open(QIODevice::WriteOnly); QByteArray outputByteArray; outputByteArray.append(textArea->toPlainText().toUtf8()); file.write(outputByteArray); file.commit(); fileName = outputFileName; } } void MainWindow::saveFileAs() { saveFileAs(QFileDialog::getSaveFileName(this, i18n("Save File As"))); } void MainWindow::saveFile() { if (!fileName.isEmpty()) { saveFileAs(fileName); } else { saveFileAs(); } } void MainWindow::openFile() { QUrl fileNameFromDialog = QFileDialog::getOpenFileUrl(this, i18n("Open File")); if (!fileNameFromDialog.isEmpty()) { KIO::Job* job = KIO::storedGet(fileNameFromDialog); fileName = fileNameFromDialog.toLocalFile(); connect(job, SIGNAL(result(KJob*)), this, SLOT(downloadFinished(KJob*))); job->exec(); } } void MainWindow::downloadFinished(KJob* job) { if (job->error()) { KMessageBox::error(this, job->errorString()); fileName.clear(); return; } KIO::StoredTransferJob* storedJob = (KIO::StoredTransferJob*)job; textArea->setPlainText(QTextStream(storedJob->data(), QIODevice::ReadOnly).readAll()); } </syntaxhighlight> We'll get into the details of <tt>mainwindow.cpp</tt> in a while. ===tutorial4ui.rc=== <syntaxhighlight lang="xml"> <?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="clear" /> </Menu> </MenuBar> <ToolBar name="mainToolBar" > <text>Main Toolbar</text> <Action name="clear" /> </ToolBar> </gui> </syntaxhighlight> This is identical to <tt>tutorial3ui.rc</tt> from tutorial 3 except the <tt>name</tt> has changed to 'tutorial4'. We do not need to add any information about any of the <tt>KStandardAction</tt>s 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. This will all be happening in <tt>mainwindow.cpp</tt> The first thing we do is add <tt>fileName(QString())</tt> to the <tt>MainWindow</tt> constructor list to make sure that <tt>fileName</tt> 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 <tt>quit</tt> action in tutorial 3, we will use <tt>KStandardActions</tt>. We add the actions in the same way as for the <tt>quit</tt> action and, 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 <tt>newFile()</tt> function. <syntaxhighlight lang="cpp-qt"> void MainWindow::newFile() { fileName.clear(); textArea->clear(); } </syntaxhighlight> <tt>fileName.clear()</tt> sets the <tt>fileName</tt> QString to be empty to reflect the fact that this document does not yet have a presence on storage. <tt>textArea->clear()</tt> then clears the central text area using the same function that we connected the <tt>clear</tt> <tt>KQction</tt> to in tutorial 3. {{Warning|This simple example simply clears the text area without checking if the file has been saved first. It's only meant as a demonstration of file I/O and not as an example of best programming practices.}} ===Saving a file=== {{Note|To make this tutorial simple, this example program can only save to local storage even though it can open any file from any location, even those from remote sources.}} ====saveFileAs(QString)==== 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. Qt provides a class for safely saving a file called [http://doc.qt.io/qt-5/qsavefile.html QSaveFile]. The function's prototype is <syntaxhighlight lang="cpp-qt"> void MainWindow::saveFileAs(const QString &outputFileName) </syntaxhighlight> We then create our <tt>QSaveFile</tt> object and open it with <syntaxhighlight lang="cpp-qt"> QSaveFile file(outputFileName); file.open(QIODevice::WriteOnly); </syntaxhighlight> Now that we have our 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 [http://doc.qt.io/qt-5/qbytearray.html QByteArray] and fill it with the plain text version of whatever is in the text area: <syntaxhighlight lang="cpp-qt"> QByteArray outputByteArray; outputByteArray.append(textArea->toPlainText().toUtf8()); </syntaxhighlight> Now that we have our <tt>QByteArray</tt>, we use it to write to the file with <tt>QSaveFile::write()</tt>. If we were using a normal <tt>QFile</tt>, this would make the changes immediately. However, if a problem occurred partway through writing, the file would become corrupted. For this reason, <tt>QSaveFile</tt> works by first writing to a temporary file and then, when you call <tt>QSaveFile::commit()</tt> the changes are made to the actual file. <tt>commit()</tt> also closes the file. <syntaxhighlight lang="cpp-qt"> file.write(outputByteArray); file.commit(); </syntaxhighlight> Finally, we set <tt>MainWindows</tt>'s <tt>fileName</tt> member to point to the file name we just saved to. <syntaxhighlight lang="cpp-qt"> fileName = outputFileName; </syntaxhighlight> ====saveFileAs()==== This is the function that the <tt>saveAs</tt> slot is connected to. It simply calls the generic <tt>saveFileAs(QString)</tt> function and passes the file name returned by <tt>[http://doc.qt.io/qt-5/qfiledialog.html QFileDialog]::[http://doc.qt.io/qt-5/qfiledialog.html#getSaveFileName getSaveFileName()]</tt>. <syntaxhighlight lang="cpp-qt"> void MainWindow::saveFileAs() { saveFileAs(QFileDialog::getSaveFileName(this, i18n("Save File As"))); } </syntaxhighlight> [http://doc.qt.io/qt-5/qfiledialog.html QFileDialog] provides a number of static functions for displaying the common file dialog that is used by all KDE applications. Calling <tt>QFileDialog::getSaveFileName()</tt> will display a dialog where the user can select the name of the file to save to or choose a new name. The function returns the full file name, which we then pass to <tt>saveFileAs(QString)</tt>. ====saveFile()==== <syntaxhighlight lang="cpp-qt"> void MainWindow::saveFile() { if(!fileName.isEmpty()) { saveFileAs(fileName); } else { saveFileAs(); } } </syntaxhighlight> There's nothing exciting or new in this function, just the logic to decide whether or not to show the save dialog. If <tt>fileName</tt> is not empty, then the file is saved to <tt>fileName</tt>. But if it is, then the dialog is shown to allow the user to select a file name. ===Loading a file=== Finally, we get round to being able to load a file, from local storage or from a remote location like an FTP server. The code for this is all contained in <tt>MainWindow::openFile()</tt>. First we must ask the user for the name of the file they wish to open. We do this using another one of the <tt>QFileDialog</tt> functions, this time <tt>getOpenFileName()</tt>: <syntaxhighlight lang="cpp-qt"> QUrl fileNameFromDialog = QFileDialog::getOpenFileUrl(this, i18n("Open File")); </syntaxhighlight> Here we use the QUrl class to handle files from remote locations. Then we use the KIO library to retrieve our file. This allows us to open the file normally even if it's stored in a remote location like an FTP site. We make the following call to the <tt>[http://api.kde.org/frameworks-api/frameworks5-apidocs/kio/html/namespaceKIO.html#a17631774b47cddb0127d8a3c1fc2315c KIO::storedGet()]</tt> function with an argument for the file you wish to open or download: <syntaxhighlight lang="cpp-qt"> KIO::Job* job = KIO::storedGet(fileNameFromDialog); </syntaxhighlight> The function returns a handle to a <tt>KIO::Job</tt>, which we first connect to our <tt>downloadFinished()</tt> slot before "running" the job. <syntaxhighlight lang="cpp-qt"> connect(job, SIGNAL(result(KJob*)), this, SLOT(downloadFinished(KJob*))); job->exec(); </syntaxhighlight> The rest of the work happens in the <tt>downloadFinished()</tt> slot. First, the job is checked for errors. If it failed, we display a message box giving the error. We also make sure to clear the fileName, since the file wasn't opened successfully: <syntaxhighlight lang="cpp-qt"> KMessageBox::error(this, job->errorString()); fileName.clear(); </syntaxhighlight> Otherwise, we continue with opening the file. The data that <tt>storedGet()</tt> successfully downloaded, in this case the contents of our text file, is stored in the <tt>data</tt> member of a <tt>[http://api.kde.org/frameworks-api/frameworks5-apidocs/kio/html/classKIO_1_1StoredTransferJob.html KIO::StoredTransferJob]</tt> class. But in order to display the contents of the file at text, we must use a [http://doc.qt.io/qt-5/qtextstream.html QTextStream]. We create one by passing the the data of the <tt>StoredTransferJob</tt> to its constructor and then call its <tt>readAll()</tt> function to get the text from the file. This is then passed to the <tt>setPlainText()</tt> function of our text area. <syntaxhighlight lang="cpp-qt"> KIO::StoredTransferJob* storedJob = (KIO::StoredTransferJob*)job; textArea->setPlainText(QTextStream(storedJob->data(), QIODevice::ReadOnly).readAll()); </syntaxhighlight> {{{Note|Again, for simplicity's sake, this tutorial only saves text files to local disk. When you open a remote file for viewing and try to save it, the program will behave as if you were calling Save As on a completely new file.}} ==Make, Install, and Run== ===CMakeLists.txt=== <syntaxhighlight lang="cmake"> cmake_minimum_required(VERSION 3.0) project (tutorial4) set(QT_MIN_VERSION "5.3.0") set(KF5_MIN_VERSION "5.2.0") find_package(ECM 1.0.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(FeatureSummary) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core # QCommandLineParser, QStringLiteral, QSaveFile, QTextStream, QByteArray Widgets # QApplication, QAction, QFileDialog ) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS CoreAddons # KAboutData I18n # KLocalizedString XmlGui # KXmlGuiWindow, KActionCollection TextWidgets # KTextEdit ConfigWidgets # KStandardActions WidgetsAddons # KMessageBox KIO # KIO ) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) set(tutorial4_SRCS main.cpp mainwindow.cpp) add_executable(tutorial4 ${tutorial4_SRCS}) target_link_libraries(tutorial4 Qt5::Widgets KF5::CoreAddons KF5::I18n KF5::XmlGui KF5::TextWidgets KF5::ConfigWidgets KF5::WidgetsAddons KF5::KIOCore ) install(TARGETS tutorial4 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES tutorial4ui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/tutorial4) </syntaxhighlight> Since we are now using the KIO library, we must tell CMake to link against it. We do this by passing <tt>KIO</tt> to the <tt>find_package()</tt> function and <tt>KF5::KIOCore</tt> to <tt>target_link_libraries()</tt> function. With this file, the tutorial can be built and run in the same way as tutorial 3. For more information, see tutorial 3. <syntaxhighlight lang="bash"> mkdir build && cd build cmake .. -DCMAKE_INSTALL_PREFIX=$HOME make install XDG_DATA_DIRS=$HOME/share:$XDG_DATA_DIRS $HOME/bin/tutorial4 </syntaxhighlight> ==Moving On== Now you can move on to the [[Development/Tutorials/CommandLineArguments|command line arguments]] tutorial. [[Category:C++]]