Skip to content
Snippets Groups Projects
RepoModel.h 8.66 KiB
Newer Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2013 ISIS Rutherford Appleton Laboratory UKRI,
//     NScD Oak Ridge National Laboratory, European Spallation Source
//     & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#ifndef MANTID_API_REPOMODEL_H_
#define MANTID_API_REPOMODEL_H_
#include "MantidAPI/ScriptRepository.h"
#include <QAbstractItemModel>
#include <QDialog>
#include <QFutureWatcher>
#include <QMessageBox>
#include <QModelIndex>
#include <QStringList>
#include <QVariant>
#include <QWidget>
class QLineEdit;
class QCheckBox;
namespace MantidQt {
namespace API {
const QString REMOTEONLY = "REMOTE_ONLY";
const QString LOCALONLY = "LOCAL_ONLY";
const QString LOCALCHANGED = "LOCAL_CHANGED";
const QString REMOTECHANGED = "REMOTE_CHANGED";
const QString BOTHUNCHANGED = "UPDATED";
const QString BOTHCHANGED = "CHANGED";
const QString UPLOADST = "UPLOADING";
const QString DOWNLOADST = "DOWNLOADING";
const QString PROTECTEDENTRY = "protected";
const QString DELETABLEENTRY = "deletable";

/** RepoModel : Wrapper for ScriptRepository to fit the Model View Qt Framework.

    The ScriptRepository has an hierarchical access to the folders and files, as
  so,
    it was necessary to extend the QAbstractItemModel in order to provide access
  to the
    entries on ScriptRepository.

    The RepoModel will be given to a QTreeView and as so, it will allow the user
  to interact
    with the ScriptRepository through the Qt ModelView Framework.

    The requirements for a class to fit this framework is to reimplement the
  following methods:
      - RepoModel::data - giving access to the data
      - RepoModel::flags - indication of the allowed interaction
      - RepoModel::headerData
      - RepoModel::index
      - RepoModel::parent
      - RepoModel::rowCount
      - RepoModel::columnCount
      - RepoModel::setData

   Through these methods, the RepoModel will be able to provide access to the
  ScriptRepository
   service. Allowing the users to upload and download files and folders.

   Some extra services are provided, to allow the classes to show the
  description of the files
   as well as open the files to be inspected by the users:
    - entrySelected
    - fileSelected

   This class should be constructed just once, and as so, the copy constructor
  and the assignment
   will be make private to ensure this.
*/
class RepoModel : public QAbstractItemModel {
  Q_OBJECT

  /** A nested class to help RepoModel to implement the QAbstractItemModel.
      This class in indended to keep track of the path inside the Repository
      of the entries, in such a way the repomodel will be able to get from the
      index the path.
      The RepoModel::appendChild allows the RepoModel to reconstruct the tree of
     the directories,
      while the RepoModel::child and RepoModel::parent methods allow to iterate
     over the tree.
  class RepoItem {
  public:
    // construct the RepoItem passing the script repository path
    RepoItem(const QString &label, const QString &path = "/",
             RepoItem *parent = nullptr);

    ~RepoItem();
    // append child to build the directory tree
    void appendChild(RepoItem *child);
    // access to the row_th file/folder child of this entry
    RepoItem *child(int row) const;
    /// To which row this repoItem belongs?
    int row() const;
    // return the number of files/folders that are children of this entry
    int childCount() const;
    /// access to the script repository path
    /// @return : script repository path
    const QString &path() const { return keypath; };
    /// access to the label provided at construction
    /// @return : label for this entry
    const QString &label() const { return m_label; };
    /// access to the parent of this entry
    /// @return : this entry parent's
    RepoItem *parent() const { return parentItem; };
    /// allow to remove a child, which allows erasing rows from the view.
    bool removeChild(int row);
    /// track the list of children for this entry
    QList<RepoItem *> childItems;
    /// the label of this entry
    /// the path of the script repository
    /// the parent of this entry
    RepoItem *parentItem;
  private:
    RepoItem(const RepoItem &);
    const RepoItem &operator=(const RepoItem &);
  };

  class UploadForm : public QDialog {
  public:
    UploadForm(const QString &file2upload, QWidget *parent = nullptr);
    ~UploadForm() override;
    QString email();
    QString author();
    QString comment();
    bool saveInfo();
    void setEmail(const QString & /*email*/);
    void setAuthor(const QString & /*author*/);
    void lastSaveOption(bool option);

