Table of Contents

Visitor

V našem příkladě návrhový vzor visitor “navštíví” všechny uzly stromu typu TreeItem a zavolá metodu visit.

Třída TreeItem představující zpracovávané uzly stromu

Třída TreeItem je rozšířením standardní třídy QTreeWidgetItem o proměnnou obsahující cestu k danému souboru nebo adresáři.

class TreeItem : public QTreeWidgetItem
{
public:
    QString path;
};

Třída Visitor

Třída Visitor obsahuje

class Visitor
{
protected:
    virtual void visit (QFileInfo & info) = 0;
private:
    void processBranch (QTreeWidgetItem * branch);
public:
    void process (QTreeWidget * tree);
};

Metoda process využije formální kořenový prvek stromu a zavolá processBranch

void Visitor::process (QTreeWidget * tree)
{
    processBranch (tree->invisibleRootItem ());
}

Metod processBranch se pokusí převédst obecný uzel stromu na náš typ TreeItem.
A pokud se to povede, vyzvedne cestu k souboru a vytvoří info typu QFileInfo.
Pokud info představuje soubor (a nikoliv adresář), zavolá metodu visit.

Nakonec rekurzivnš zavoláme processBranch pro vnořené větve stromu.

void Visitor::processBranch (QTreeWidgetItem * branch)
{
    TreeItem * item = dynamic_cast < TreeItem * > (branch);
    if (item != nullptr)
    {
        QFileInfo info (item->path);
        if (info.isFile())
           visit (info);
    }
 
    int cnt = branch->childCount();
    for (int i = 0; i < cnt; i++)
    {
        processBranch (branch->child (i));
    }
}

Použití třídy Visitor

Třída FileSizeVisitor odvozená ze třídy Visitor,
navštíví uzly stromu představující soubory,
vytiskne jejich jména,
spočítá soubory a jejich celkovou délku,

Třída obsahuje proměnné používané při zpracování stromu * proměnná cnt bude obsahovat počet souborů * v proměnné sum bude celkový počet bytů * output je ukazatel na okénko pro výstup textu

class FileSizeVisitor : public Visitor
{
private:
    int cnt;
    long long sum;
    QTextEdit * output;
    void print (QString s);
protected:
    void visit (QFileInfo & info);
public:
     FileSizeVisitor (QTreeWidget * tree, QTextEdit * edit);
};

Konstruktor :

FileSizeVisitor::FileSizeVisitor (QTreeWidget * tree, QTextEdit * edit)
{
    output = edit;
    cnt = 0;
    sum = 0;
    process (tree);
    print (QString::number (cnt) + " files, " + fmt (sum) + " bytes");
}

Metoda proces pro jednolivé souboty zavolá metodu visit.

void FileSizeVisitor::visit (QFileInfo &info)
{
    print ("file " + info.fileName());
    cnt ++;
    sum = sum + info.size();
}

Pomocná funkce print přidá jednu řádku do výstupního okénka

void FileSizeVisitor::print (QString s)
{
    output->append (s);
}

Hlavní okno

Zavoláme FileSizeVisitor, parametry bude strom a výstupní okénko.
( Ani nedeklarujeme proměnnou typu FileSizeVisitor, jen zavoláme konstruktor. )

    FileSizeVisitor (ui->treeWidget, ui->textEdit);

Ještě musíme naprogramovat metodu showDir, která naplní strom soubory a adresáři.

class MainWindow : public QMainWindow
{
    /* ... */
    void showDir (QTreeWidgetItem * target, QString path);
};

Metoda showDir

void MainWindow::showDir (QTreeWidgetItem * target, QString path)
{
    QDir dir (path);
 
    TreeItem * branch = new TreeItem;
    branch->path = dir.absolutePath ();
    branch->setText (0, dir.dirName());
    branch->setToolTip (0, branch->path);
    branch->setForeground(0, QColor ("red"));
    branch->setIcon(0, QIcon::fromTheme ("folder"));
    target->addChild (branch);
 
    QDir::Filters filter = QDir::AllEntries | QDir::NoDotAndDotDot;
    QDir::SortFlags sort = QDir::Name;
 
    for (QFileInfo info : dir.entryInfoList (filter, sort))
    {
       if (info.isDir())
       {
          showDir (branch, info.absoluteFilePath());
       }
       else
       {
          TreeItem * node = new TreeItem;
          node->path = info.absoluteFilePath();
          node->setText (0, info.fileName());
          node->setToolTip (0, node->path);
          node->setForeground (0, QColor ("blue"));
          node->setIcon (0, QIcon::fromTheme ("document"));
          branch->addChild (node);
       }
    }
}
MainWindow::MainWindow (QWidget *parent)
{
    /* ... */
    QDir dir = QDir ("..");
    showDir (ui->treeWidget->invisibleRootItem(), dir.canonicalPath());
    FileSizeVisitor (ui->treeWidget, ui->textEdit);
}

gitlab