Desenvolvimento/Tutoriais/Parâmetros de Linha de comando

< Development‎ | Tutorials
Revision as of 15:07, 20 November 2019 by Juliano Assis (talk | contribs) (Created page with "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 <...")
Jump to: navigation, search
Other languages:
English • ‎português do Brasil
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.

Tutorial5-kf5.png

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"));

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 openFile() function and feed it the URL of the file we want to open, whether it is a local file like $HOME/foo or a remote one like ftp.mydomain.com/bar. We use the overloaded form of QUrl::fromUserInput() in order to set the current path. This is needed in order to work with relative paths like "../baz".

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

Make, Install and 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} ${ECM_KDE_MODULE_DIR} ${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)

With this file, the tutorial can built and run in the same way as tutorial 3 and 4. For more information, see 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


Content is available under Creative Commons License SA 4.0 unless otherwise noted.