  protected:
    QLineEdit *author_le;
    QLineEdit *email_le;
    QCheckBox *save_ck;
    QTextEdit *comment_te;
  };

  /** Auxiliary Dialog to get the option from the user about removing the
   * entries
   *  from the local folder or the central repository. When removing from
   * central
   *  repository, it will allow also to provide the justification.
   */
  class DeleteQueryBox : public QMessageBox {
  public:
    DeleteQueryBox(const QString &path, QWidget *parent = nullptr);
    ~DeleteQueryBox() override;
    QString comment();

  private:
    QTextEdit *comment_te;
  };
  RepoModel(QObject *parent = nullptr);
  /// destructor
  ~RepoModel() override;
  /// access to the ScriptRepository data
  QVariant data(const QModelIndex &index, int role) const override;
  /// information on the available interaction
  Qt::ItemFlags flags(const QModelIndex &index) const override;
  /// header strings
  QVariant headerData(int section, Qt::Orientation orientation,
                      int role = Qt::DisplayRole) const override;
  /// access to the index
  QModelIndex index(int row, int column,
                    const QModelIndex &parent = QModelIndex()) const override;
  /// access to parent
  QModelIndex parent(const QModelIndex &index) const override;
  //// provide the number of the rows
  int rowCount(const QModelIndex &parent = QModelIndex()) const override;
  /// provide the nubmer of the coluns
  int columnCount(const QModelIndex &parent = QModelIndex()) const override;
  /// change data
  bool setData(const QModelIndex &index, const QVariant &value,
               int role = Qt::EditRole) override;

  static const QString &localOnlySt();
  static const QString &remoteOnlySt();
  static const QString &localChangedSt();
  static const QString &remoteChangedSt();
  static const QString &updatedSt();
  static const QString &bothChangedSt();
  static const QString &downloadSt();
  static const QString &uploadSt();

  QString fileDescription(const QModelIndex &index);
  QString filePath(const QModelIndex &index);
  QString author(const QModelIndex &index);

signals:
  void executingThread(bool /*_t1*/);
  /// auxiliary method to populate the model
  void setupModelData(RepoItem *parent);
  /// auxiliary method to match the ScriptStatus to string
  const QString &fromStatus(Mantid::API::SCRIPTSTATUS status) const;
  /// pointer to the RepoItem root
  RepoItem *rootItem;
  /// pointer to the ScriptRepository
  Mantid::API::ScriptRepository_sptr repo_ptr;
  /// ScriptLocalRepository path, to be able to retrieve the absolute path
  QString repo_path;
  /// auxiliary method to help populating the model
  RepoItem *getParent(const QString &folder, QList<RepoItem *> &parents);
  Q_DISABLE_COPY(RepoModel)

  /// auxiliary method to deal with exceptions
  void handleExceptions(const Mantid::API::ScriptRepoException &ex,
                        const QString &title, bool showWarning = true) const;

  // handle download in thread
  QFuture<QString> download_threads;
  QFutureWatcher<QString> download_watcher;
  QModelIndex download_index;
  QString downloading_path;
  bool isDownloading(const QModelIndex &index) const;
private slots:
  void downloadFinished();

private:
  // handle connection to the uploader server in thread
  // this connection are used to upload or deleting files.

  // QFuture variable, used to check if the thread is running, alive, etc...
  QFuture<QString> upload_threads;
  // The mechanism to have a call back function executed after finishing the
  // thread
  QFutureWatcher<QString> upload_watcher;
  // keep track of the file being used to the connection with uploader
  QString uploading_path;
  QModelIndex upload_index;
  // check if the file pointed by the index is inside a connection with uploader
  bool isUploading(const QModelIndex &index) const;
private slots:
  // call back method executed after finishing the thread
  void uploadFinished();
};
} // namespace API
} // namespace MantidQt
#endif /* MANTID_API_SCRIPTREPOSITORYVIEW_H_ */