Development/Tutorials/CommandLineArguments/pt-br: Difference between revisions

    From KDE TechBase
    (Created page with "Aqui não fizemos nada além de adicionar uma nova função <tt>openFile</tt> que utiliza uma <tt>QUrl</tt>. Novamente, usamos uma QUrl em vez de uma QString para que também...")
    (Updating to match new version of source page)
     
    (8 intermediate revisions by one other user not shown)
    Line 270: Line 270:
    ===mainwindow.cpp===
    ===mainwindow.cpp===


    There's no new code here, only rearranging. Everything from <tt>void openFile()</tt> has been moved into <tt>void openFile(const QUrl &inputFileName)</tt> except the call to <tt>QFileDialog::getOpenFileUrl()</tt>.
    Não há código novo aqui, apenas reorganizando. Tudo de <tt>void openFile()</tt> foi movido para <tt>void openFile(const QUrl & inputFileName)</tt>, exceto a chamada para <tt>QFileDialog::getOpenFileUrl()</tt>.


    This way, we can call <tt>openFile()</tt> if we want to display a dialog, or we can call <tt>openFile(QUrl)</tt> if we know the name of the file already. Which will be the case when we feed the file name through the command line.
    Dessa forma, podemos chamar <tt>openFile()</tt> se quisermos exibir uma caixa de diálogo, ou podemos chamar <tt>openFile(QUrl)</tt> se já sabemos o nome do arquivo. Que será o caso de quando alimentarmos o nome do arquivo através da linha de comando.


    ===main.cpp===
    ===main.cpp===


    This is where all the [http://doc.qt.io/qt-5/qcommandlineparser.html QCommandLineParser] magic happens. In previous examples, we only used the class to feed QApplication the necessary data for using flags like <tt>--version</tt> or <tt>--author</tt>. Now we actually get to use it to process command line arguments.
    É aqui que toda a magia [http://doc.qt.io/qt-5/qcommandlineparser.html QCommandLineParser] acontece. Nos exemplos anteriores, usamos apenas a classe para alimentar os dados necessários do QApplication para o uso de sinalizadores como <tt>--version</tt> ou <tt>--author</tt>. Agora, na verdade, podemos usá-lo para processar parâmetros de linha de comando.


    First, we tell QCommandLineParser that we want to add a new positional arguments. In a nutshell, these are arguments that are not options. <tt>-h</tt> or <tt>--version</tt> are options, <tt>file</tt> is an argument.
    Primeiro, dizemos ao QCommandLineParser que queremos adicionar novos argumentos posicionais. Em poucas palavras, esses são argumentos que não são opções. <tt>-h</tt> ou <tt>--version</tt> são opções, <tt>file</tt> é um argumento.
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    parser.addPositionalArgument(QStringLiteral("file"), i18n("Document to open"));
    parser.addPositionalArgument(QStringLiteral("file"), i18n("Document to open"));
    </syntaxhighlight>
    </syntaxhighlight>


    Later on, we start processing positional arguments, but only if there is one. Otherwise, we proceed as usual. In our case we can only open one file at a time, so only the first file is of interest to us. We call the <tt>openFile()</tt> function and feed it the URL of the file we want to open, whether it is a local file like {{path|$HOME/foo}} or a remote one like {{path|ftp.mydomain.com/bar}}. We use the overloaded form of <tt>[http://doc.qt.io/qt-5/qurl.html#fromUserInput-1 QUrl::fromUserInput()]</tt> in order to set the current path. This is needed in order to work with relative paths like <tt>"../baz"</tt>.
    Posteriormente, começamos a processar argumentos posicionais, mas apenas se houver um. Caso contrário, prosseguiremos como de costume. No nosso caso, podemos abrir apenas um arquivo de cada vez, portanto, apenas o primeiro arquivo é do nosso interesse. Chamamos a função <tt>openFile()</tt> e alimentamos a URL do arquivo que queremos abrir, seja um arquivo local como {{path | $HOME/foo}} ou remoto como {{path|ftp.mydomain.com/bar}}. Usamos o formato de sobrecarga de <tt>[http://doc.qt.io/qt-5/qurl.html#fromUserInput-1 QUrl::fromUserInput()]</tt> para definir o caminho atual. Isso é necessário para trabalhar com caminhos relativos como <tt>"../baz"</tt>.
    <syntaxhighlight lang="cpp-qt">
    <syntaxhighlight lang="cpp-qt">
    if (parser.positionalArguments().count() > 0)
    if (parser.positionalArguments().count() > 0)
    Line 290: Line 290:
    }
    }
    </syntaxhighlight>
    </syntaxhighlight>
    ==Make, Install and Run==
    ==Make, Install e Run==


    ===CMakeLists.txt===
    ===CMakeLists.txt===
    Line 302: Line 302:


    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 345: Line 345:
    install(FILES tutorial5ui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/tutorial5)
    install(FILES tutorial5ui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/tutorial5)
    </syntaxhighlight>
    </syntaxhighlight>
    With this file, the tutorial can built and run in the same way as tutorial 3 and 4. For more information, see tutorial 3.
    Com esse arquivo, o tutorial pode ser construído e executado da mesma maneira que o tutorial 3 e 4. Para obter mais informações, veja o tutorial 3.
    <syntaxhighlight lang="bash">
    <syntaxhighlight lang="bash">
    mkdir build && cd build
    mkdir build && cd build
    Line 352: Line 352:
    XDG_DATA_DIRS=$HOME/share:$XDG_DATA_DIRS $HOME/bin/tutorial5
    XDG_DATA_DIRS=$HOME/share:$XDG_DATA_DIRS $HOME/bin/tutorial5
    </syntaxhighlight>
    </syntaxhighlight>
    ==Moving On==
     
    ==Adiante==


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

    Latest revision as of 16:44, 24 August 2020

    Other languages:
    Parâmetros de Linha de Comando
    Tutorial Series   Tutorial para Iniciantes
    Previous   Tutorial 4 - Loading and saving
    What's Next   n/a
    Further Reading   n/a


    Resumo

    Agora que temos um editor de texto que pode abrir e salvar arquivos. Agora, faremos com que o editor aja mais como um aplicativo de desktop, permitindo que ele abra arquivos a partir de argumentos de linha de comando ou mesmo usando Abrir com no Dolphin.

    O Código

    main.cpp

    #include <cstdlib>
     
    #include <QApplication>
    #include <QCommandLineParser>
    #include <QUrl>
    #include <QDir>
    
    #include <KAboutData>
    #include <KLocalizedString>
    
    #include "mainwindow.h"
     
    int main (int argc, char *argv[])
    {
        QApplication app(argc, argv);
        
        KLocalizedString::setApplicationDomain("tutorial5");
        
        KAboutData aboutData(
                             // The program name used internally. (componentName)
                             QStringLiteral("tutorial5"),
                             // A displayable program name string. (displayName)
                             i18n("Tutorial 5"),
                             // 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.addPositionalArgument(QStringLiteral("file"), i18n("Document to open"));
        
        parser.process(app);
        aboutData.processCommandLine(&parser);
        
        MainWindow* window = new MainWindow();
        window->show();
        
        if (parser.positionalArguments().count() > 0)
        {
            window->openFile(QUrl::fromUserInput(parser.positionalArguments().at(0), QDir::currentPath()));
        }
        
        return app.exec();
    }
    

    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);
        void openFile(const QUrl &inputFileName);
     
      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
    

    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, "tutorial5ui.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()
    {
        openFile(QFileDialog::getOpenFileUrl(this, i18n("Open File")));
    }
        
    void MainWindow::openFile(const QUrl &inputFileName)
    {
        if (!inputFileName.isEmpty())
        {
            KIO::Job* job = KIO::storedGet(inputFileName);
            fileName = inputFileName.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());
    }
    

    tutorial5ui.rc

    <?xml version="1.0" encoding="UTF-8"?>
    <gui name="tutorial5"
         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>
    

    Explicação

    mainwindow.h

    Aqui não fizemos nada além de adicionar uma nova função openFile que utiliza uma QUrl. Novamente, usamos uma QUrl em vez de uma QString para que também possamos trabalhar com arquivos remotos como se fossem locais.

    void openFile(const QUrl &inputFileName);
    

    mainwindow.cpp

    Não há código novo aqui, apenas reorganizando. Tudo de void openFile() foi movido para void openFile(const QUrl & inputFileName), exceto a chamada para QFileDialog::getOpenFileUrl().

    Dessa forma, podemos chamar openFile() se quisermos exibir uma caixa de diálogo, ou podemos chamar openFile(QUrl) se já sabemos o nome do arquivo. Que será o caso de quando alimentarmos o nome do arquivo através da linha de comando.

    main.cpp

    É aqui que toda a magia QCommandLineParser acontece. Nos exemplos anteriores, usamos apenas a classe para alimentar os dados necessários do QApplication para o uso de sinalizadores como --version ou --author. Agora, na verdade, podemos usá-lo para processar parâmetros de linha de comando.

    Primeiro, dizemos ao QCommandLineParser que queremos adicionar novos argumentos posicionais. Em poucas palavras, esses são argumentos que não são opções. -h ou --version são opções, file é um argumento.

    parser.addPositionalArgument(QStringLiteral("file"), i18n("Document to open"));
    

    Posteriormente, começamos a processar argumentos posicionais, mas apenas se houver um. Caso contrário, prosseguiremos como de costume. No nosso caso, podemos abrir apenas um arquivo de cada vez, portanto, apenas o primeiro arquivo é do nosso interesse. Chamamos a função openFile() e alimentamos a URL do arquivo que queremos abrir, seja um arquivo local como $HOME/foo ou remoto como ftp.mydomain.com/bar. Usamos o formato de sobrecarga de QUrl::fromUserInput() para definir o caminho atual. Isso é necessário para trabalhar com caminhos relativos como "../baz".

    if (parser.positionalArguments().count() > 0)
    {
        window->openFile(QUrl::fromUserInput(parser.positionalArguments().at(0), QDir::currentPath()));
    }
    

    Make, Install e Run

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.0)
    
    project (tutorial5)
    
    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(tutorial5_SRCS main.cpp mainwindow.cpp)
    
    add_executable(tutorial5 ${tutorial5_SRCS})
    
    target_link_libraries(tutorial5
        Qt5::Widgets
        KF5::CoreAddons
        KF5::I18n
        KF5::XmlGui
        KF5::TextWidgets
        KF5::ConfigWidgets
        KF5::WidgetsAddons
        KF5::KIOCore
    )
    
    install(TARGETS tutorial5  ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
    
    install(FILES tutorial5ui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/tutorial5)
    

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

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

    Adiante