Development/Tutorials/Saving and loading/pt-br: Difference between revisions

    From KDE TechBase
    (Created page with "Também queremos acompanhar o nome do arquivo do arquivo aberto no momento, por isso declaramos um<tt>[http://doc.qt.io/qt-5/qstring.html QString] fileName</tt>.")
    (Updating to match new version of source page)
     
    (45 intermediate revisions by one other user not shown)
    Line 112: Line 112:
    Como queremos adicionar a capacidade de carregar e salvar arquivos, precisamos adicionar as funções que farão o trabalho. Como as funções serão chamadas pelo mecanismo do Qt [http://doc.qt.io/qt-5/signalsandslots.html signal/slot], devemos especificar que essas funções são slots. Como estamos usando slots neste arquivo de cabeçalho, também devemos adicionar a macro  [http://doc.qt.io/qt-5/qobject.html#Q_OBJECT <tt>Q_OBJECT</tt>].
    Como queremos adicionar a capacidade de carregar e salvar arquivos, precisamos adicionar as funções que farão o trabalho. Como as funções serão chamadas pelo mecanismo do Qt [http://doc.qt.io/qt-5/signalsandslots.html signal/slot], devemos especificar que essas funções são slots. Como estamos usando slots neste arquivo de cabeçalho, também devemos adicionar a macro  [http://doc.qt.io/qt-5/qobject.html#Q_OBJECT <tt>Q_OBJECT</tt>].


    Também queremos acompanhar o nome do arquivo do arquivo aberto no momento, por isso declaramos um<tt>[http://doc.qt.io/qt-5/qstring.html QString] fileName</tt>.
    Também queremos acompanhar o nome de arquivo do arquivo aberto no momento, por isso declaramos um<tt>[http://doc.qt.io/qt-5/qstring.html QString] fileName</tt>.


    ===mainwindow.cpp===
    ===mainwindow.cpp===
    Line 230: Line 230:
    }
    }
    </syntaxhighlight>
    </syntaxhighlight>
    We'll get into the details of <tt>mainwindow.cpp</tt> in a while.
    Entraremos em detalhes do <tt>mainwindow.cpp</tt> daqui a pouco.


    ===tutorial4ui.rc===
    ===tutorial4ui.rc===
    Line 255: Line 255:
    </gui>
    </gui>
    </syntaxhighlight>
    </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.
    Isso é idêntico ao <tt>tutorial3ui.rc</tt> do tutorial 3, exceto que o <tt>name</tt> foi alterado para 'tutorial4'. Não precisamos adicionar nenhuma informação sobre nenhum dos <tt>KStandardAction</tt>s, pois o posicionamento dessas actions é tratado automaticamente pelo KDE.


    ==Explanation==
    ==Explicação==


    Okay, now to implement the code that will do the loading and saving. This will all be happening in <tt>mainwindow.cpp</tt>
    Ok, agora para implementar o código que fará o carregamento e o salvamento. Tudo isso estará acontecendo em <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.
    A primeira coisa que fazemos é adicionar <tt>fileName(QString())</tt> à lista de construtores <tt>MainWindow</tt> para garantir que <tt>fileName</tt> esteja vazio desde o início.


    ===Adding the actions===
    ===Adicionando os 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.
    A primeira coisa que faremos é fornecer a interface externa para o usuário, para que ele possa dizer ao aplicativo para carregar e salvar. Assim como na action <tt>quit</tt> no tutorial 3, usaremos <tt>KStandardActions</tt>. Nós adicionamos as actions da mesma maneira que para a action <tt>quit</tt> e, para cada uma, nós a conectamos ao slot apropriado que declaramos no arquivo de cabeçalho.


    ===Creating a new document===
    ===Criando um novo documento===


    The first function we create is the <tt>newFile()</tt> function.
    A primeira função que criamos é a função <tt>newFile()</tt>.
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    void MainWindow::newFile()
    void MainWindow::newFile()
    Line 277: Line 277:
    }
    }
    </syntaxhighlight>
    </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.
    <tt>fileName.clear()</tt> define a QString <tt>fileName</tt> como vazio para refletir o fato de que este documento ainda não tem presença no armazenamento. <tt>textArea->clear()</tt> limpa a área de texto central usando a mesma função à qual conectamos o <tt>clear</tt> <tt>KQction</tt> no 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.}}
    {{Warning (pt BR)|Este exemplo simples apenas limpa a área de texto sem verificar se o arquivo foi salvo primeiro. É apenas uma demonstração de E/S de arquivo e não um exemplo de boas práticas de programação.}}


    ===Saving a file===
    ===Salvando um arquivo===


    {{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.}}
    {{Note (pt BR)|Para simplificar este tutorial, este exemplo de programa pode salvar apenas no armazenamento local, mesmo que possa abrir qualquer arquivo de qualquer local, mesmo de fontes remotas.}}


    ====saveFileAs(QString)====
    ====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].
    Agora chegamos a nossa primeira manipulação de código de arquivos. Vamos implementar uma função que salvará o conteúdo da área de texto no arquivo de nome fornecido como parâmetro. O Qt fornece uma classe para salvar com segurança um arquivo chamada [http://doc.qt.io/qt-5/qsavefile.html QSaveFile].


    The function's prototype is
    O protótipo da função é
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    void MainWindow::saveFileAs(const QString &outputFileName)
    void MainWindow::saveFileAs(const QString &outputFileName)
    </syntaxhighlight>
    </syntaxhighlight>
    We then create our <tt>QSaveFile</tt> object and open it with
    Em seguida, criamos nosso objeto <tt>QSaveFile</tt> e o abrimos com
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    QSaveFile file(outputFileName);
    QSaveFile file(outputFileName);
    file.open(QIODevice::WriteOnly);
    file.open(QIODevice::WriteOnly);
    </syntaxhighlight>
    </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:
    Agora que temos nosso arquivo para gravar, precisamos formatar o texto na área de texto para um formato que possa ser gravado em arquivo. Para isso, criamos um [http://doc.qt.io/qt-5/qbytearray.html QByteArray] e o preenchemos com a versão em texto sem formatação do que estiver na área de texto:
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    QByteArray outputByteArray;
    QByteArray outputByteArray;
    outputByteArray.append(textArea->toPlainText().toUtf8());
    outputByteArray.append(textArea->toPlainText().toUtf8());
    </syntaxhighlight>
    </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.
    Agora que temos nosso <tt>QByteArray</tt>, usamos o para gravar no arquivo com <tt>QSaveFile::write()</tt>. Se estivéssemos usando um <tt>QFile</tt> normal, isso faria as alterações imediatamente. No entanto, se um problema ocorresse parcialmente durante a gravação, o arquivo seria corrompido. Por esse motivo, <tt>QSaveFile</tt> funciona primeiro escrevendo em um arquivo temporário e, em seguida, quando você chama <tt>QSaveFile::commit()</tt> as alterações são feitas no arquivo real. <tt>commit() </tt> também fecha o arquivo.
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    file.write(outputByteArray);
    file.write(outputByteArray);
    file.commit();
    file.commit();
    </syntaxhighlight>
    </syntaxhighlight>
    Finally, we set <tt>MainWindows</tt>'s <tt>fileName</tt> member to point to the file name we just saved to.
    Por fim, definimos <tt>fileName</tt> do membro <tt>MainWindows</tt> para apontar para o nome do arquivo no qual acabamos de salvar.
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    fileName = outputFileName;
    fileName = outputFileName;
    Line 315: Line 315:
    ====saveFileAs()====
    ====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>.
    Esta é a função à qual o slot <tt>saveAs</tt> está conectado. Ele simplesmente chama a função genérica <tt>saveFileAs(QString)</tt> e passa o nome do arquivo retornado por <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">
    <syntaxhighlight lang="cpp-qt">
    void MainWindow::saveFileAs()
    void MainWindow::saveFileAs()
    Line 323: Line 323:
    </syntaxhighlight>
    </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>.
    [http://doc.qt.io/qt-5/qfiledialog.html QFileDialog] fornece várias funções estáticas para exibir a caixa de diálogo de arquivo comum usada por todos os aplicativos do KDE. Chamar <tt>QFileDialog::getSaveFileName()</tt> exibirá uma caixa de diálogo onde o usuário pode selecionar o nome do arquivo para salvar ou escolher um novo nome. A função retorna o nome completo do arquivo, que passamos para <tt>saveFileAs(QString)</tt>.


    ====saveFile()====
    ====saveFile()====
    Line 341: Line 341:
    </syntaxhighlight>
    </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.
    Não há nada interessante ou novo nessa função, apenas a lógica para decidir se deve ou não mostrar a caixa de diálogo Salvar. Se <tt>fileName</tt> não estiver vazio, o arquivo será salvo em <tt>fileName</tt>. Mas, se estiver, a caixa de diálogo é mostrada para permitir que o usuário selecione um nome de arquivo.


    ===Loading a file===
    ===Carregando um arquivo===


    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>.
    Por fim, somos capazes de carregar um arquivo, do armazenamento local ou de um local remoto como um servidor FTP. O código para isso está todo contido em <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>:
    Primeiro, devemos solicitar ao usuário o nome do arquivo que ele deseja abrir. Fazemos isso usando outra das funções <tt>QFileDialog</tt>, desta vez <tt>getOpenFileName()</tt>:
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    QUrl fileNameFromDialog = QFileDialog::getOpenFileUrl(this, i18n("Open File"));
    QUrl fileNameFromDialog = QFileDialog::getOpenFileUrl(this, i18n("Open File"));
    </syntaxhighlight>
    </syntaxhighlight>
    Here we use the QUrl class to handle files from remote locations.
    Aqui usamos a classe QUrl para manipular arquivos de locais remotos.


    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:
    Em seguida, usamos a biblioteca KIO para recuperar nosso arquivo. Isso nos permite abrir o arquivo normalmente, mesmo se ele estiver armazenado em um local remoto, como um site FTP. Fazemos a seguinte chamada para a função <tt>[http://api.kde.org/frameworks-api/frameworks5-apidocs/kio/html/namespaceKIO.html#a17631774b47cddb0127d8a3c1fc2315c KIO::storedGet()]</tt> com um argumento para o arquivo que você deseja abrir ou baixar:
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    KIO::Job* job = KIO::storedGet(fileNameFromDialog);
    KIO::Job* job = KIO::storedGet(fileNameFromDialog);
    </syntaxhighlight>
    </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.
    A função retorna um manipulador para um <tt>KIO::Job</tt>, que primeiro conectamos ao nosso slot <tt>downloadFinished()</tt> antes de "executar" o trabalho.
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    connect(job, SIGNAL(result(KJob*)), this, SLOT(downloadFinished(KJob*)));
    connect(job, SIGNAL(result(KJob*)), this, SLOT(downloadFinished(KJob*)));
    Line 365: Line 365:
    </syntaxhighlight>
    </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:
    O restante do trabalho acontece no slot <tt>downloadFinished()</tt>. Primeiro, o job é verificado quanto a erros. Se ele falhar, exibimos uma caixa de mensagem indicando o erro. Também limpamos o fileName, pois o arquivo não foi aberto com sucesso:
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    KMessageBox::error(this, job->errorString());
    KMessageBox::error(this, job->errorString());
    fileName.clear();
    fileName.clear();
    </syntaxhighlight>
    </syntaxhighlight>
    Otherwise, we continue with opening the file.
    Caso contrário, continuamos com a abertura do arquivo.


    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.
    Os dados que o <tt>storedGet()</tt> baixou com sucesso, neste caso o conteúdo do nosso arquivo de texto, são armazenados no membro <tt>data</tt> de um <tt>[http://api.kde.org/frameworks-api/frameworks5-apidocs/kio/html/classKIO_1_1StoredTransferJob.html KIO::StoredTransferJob]</tt>. Mas, para exibir o conteúdo do arquivo em texto, devemos usar um  [http://doc.qt.io/qt-5/qtextstream.html QTextStream]. Criamos um passando os dados do <tt>StoredTransferJob</tt> para seu construtor e, em seguida, chamamos sua função <tt>readAll()</tt> para obter o texto do arquivo. Isso é passado para a função <tt>setPlainText()</tt> da nossa área de texto.
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    KIO::StoredTransferJob* storedJob = (KIO::StoredTransferJob*)job;
    KIO::StoredTransferJob* storedJob = (KIO::StoredTransferJob*)job;
    textArea->setPlainText(QTextStream(storedJob->data(), QIODevice::ReadOnly).readAll());
    textArea->setPlainText(QTextStream(storedJob->data(), QIODevice::ReadOnly).readAll());
    </syntaxhighlight>
    </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.}}
    {{{Note(pt BR)|Novamente, por uma questão de simplicidade, este tutorial salva apenas arquivos de texto no disco local. Quando você abre um arquivo remoto para visualização e tenta salvá-lo, o programa se comporta como se você estivesse chamando o Salvar Como em um arquivo completamente novo.}}


    ==Make, Install, and Run==
    ==Make, Install, e Run==


    ===CMakeLists.txt===
    ===CMakeLists.txt===
    Line 391: Line 391:


    find_package(ECM 1.0.0 REQUIRED NO_MODULE)
    find_package(ECM 1.0.0 REQUIRED NO_MODULE)
    set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
    set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)


    include(KDEInstallDirs)
    include(KDEInstallDirs)
    Line 435: Line 435:
    install(FILES tutorial4ui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/tutorial4)
    install(FILES tutorial4ui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/tutorial4)
    </syntaxhighlight>
    </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.
    Como agora estamos usando a biblioteca KIO, precisamos dizer ao CMake para linkar-se a ela. Fazemos isso passando <tt>KIO</tt> para a função <tt>find_package()</tt> e <tt>KF5::KIOCore</tt> para <tt>target_link_libraries()</tt> .


    With this file, the tutorial can be built and run in the same way as tutorial 3. For more information, see tutorial 3.
    Com esse arquivo, o tutorial pode ser construído e executado da mesma maneira que o tutorial 3. Para obter mais informações, consulte o tutorial 3.
    <syntaxhighlight lang="bash">
    <syntaxhighlight lang="bash">
    mkdir build && cd build
    mkdir build && cd build
    Line 444: Line 444:
    XDG_DATA_DIRS=$HOME/share:$XDG_DATA_DIRS $HOME/bin/tutorial4
    XDG_DATA_DIRS=$HOME/share:$XDG_DATA_DIRS $HOME/bin/tutorial4
    </syntaxhighlight>
    </syntaxhighlight>
    ==Moving On==


    Now you can move on to the [[Development/Tutorials/CommandLineArguments|command line arguments]] tutorial.
    ==Adiante==
     
    Agora você pode seguir para tutorial [[Development/Tutorials/CommandLineArguments|command line arguments]].


    [[Category:C++]]
    [[Category:C++]]

    Latest revision as of 16:44, 24 August 2020

    Other languages:
    Carregando e salvando arquivos
    Tutorial Series   Tutorial para Iniciantes
    Previous   Tutorial 3 - Actions
    What's Next   Tutorial 5 - Using Command Line Arguments
    Further Reading   Tutorial: Using KIO Slaves in your Program KIO::NetAccess QFile

    Resumo

    Agora que temos uma interface básica de editor de texto, é hora de fazer algo útil. No mais básico, um editor de texto precisa ser capaz de carregar arquivos do armazenamento de dados, salvar arquivos que você criou/editou e criar novos arquivos.

    O KDE Frameworks fornece várias classes para trabalhar com arquivos que facilitam muito a vida dos desenvolvedores. A KIO framework permite que você acesse arquivos facilmente através de protocolos transparentes de rede. Ao mesmo tempo, o Qt também fornece caixas de diálogo de arquivo padrão para abrir e salvar arquivos.

    O Código

    main.cpp

    #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("[email protected]")
                             QStringLiteral("[email protected]"));
        aboutData.addAuthor(i18n("Name"), i18n("Task"), QStringLiteral("[email protected]"),
                            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();
    }
    

    main.cpp não mudou do tutorial 3, exceto para alterar qualquer referência do tutorial 3 para o tutorial 4.

    mainwindow.h

    #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
    

    Como queremos adicionar a capacidade de carregar e salvar arquivos, precisamos adicionar as funções que farão o trabalho. Como as funções serão chamadas pelo mecanismo do Qt signal/slot, devemos especificar que essas funções são slots. Como estamos usando slots neste arquivo de cabeçalho, também devemos adicionar a macro Q_OBJECT.

    Também queremos acompanhar o nome de arquivo do arquivo aberto no momento, por isso declaramos umQString fileName.

    mainwindow.cpp

    #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());
    }
    

    Entraremos em detalhes do mainwindow.cpp daqui a pouco.

    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="clear" />
        </Menu>
      </MenuBar>
     
      <ToolBar name="mainToolBar" >
        <text>Main Toolbar</text>
        <Action name="clear" />
      </ToolBar>
     
    </gui>
    

    Isso é idêntico ao tutorial3ui.rc do tutorial 3, exceto que o name foi alterado para 'tutorial4'. Não precisamos adicionar nenhuma informação sobre nenhum dos KStandardActions, pois o posicionamento dessas actions é tratado automaticamente pelo KDE.

    Explicação

    Ok, agora para implementar o código que fará o carregamento e o salvamento. Tudo isso estará acontecendo em mainwindow.cpp

    A primeira coisa que fazemos é adicionar fileName(QString()) à lista de construtores MainWindow para garantir que fileName esteja vazio desde o início.

    Adicionando os actions

    A primeira coisa que faremos é fornecer a interface externa para o usuário, para que ele possa dizer ao aplicativo para carregar e salvar. Assim como na action quit no tutorial 3, usaremos KStandardActions. Nós adicionamos as actions da mesma maneira que para a action quit e, para cada uma, nós a conectamos ao slot apropriado que declaramos no arquivo de cabeçalho.

    Criando um novo documento

    A primeira função que criamos é a função newFile().

    void MainWindow::newFile()
    {
      fileName.clear();
      textArea->clear();
    }
    

    fileName.clear() define a QString fileName como vazio para refletir o fato de que este documento ainda não tem presença no armazenamento. textArea->clear() limpa a área de texto central usando a mesma função à qual conectamos o clear KQction no tutorial 3.

    Aviso
    Este exemplo simples apenas limpa a área de texto sem verificar se o arquivo foi salvo primeiro. É apenas uma demonstração de E/S de arquivo e não um exemplo de boas práticas de programação.


    Salvando um arquivo

    Nota
    Para simplificar este tutorial, este exemplo de programa pode salvar apenas no armazenamento local, mesmo que possa abrir qualquer arquivo de qualquer local, mesmo de fontes remotas.


    saveFileAs(QString)

    Agora chegamos a nossa primeira manipulação de código de arquivos. Vamos implementar uma função que salvará o conteúdo da área de texto no arquivo de nome fornecido como parâmetro. O Qt fornece uma classe para salvar com segurança um arquivo chamada QSaveFile.

    O protótipo da função é

    void MainWindow::saveFileAs(const QString &outputFileName)
    

    Em seguida, criamos nosso objeto QSaveFile e o abrimos com

    QSaveFile file(outputFileName);
    file.open(QIODevice::WriteOnly);
    

    Agora que temos nosso arquivo para gravar, precisamos formatar o texto na área de texto para um formato que possa ser gravado em arquivo. Para isso, criamos um QByteArray e o preenchemos com a versão em texto sem formatação do que estiver na área de texto:

    QByteArray outputByteArray;
    outputByteArray.append(textArea->toPlainText().toUtf8());
    

    Agora que temos nosso QByteArray, usamos o para gravar no arquivo com QSaveFile::write(). Se estivéssemos usando um QFile normal, isso faria as alterações imediatamente. No entanto, se um problema ocorresse parcialmente durante a gravação, o arquivo seria corrompido. Por esse motivo, QSaveFile funciona primeiro escrevendo em um arquivo temporário e, em seguida, quando você chama QSaveFile::commit() as alterações são feitas no arquivo real. commit() também fecha o arquivo.

    file.write(outputByteArray);
    file.commit();
    

    Por fim, definimos fileName do membro MainWindows para apontar para o nome do arquivo no qual acabamos de salvar.

    fileName = outputFileName;
    

    saveFileAs()

    Esta é a função à qual o slot saveAs está conectado. Ele simplesmente chama a função genérica saveFileAs(QString) e passa o nome do arquivo retornado por QFileDialog::getSaveFileName().

    void MainWindow::saveFileAs()
    {
      saveFileAs(QFileDialog::getSaveFileName(this, i18n("Save File As")));
    }
    

    QFileDialog fornece várias funções estáticas para exibir a caixa de diálogo de arquivo comum usada por todos os aplicativos do KDE. Chamar QFileDialog::getSaveFileName() exibirá uma caixa de diálogo onde o usuário pode selecionar o nome do arquivo para salvar ou escolher um novo nome. A função retorna o nome completo do arquivo, que passamos para saveFileAs(QString).

    saveFile()

    void MainWindow::saveFile()
    {
      if(!fileName.isEmpty())
      {
        saveFileAs(fileName);
      }
      else
      {
        saveFileAs();
      }
    }
    

    Não há nada interessante ou novo nessa função, apenas a lógica para decidir se deve ou não mostrar a caixa de diálogo Salvar. Se fileName não estiver vazio, o arquivo será salvo em fileName. Mas, se estiver, a caixa de diálogo é mostrada para permitir que o usuário selecione um nome de arquivo.

    Carregando um arquivo

    Por fim, somos capazes de carregar um arquivo, do armazenamento local ou de um local remoto como um servidor FTP. O código para isso está todo contido em MainWindow::openFile().

    Primeiro, devemos solicitar ao usuário o nome do arquivo que ele deseja abrir. Fazemos isso usando outra das funções QFileDialog, desta vez getOpenFileName():

    QUrl fileNameFromDialog = QFileDialog::getOpenFileUrl(this, i18n("Open File"));
    

    Aqui usamos a classe QUrl para manipular arquivos de locais remotos.

    Em seguida, usamos a biblioteca KIO para recuperar nosso arquivo. Isso nos permite abrir o arquivo normalmente, mesmo se ele estiver armazenado em um local remoto, como um site FTP. Fazemos a seguinte chamada para a função KIO::storedGet() com um argumento para o arquivo que você deseja abrir ou baixar:

    KIO::Job* job = KIO::storedGet(fileNameFromDialog);
    

    A função retorna um manipulador para um KIO::Job, que primeiro conectamos ao nosso slot downloadFinished() antes de "executar" o trabalho.

    connect(job, SIGNAL(result(KJob*)), this, SLOT(downloadFinished(KJob*)));
    
    job->exec();
    

    O restante do trabalho acontece no slot downloadFinished(). Primeiro, o job é verificado quanto a erros. Se ele falhar, exibimos uma caixa de mensagem indicando o erro. Também limpamos o fileName, pois o arquivo não foi aberto com sucesso:

    KMessageBox::error(this, job->errorString());
    fileName.clear();
    

    Caso contrário, continuamos com a abertura do arquivo.

    Os dados que o storedGet() baixou com sucesso, neste caso o conteúdo do nosso arquivo de texto, são armazenados no membro data de um KIO::StoredTransferJob. Mas, para exibir o conteúdo do arquivo em texto, devemos usar um QTextStream. Criamos um passando os dados do StoredTransferJob para seu construtor e, em seguida, chamamos sua função readAll() para obter o texto do arquivo. Isso é passado para a função setPlainText() da nossa área de texto.

    KIO::StoredTransferJob* storedJob = (KIO::StoredTransferJob*)job;
    textArea->setPlainText(QTextStream(storedJob->data(), QIODevice::ReadOnly).readAll());
    

    {Template:Note(pt BR)

    Make, Install, e Run

    CMakeLists.txt

    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)
    

    Como agora estamos usando a biblioteca KIO, precisamos dizer ao CMake para linkar-se a ela. Fazemos isso passando KIO para a função find_package() e KF5::KIOCore para target_link_libraries() .

    Com esse arquivo, o tutorial pode ser construído e executado da mesma maneira que o tutorial 3. Para obter mais informações, consulte o tutorial 3.

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

    Adiante

    Agora você pode seguir para tutorial command line arguments.