Added Workspace Tree view
Added Rename Folder action Minor GUI cleanups FossilOrigin-Name: 5fc925ac68148c69db66e88e23be196807ffec22
This commit is contained in:
parent
c153c9ce0a
commit
5acd01a0fd
544
MainWindow.cpp
544
MainWindow.cpp
@ -24,14 +24,21 @@
|
|||||||
QString EOL_MARK("\n");
|
QString EOL_MARK("\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define PATH_SEP "/"
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
COLUMN_STATUS,
|
COLUMN_STATUS,
|
||||||
COLUMN_PATH,
|
|
||||||
COLUMN_FILENAME,
|
COLUMN_FILENAME,
|
||||||
COLUMN_EXTENSION,
|
COLUMN_EXTENSION,
|
||||||
COLUMN_MODIFIED
|
COLUMN_MODIFIED,
|
||||||
|
COLUMN_PATH
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
REPODIRMODEL_ROLE_PATH = Qt::UserRole+1
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -128,17 +135,40 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
ui(new Ui::MainWindow)
|
ui(new Ui::MainWindow)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->tableView->setModel(&itemModel);
|
|
||||||
itemModel.setHorizontalHeaderLabels(QStringList() << tr("S") << tr("Path") << tr("File") << tr("Ext") << tr("Modified") );
|
QAction *separator = new QAction(this);
|
||||||
|
separator->setSeparator(true);
|
||||||
|
|
||||||
|
// TableView
|
||||||
|
ui->tableView->setModel(&repoFileModel);
|
||||||
|
|
||||||
ui->tableView->addAction(ui->actionDiff);
|
ui->tableView->addAction(ui->actionDiff);
|
||||||
ui->tableView->addAction(ui->actionHistory);
|
ui->tableView->addAction(ui->actionHistory);
|
||||||
ui->tableView->addAction(ui->actionOpenFile);
|
ui->tableView->addAction(ui->actionOpenFile);
|
||||||
ui->tableView->addAction(ui->actionOpenContaining);
|
ui->tableView->addAction(ui->actionOpenContaining);
|
||||||
|
ui->tableView->addAction(separator);
|
||||||
ui->tableView->addAction(ui->actionAdd);
|
ui->tableView->addAction(ui->actionAdd);
|
||||||
ui->tableView->addAction(ui->actionDelete);
|
ui->tableView->addAction(ui->actionRevert);
|
||||||
ui->tableView->addAction(ui->actionRename);
|
ui->tableView->addAction(ui->actionRename);
|
||||||
|
ui->tableView->addAction(ui->actionDelete);
|
||||||
|
|
||||||
|
// TreeView
|
||||||
|
ui->treeView->setModel(&repoDirModel);
|
||||||
|
connect( ui->treeView->selectionModel(),
|
||||||
|
SIGNAL( selectionChanged(const QItemSelection &, const QItemSelection &) ),
|
||||||
|
SLOT( on_treeView_selectionChanged(const QItemSelection &, const QItemSelection &) ),
|
||||||
|
Qt::DirectConnection );
|
||||||
|
|
||||||
|
ui->treeView->addAction(ui->actionCommit);
|
||||||
|
ui->treeView->addAction(ui->actionOpenFolder);
|
||||||
|
ui->treeView->addAction(ui->actionAdd);
|
||||||
|
ui->treeView->addAction(ui->actionRevert);
|
||||||
|
ui->treeView->addAction(ui->actionDelete);
|
||||||
|
ui->treeView->addAction(separator);
|
||||||
|
ui->treeView->addAction(ui->actionRenameFolder);
|
||||||
|
ui->treeView->addAction(ui->actionOpenFolder);
|
||||||
|
|
||||||
|
// Recent Workspaces
|
||||||
// Locate a sequence of two separator actions in file menu
|
// Locate a sequence of two separator actions in file menu
|
||||||
QList<QAction*> file_actions = ui->menuFile->actions();
|
QList<QAction*> file_actions = ui->menuFile->actions();
|
||||||
QAction *recent_sep=0;
|
QAction *recent_sep=0;
|
||||||
@ -156,7 +186,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
{
|
{
|
||||||
recentWorkspaceActs[i] = new QAction(this);
|
recentWorkspaceActs[i] = new QAction(this);
|
||||||
recentWorkspaceActs[i]->setVisible(false);
|
recentWorkspaceActs[i]->setVisible(false);
|
||||||
connect(recentWorkspaceActs[i], SIGNAL(triggered()), this, SLOT(onOpenRecent()));
|
connect(recentWorkspaceActs[i], SIGNAL(triggered()), this, SLOT(on_openRecent()));
|
||||||
ui->menuFile->insertAction(recent_sep, recentWorkspaceActs[i]);
|
ui->menuFile->insertAction(recent_sep, recentWorkspaceActs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +202,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
a->setIconVisibleInMenu(false);
|
a->setIconVisibleInMenu(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
viewMode = VIEWMODE_TREE;
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
refresh();
|
refresh();
|
||||||
rebuildRecent();
|
rebuildRecent();
|
||||||
@ -183,6 +215,11 @@ MainWindow::~MainWindow()
|
|||||||
{
|
{
|
||||||
stopUI();
|
stopUI();
|
||||||
saveSettings();
|
saveSettings();
|
||||||
|
|
||||||
|
// Dispose RepoFiles
|
||||||
|
for(filemap_t::iterator it = workspaceFiles.begin(); it!=workspaceFiles.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -254,11 +291,12 @@ bool MainWindow::openWorkspace(const QString &dir)
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void MainWindow::on_actionOpen_triggered()
|
void MainWindow::on_actionOpen_triggered()
|
||||||
{
|
{
|
||||||
QString path = QFileDialog::getExistingDirectory(this, tr("Fossil Checkout"), QDir::currentPath());
|
QString path = QFileDialog::getExistingDirectory(this, tr("Fossil Workspace"), QDir::currentPath());
|
||||||
if(!path.isNull())
|
if(!path.isNull())
|
||||||
openWorkspace(path);
|
openWorkspace(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void MainWindow::rebuildRecent()
|
void MainWindow::rebuildRecent()
|
||||||
{
|
{
|
||||||
@ -279,7 +317,7 @@ void MainWindow::rebuildRecent()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void MainWindow::onOpenRecent()
|
void MainWindow::on_openRecent()
|
||||||
{
|
{
|
||||||
QAction *action = qobject_cast<QAction *>(sender());
|
QAction *action = qobject_cast<QAction *>(sender());
|
||||||
if(!action)
|
if(!action)
|
||||||
@ -305,7 +343,7 @@ bool MainWindow::scanDirectory(QFileInfoList &entries, const QString& dirPath, c
|
|||||||
QString filename = info.fileName();
|
QString filename = info.fileName();
|
||||||
QString filepath = info.filePath();
|
QString filepath = info.filePath();
|
||||||
QString rel_path = filepath;
|
QString rel_path = filepath;
|
||||||
rel_path.remove(baseDir+"/");
|
rel_path.remove(baseDir+PATH_SEP);
|
||||||
|
|
||||||
// Skip ignored files
|
// Skip ignored files
|
||||||
if(!ignoreSpec.isEmpty() && QDir::match(ignoreSpec, rel_path))
|
if(!ignoreSpec.isEmpty() && QDir::match(ignoreSpec, rel_path))
|
||||||
@ -351,14 +389,14 @@ bool MainWindow::refresh()
|
|||||||
{
|
{
|
||||||
setStatus(tr("No checkout detected."));
|
setStatus(tr("No checkout detected."));
|
||||||
enableActions(false);
|
enableActions(false);
|
||||||
itemModel.removeRows(0, itemModel.rowCount());
|
repoFileModel.removeRows(0, repoFileModel.rowCount());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if(st==REPO_OLD_SCHEMA)
|
else if(st==REPO_OLD_SCHEMA)
|
||||||
{
|
{
|
||||||
setStatus(tr("Old fossil schema detected. Consider running rebuild."));
|
setStatus(tr("Old fossil schema detected. Consider running rebuild."));
|
||||||
enableActions(false);
|
enableActions(false);
|
||||||
itemModel.removeRows(0, itemModel.rowCount());
|
repoFileModel.removeRows(0, repoFileModel.rowCount());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +431,13 @@ void MainWindow::scanWorkspace()
|
|||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||||
|
|
||||||
|
// Dispose RepoFiles
|
||||||
|
for(filemap_t::iterator it = workspaceFiles.begin(); it!=workspaceFiles.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
workspaceFiles.clear();
|
workspaceFiles.clear();
|
||||||
|
pathSet.clear();
|
||||||
|
|
||||||
if(scan_files)
|
if(scan_files)
|
||||||
{
|
{
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
@ -416,17 +460,20 @@ void MainWindow::scanWorkspace()
|
|||||||
if(filename == "_FOSSIL_" || (!repositoryFile.isEmpty() && it->absoluteFilePath()==repositoryFile))
|
if(filename == "_FOSSIL_" || (!repositoryFile.isEmpty() && it->absoluteFilePath()==repositoryFile))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
RepoFile e;
|
RepoFile *rf = new RepoFile(*it, RepoFile::TYPE_UNKNOWN, wkdir);
|
||||||
e.set(*it, RepoFile::TYPE_UNKNOWN, wkdir);
|
workspaceFiles.insert(rf->getFilePath(), rf);
|
||||||
workspaceFiles.insert(e.getFilename(), e);
|
pathSet.insert(rf->getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setStatus(tr("Updating..."));
|
setStatus(tr("Updating..."));
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
for(QStringList::iterator it=res.begin(); it!=res.end(); ++it)
|
// Update Files and Directories
|
||||||
|
|
||||||
|
for(QStringList::iterator line_it=res.begin(); line_it!=res.end(); ++line_it)
|
||||||
{
|
{
|
||||||
QString line = (*it).trimmed();
|
QString line = (*line_it).trimmed();
|
||||||
if(line.length()==0)
|
if(line.length()==0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -467,26 +514,114 @@ void MainWindow::scanWorkspace()
|
|||||||
|
|
||||||
filemap_t::iterator it = workspaceFiles.find(fname);
|
filemap_t::iterator it = workspaceFiles.find(fname);
|
||||||
|
|
||||||
|
RepoFile *rf = 0;
|
||||||
if(add_missing && it==workspaceFiles.end())
|
if(add_missing && it==workspaceFiles.end())
|
||||||
{
|
{
|
||||||
RepoFile e;
|
|
||||||
QFileInfo info(wkdir+QDir::separator()+fname);
|
QFileInfo info(wkdir+QDir::separator()+fname);
|
||||||
e.set(info, type, wkdir);
|
rf = new RepoFile(info, type, wkdir);
|
||||||
workspaceFiles.insert(e.getFilename(), e);
|
workspaceFiles.insert(rf->getFilePath(), rf);
|
||||||
}
|
}
|
||||||
|
|
||||||
it = workspaceFiles.find(fname);
|
if(!rf)
|
||||||
Q_ASSERT(it!=workspaceFiles.end());
|
{
|
||||||
|
it = workspaceFiles.find(fname);
|
||||||
|
Q_ASSERT(it!=workspaceFiles.end());
|
||||||
|
rf = *it;
|
||||||
|
}
|
||||||
|
|
||||||
it.value().setType(type);
|
rf->setType(type);
|
||||||
|
|
||||||
|
QString path = rf->getPath();
|
||||||
|
pathSet.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the model
|
// Update the file item model
|
||||||
|
updateDirView();
|
||||||
|
updateFileView();
|
||||||
|
|
||||||
|
setEnabled(true);
|
||||||
|
setStatus("");
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void addPathToTree(QStandardItem &root, const QString &path)
|
||||||
|
{
|
||||||
|
QStringList dirs = path.split('/');
|
||||||
|
QStandardItem *parent = &root;
|
||||||
|
|
||||||
|
QString fullpath;
|
||||||
|
for(QStringList::iterator it = dirs.begin(); it!=dirs.end(); ++it)
|
||||||
|
{
|
||||||
|
const QString &dir = *it;
|
||||||
|
fullpath += dir;
|
||||||
|
|
||||||
|
// Find the child that matches this subdir
|
||||||
|
bool found = false;
|
||||||
|
for(int r=0; r<parent->rowCount(); ++r)
|
||||||
|
{
|
||||||
|
QStandardItem *child = parent->child(r, 0);
|
||||||
|
Q_ASSERT(child);
|
||||||
|
if(child->text() == dir)
|
||||||
|
{
|
||||||
|
parent = child;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found) // Generate it
|
||||||
|
{
|
||||||
|
QStandardItem *child = new QStandardItem(QIcon(":icons/icons/Folder-01.png"), dir);
|
||||||
|
child->setData(fullpath); // keep the full path to simplify selection
|
||||||
|
parent->appendRow(child);
|
||||||
|
parent = child;
|
||||||
|
}
|
||||||
|
fullpath += '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::updateDirView()
|
||||||
|
{
|
||||||
|
if(viewMode == VIEWMODE_TREE)
|
||||||
|
{
|
||||||
|
// Directory View
|
||||||
|
repoDirModel.clear();
|
||||||
|
QStandardItem *root = new QStandardItem(QIcon(":icons/icons/My Documents-01.png"), projectName);
|
||||||
|
root->setData(""); // Empty Path
|
||||||
|
root->setEditable(false);
|
||||||
|
QString aa = root->data().toString();
|
||||||
|
repoDirModel.appendRow(root);
|
||||||
|
for(pathset_t::iterator it = pathSet.begin(); it!=pathSet.end(); ++it)
|
||||||
|
{
|
||||||
|
const QString &dir = *it;
|
||||||
|
if(dir.isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
addPathToTree(*root, dir);
|
||||||
|
}
|
||||||
|
ui->treeView->expandToDepth(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::updateFileView()
|
||||||
|
{
|
||||||
|
// File View
|
||||||
// Clear all rows (except header)
|
// Clear all rows (except header)
|
||||||
itemModel.removeRows(0, itemModel.rowCount());
|
repoFileModel.clear();
|
||||||
|
|
||||||
|
QStringList header;
|
||||||
|
header << tr("S") << tr("File") << tr("Ext") << tr("Modified");
|
||||||
|
|
||||||
|
if(viewMode==VIEWMODE_LIST)
|
||||||
|
header << tr("Path");
|
||||||
|
|
||||||
|
repoFileModel.setHorizontalHeaderLabels(header);
|
||||||
|
|
||||||
struct { RepoFile::EntryType type; const char *tag; const char *tooltip; const char *icon; }
|
struct { RepoFile::EntryType type; const char *tag; const char *tooltip; const char *icon; }
|
||||||
stats[] = {
|
stats[] =
|
||||||
|
{
|
||||||
{ RepoFile::TYPE_EDITTED, "E", "Editted", ":icons/icons/Button Blank Yellow-01.png" },
|
{ RepoFile::TYPE_EDITTED, "E", "Editted", ":icons/icons/Button Blank Yellow-01.png" },
|
||||||
{ RepoFile::TYPE_UNCHANGED, "U", "Unchanged", ":icons/icons/Button Blank Green-01.png" },
|
{ RepoFile::TYPE_UNCHANGED, "U", "Unchanged", ":icons/icons/Button Blank Green-01.png" },
|
||||||
{ RepoFile::TYPE_ADDED, "A", "Added", ":icons/icons/Button Add-01.png" },
|
{ RepoFile::TYPE_ADDED, "A", "Added", ":icons/icons/Button Add-01.png" },
|
||||||
@ -495,13 +630,18 @@ void MainWindow::scanWorkspace()
|
|||||||
{ RepoFile::TYPE_MISSING, "M", "Missing", ":icons/icons/Button Help-01.png" },
|
{ RepoFile::TYPE_MISSING, "M", "Missing", ":icons/icons/Button Help-01.png" },
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t num_files = workspaceFiles.size();
|
//size_t num_files = workspaceFiles.size();
|
||||||
itemModel.insertRows(0, num_files);
|
//repoFileModel.insertRows(0, num_files);
|
||||||
|
|
||||||
size_t i=0;
|
size_t item_id=0;
|
||||||
for(filemap_t::iterator it = workspaceFiles.begin(); it!=workspaceFiles.end(); ++it, ++i)
|
for(filemap_t::iterator it = workspaceFiles.begin(); it!=workspaceFiles.end(); ++it)
|
||||||
{
|
{
|
||||||
const RepoFile &e = it.value();
|
const RepoFile &e = *it.value();
|
||||||
|
QString path = e.getPath();
|
||||||
|
|
||||||
|
// In Tree mode, filter all items not included in the current dir
|
||||||
|
if(viewMode==VIEWMODE_TREE && path != viewDir)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Status Column
|
// Status Column
|
||||||
const char *tag = "?"; // Default Tag
|
const char *tag = "?"; // Default Tag
|
||||||
@ -521,26 +661,35 @@ void MainWindow::scanWorkspace()
|
|||||||
|
|
||||||
QStandardItem *status = new QStandardItem(QIcon(status_icon), tag);
|
QStandardItem *status = new QStandardItem(QIcon(status_icon), tag);
|
||||||
status->setToolTip(tooltip);
|
status->setToolTip(tooltip);
|
||||||
itemModel.setItem(i, COLUMN_STATUS, status);
|
repoFileModel.setItem(item_id, COLUMN_STATUS, status);
|
||||||
|
|
||||||
QString path = e.getFilename();
|
|
||||||
path = path.left(path.indexOf(e.getFileInfo().fileName()));
|
|
||||||
QFileInfo finfo = e.getFileInfo();
|
QFileInfo finfo = e.getFileInfo();
|
||||||
|
|
||||||
itemModel.setItem(i, COLUMN_PATH, new QStandardItem(path));
|
QStandardItem *filename_item = 0;
|
||||||
itemModel.setItem(i, COLUMN_FILENAME, new QStandardItem(e.getFilename()));
|
if(viewMode==VIEWMODE_LIST)
|
||||||
itemModel.setItem(i, COLUMN_EXTENSION, new QStandardItem(finfo .completeSuffix()));
|
{
|
||||||
itemModel.setItem(i, COLUMN_MODIFIED, new QStandardItem(finfo .lastModified().toString(Qt::SystemLocaleShortDate)));
|
repoFileModel.setItem(item_id, COLUMN_PATH, new QStandardItem(path));
|
||||||
|
|
||||||
|
filename_item = new QStandardItem(e.getFilePath());
|
||||||
|
}
|
||||||
|
else // In Tree mode the path is implicit so the file name is enough
|
||||||
|
filename_item = new QStandardItem(e.getFilename());
|
||||||
|
|
||||||
|
Q_ASSERT(filename_item);
|
||||||
|
// Keep the path in the user data
|
||||||
|
filename_item->setData(e.getFilePath());
|
||||||
|
repoFileModel.setItem(item_id, COLUMN_FILENAME, filename_item);
|
||||||
|
|
||||||
|
repoFileModel.setItem(item_id, COLUMN_EXTENSION, new QStandardItem(finfo .completeSuffix()));
|
||||||
|
repoFileModel.setItem(item_id, COLUMN_MODIFIED, new QStandardItem(finfo .lastModified().toString(Qt::SystemLocaleShortDate)));
|
||||||
|
|
||||||
|
++item_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->tableView->resizeColumnsToContents();
|
ui->tableView->resizeColumnsToContents();
|
||||||
ui->tableView->resizeRowsToContents();
|
ui->tableView->resizeRowsToContents();
|
||||||
|
|
||||||
setEnabled(true);
|
|
||||||
setStatus("");
|
|
||||||
QApplication::restoreOverrideCursor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
MainWindow::RepoStatus MainWindow::getRepoStatus()
|
MainWindow::RepoStatus MainWindow::getRepoStatus()
|
||||||
{
|
{
|
||||||
@ -653,7 +802,7 @@ bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int
|
|||||||
process.start(fossil, args);
|
process.start(fossil, args);
|
||||||
if(!process.waitForStarted())
|
if(!process.waitForStarted())
|
||||||
{
|
{
|
||||||
log("Could not start fossil executable '" + fossil + "''\n");
|
log(tr("Could not start fossil executable '") + fossil + "''\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,7 +817,7 @@ bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int
|
|||||||
{
|
{
|
||||||
if(fossilAbort)
|
if(fossilAbort)
|
||||||
{
|
{
|
||||||
log("\n* Terminated *\n");
|
log("\n* "+tr("Terminated")+" *\n");
|
||||||
#ifdef Q_WS_WIN
|
#ifdef Q_WS_WIN
|
||||||
fossilUI.kill(); // QT on windows cannot terminate console processes with QProcess::terminate
|
fossilUI.kill(); // QT on windows cannot terminate console processes with QProcess::terminate
|
||||||
#else
|
#else
|
||||||
@ -848,8 +997,9 @@ void MainWindow::loadSettings()
|
|||||||
if(qsettings.contains("ViewUnchanged"))
|
if(qsettings.contains("ViewUnchanged"))
|
||||||
ui->actionViewUnchanged->setChecked(qsettings.value("ViewUnchanged").toBool());
|
ui->actionViewUnchanged->setChecked(qsettings.value("ViewUnchanged").toBool());
|
||||||
if(qsettings.contains("ViewIgnored"))
|
if(qsettings.contains("ViewIgnored"))
|
||||||
ui->actionViewUnchanged->setChecked(qsettings.value("ViewIgnored").toBool());
|
ui->actionViewIgnored->setChecked(qsettings.value("ViewIgnored").toBool());
|
||||||
|
if(qsettings.contains("ViewAsList"))
|
||||||
|
ui->actionViewAsList->setChecked(qsettings.value("ViewAsList").toBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -881,10 +1031,80 @@ void MainWindow::saveSettings()
|
|||||||
qsettings.setValue("ViewModified", ui->actionViewModified->isChecked());
|
qsettings.setValue("ViewModified", ui->actionViewModified->isChecked());
|
||||||
qsettings.setValue("ViewUnchanged", ui->actionViewUnchanged->isChecked());
|
qsettings.setValue("ViewUnchanged", ui->actionViewUnchanged->isChecked());
|
||||||
qsettings.setValue("ViewIgnored", ui->actionViewIgnored->isChecked());
|
qsettings.setValue("ViewIgnored", ui->actionViewIgnored->isChecked());
|
||||||
|
qsettings.setValue("ViewAsList", ui->actionViewAsList->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void MainWindow::getSelectionFilenames(QStringList &filenames, int includeMask, bool allIfEmpty)
|
void MainWindow::getSelectionFilenames(QStringList &filenames, int includeMask, bool allIfEmpty)
|
||||||
|
{
|
||||||
|
if(QApplication::focusWidget() == ui->tableView)
|
||||||
|
getFileViewSelection(filenames, includeMask, allIfEmpty);
|
||||||
|
else if(QApplication::focusWidget() == ui->treeView)
|
||||||
|
getDirViewSelection(filenames, includeMask, allIfEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::getSelectionPaths(pathset_t &paths)
|
||||||
|
{
|
||||||
|
// Determine the directories selected
|
||||||
|
QModelIndexList selection = ui->treeView->selectionModel()->selectedIndexes();
|
||||||
|
for(QModelIndexList::iterator mi_it = selection.begin(); mi_it!=selection.end(); ++mi_it)
|
||||||
|
{
|
||||||
|
const QModelIndex &mi = *mi_it;
|
||||||
|
QVariant data = repoDirModel.data(mi, REPODIRMODEL_ROLE_PATH);
|
||||||
|
paths.insert(data.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::getDirViewSelection(QStringList &filenames, int includeMask, bool allIfEmpty)
|
||||||
|
{
|
||||||
|
// Determine the directories selected
|
||||||
|
pathset_t paths;
|
||||||
|
|
||||||
|
QModelIndexList selection = ui->treeView->selectionModel()->selectedIndexes();
|
||||||
|
if(!(selection.empty() && allIfEmpty))
|
||||||
|
{
|
||||||
|
getSelectionPaths(paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the actual files form the selected directories
|
||||||
|
for(filemap_t::iterator it=workspaceFiles.begin(); it!=workspaceFiles.end(); ++it)
|
||||||
|
{
|
||||||
|
const RepoFile &e = *(*it);
|
||||||
|
|
||||||
|
// Skip unwanted file types
|
||||||
|
if(!(includeMask & e.getType()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool include = true;
|
||||||
|
|
||||||
|
// If we have a limited set of paths to filter, check them
|
||||||
|
if(!paths.empty())
|
||||||
|
include = false;
|
||||||
|
|
||||||
|
for(pathset_t::iterator p_it=paths.begin(); p_it!=paths.end(); ++p_it)
|
||||||
|
{
|
||||||
|
const QString &path = *p_it;
|
||||||
|
// An empty path is the root folder, so it includes all files
|
||||||
|
// If the file's path starts with this, we include id
|
||||||
|
if(path.isEmpty() || e.getPath().indexOf(path)==0)
|
||||||
|
{
|
||||||
|
include = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!include)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
filenames.append(e.getFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << filenames;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::getFileViewSelection(QStringList &filenames, int includeMask, bool allIfEmpty)
|
||||||
{
|
{
|
||||||
QModelIndexList selection = ui->tableView->selectionModel()->selectedIndexes();
|
QModelIndexList selection = ui->tableView->selectionModel()->selectedIndexes();
|
||||||
if(selection.empty() && allIfEmpty)
|
if(selection.empty() && allIfEmpty)
|
||||||
@ -903,11 +1123,11 @@ void MainWindow::getSelectionFilenames(QStringList &filenames, int includeMask,
|
|||||||
if(mi.column()!=COLUMN_FILENAME)
|
if(mi.column()!=COLUMN_FILENAME)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QVariant data = itemModel.data(mi);
|
QVariant data = repoFileModel.data(mi, Qt::UserRole+1);
|
||||||
QString filename = data.toString();
|
QString filename = data.toString();
|
||||||
filemap_t::iterator e_it = workspaceFiles.find(filename);
|
filemap_t::iterator e_it = workspaceFiles.find(filename);
|
||||||
Q_ASSERT(e_it!=workspaceFiles.end());
|
Q_ASSERT(e_it!=workspaceFiles.end());
|
||||||
const RepoFile &e = e_it.value();
|
const RepoFile &e = *e_it.value();
|
||||||
|
|
||||||
// Skip unwanted files
|
// Skip unwanted files
|
||||||
if(!(includeMask & e.getType()))
|
if(!(includeMask & e.getType()))
|
||||||
@ -1036,7 +1256,7 @@ void MainWindow::on_actionHistory_triggered()
|
|||||||
|
|
||||||
for(QStringList::iterator it = selection.begin(); it!=selection.end(); ++it)
|
for(QStringList::iterator it = selection.begin(); it!=selection.end(); ++it)
|
||||||
{
|
{
|
||||||
QDesktopServices::openUrl(QUrl(getFossilHttpAddress()+"/finfo?name="+*it));
|
QDesktopServices::openUrl(QUrl(getFossilHttpAddress()+"/finfo?name="+*it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1229,7 +1449,7 @@ void MainWindow::on_actionRename_triggered()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void MainWindow::on_actionNew_triggered()
|
void MainWindow::on_actionNewRepository_triggered()
|
||||||
{
|
{
|
||||||
QString filter(tr("Fossil Repositories (*.fossil)"));
|
QString filter(tr("Fossil Repositories (*.fossil)"));
|
||||||
|
|
||||||
@ -1281,6 +1501,32 @@ void MainWindow::on_actionNew_triggered()
|
|||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::on_actionOpenRepository_triggered()
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
QString filter(tr("Fossil Repositories (*.fossil)"));
|
||||||
|
|
||||||
|
QString path = QFileDialog::getOpenFileName(
|
||||||
|
this,
|
||||||
|
tr("Fossil Repository"),
|
||||||
|
QDir::currentPath(),
|
||||||
|
filter,
|
||||||
|
&filter);
|
||||||
|
|
||||||
|
if(path.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!QFile::exists(path))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Repository file does not exist."), QMessageBox::Ok );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void MainWindow::on_actionClone_triggered()
|
void MainWindow::on_actionClone_triggered()
|
||||||
{
|
{
|
||||||
@ -1478,10 +1724,210 @@ void MainWindow::on_actionViewIgnored_triggered()
|
|||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::on_actionViewAsList_triggered()
|
||||||
|
{
|
||||||
|
viewMode = ui->actionViewAsList->isChecked() ? VIEWMODE_LIST : VIEWMODE_TREE;
|
||||||
|
ui->treeView->setVisible(viewMode == VIEWMODE_TREE);
|
||||||
|
updateFileView();
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
QString MainWindow::getFossilHttpAddress()
|
QString MainWindow::getFossilHttpAddress()
|
||||||
{
|
{
|
||||||
return "http://127.0.0.1:"+fossilUIPort;
|
return "http://127.0.0.1:"+fossilUIPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::on_treeView_selectionChanged(const QItemSelection &selected, const QItemSelection &/*deselected*/)
|
||||||
|
{
|
||||||
|
if(selected.indexes().count()!=1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QModelIndex index = selected.indexes().at(0);
|
||||||
|
viewDir = repoDirModel.data(index, REPODIRMODEL_ROLE_PATH).toString();
|
||||||
|
setStatus(viewDir);
|
||||||
|
updateFileView();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::on_actionOpenFolder_triggered()
|
||||||
|
{
|
||||||
|
const QItemSelection &selection = ui->treeView->selectionModel()->selection();
|
||||||
|
|
||||||
|
if(selection.indexes().count()!=1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QModelIndex index = selection.indexes().at(0);
|
||||||
|
QString target = repoDirModel.data(index, REPODIRMODEL_ROLE_PATH).toString();
|
||||||
|
target = getCurrentWorkspace() + PATH_SEP + target;
|
||||||
|
|
||||||
|
QUrl url = QUrl::fromLocalFile(target);
|
||||||
|
QDesktopServices::openUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MainWindow::on_actionRenameFolder_triggered()
|
||||||
|
{
|
||||||
|
pathset_t paths;
|
||||||
|
getSelectionPaths(paths);
|
||||||
|
|
||||||
|
if(paths.size()!=1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString old_path = *paths.begin();
|
||||||
|
|
||||||
|
// Root Node?
|
||||||
|
if(old_path.isEmpty())
|
||||||
|
{
|
||||||
|
// Cannot change the project name via command line
|
||||||
|
// so unsupported
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dir_start = old_path.lastIndexOf(PATH_SEP);
|
||||||
|
if(dir_start==-1)
|
||||||
|
dir_start = 0;
|
||||||
|
else
|
||||||
|
++dir_start;
|
||||||
|
|
||||||
|
QString old_name = old_path.mid(dir_start);
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
QString new_name = QInputDialog::getText(this, tr("Rename Folder"), tr("Enter new name"), QLineEdit::Normal, old_name, &ok, Qt::Sheet);
|
||||||
|
if(!ok || old_name==new_name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char* invalid_tokens[] = {
|
||||||
|
"/", "\\", "\\\\", ":", ">", "<", "*", "?", "|", "\"", ".."
|
||||||
|
};
|
||||||
|
|
||||||
|
for(size_t i=0; i<COUNTOF(invalid_tokens); ++i)
|
||||||
|
{
|
||||||
|
if(new_name.indexOf(invalid_tokens[i])!=-1)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Cannot rename folder.\nFolder name contains invalid characters."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString new_path = old_path.left(dir_start) + new_name;
|
||||||
|
|
||||||
|
if(pathSet.contains(new_path))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Cannot rename folder.\nThis folder exists already."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect the files to be moved
|
||||||
|
filelist_t files_to_move;
|
||||||
|
QStringList new_paths;
|
||||||
|
QStringList operations;
|
||||||
|
foreach(RepoFile *r, workspaceFiles)
|
||||||
|
{
|
||||||
|
if(r->getPath().indexOf(old_path)!=0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
files_to_move.append(r);
|
||||||
|
QString new_dir = new_path + r->getPath().mid(old_path.length());
|
||||||
|
new_paths.append(new_dir);
|
||||||
|
QString new_file_path = new_dir + PATH_SEP + r->getFilename();
|
||||||
|
operations.append(r->getFilePath() + " -> " + new_file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(files_to_move.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool move_local = false;
|
||||||
|
if(!FileActionDialog::run(this, tr("Rename Folder"), tr("Renaming folder '")+old_path+tr("' to '")+new_path
|
||||||
|
+tr("'\nThe following files will be moved in the repository. Are you sure?"),
|
||||||
|
operations,
|
||||||
|
tr("Also move the workspace files"), &move_local)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename files in fossil
|
||||||
|
Q_ASSERT(files_to_move.length() == new_paths.length());
|
||||||
|
for(int i=0; i<files_to_move.length(); ++i)
|
||||||
|
{
|
||||||
|
RepoFile *r = files_to_move[i];
|
||||||
|
const QString &new_file_path = new_paths[i] + PATH_SEP + r->getFilename();
|
||||||
|
|
||||||
|
if(!runFossil(QStringList() << "mv" << QuotePath(r->getFilePath()) << QuotePath(new_file_path)))
|
||||||
|
{
|
||||||
|
log(tr("Move aborted due to errors\n"));
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!move_local)
|
||||||
|
goto _exit;
|
||||||
|
|
||||||
|
// First ensure that the target directories exist, and if not make them
|
||||||
|
for(int i=0; i<files_to_move.length(); ++i)
|
||||||
|
{
|
||||||
|
QString target_path = QDir::cleanPath(getCurrentWorkspace() + PATH_SEP + new_paths[i] + PATH_SEP);
|
||||||
|
QDir target(target_path);
|
||||||
|
|
||||||
|
if(target.exists())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QDir wkdir(getCurrentWorkspace());
|
||||||
|
Q_ASSERT(wkdir.exists());
|
||||||
|
|
||||||
|
log(tr("Creating folder '")+target_path+"'\n");
|
||||||
|
if(!wkdir.mkpath(new_paths[i] + PATH_SEP + "."))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Cannot make target folder '")+target_path+"'\n");
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that target directories exist copy files
|
||||||
|
for(int i=0; i<files_to_move.length(); ++i)
|
||||||
|
{
|
||||||
|
RepoFile *r = files_to_move[i];
|
||||||
|
QString new_file_path = new_paths[i] + PATH_SEP + r->getFilename();
|
||||||
|
|
||||||
|
if(QFile::exists(new_file_path))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Target file '")+new_file_path+tr("' exists already"));
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(tr("Copying file '")+r->getFilePath()+tr("' to '")+new_file_path+"'\n");
|
||||||
|
|
||||||
|
if(!QFile::copy(r->getFilePath(), new_file_path))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Cannot copy file '")+r->getFilePath()+tr("' to '")+new_file_path+"'");
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally delete old files
|
||||||
|
for(int i=0; i<files_to_move.length(); ++i)
|
||||||
|
{
|
||||||
|
RepoFile *r = files_to_move[i];
|
||||||
|
|
||||||
|
log(tr("Removing old file '")+r->getFilePath()+"'\n");
|
||||||
|
|
||||||
|
if(!QFile::exists(r->getFilePath()))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Source file '")+r->getFilePath()+tr("' does not exist"));
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!QFile::remove(r->getFilePath()))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Cannot remove file '")+r->getFilePath()+"'");
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log(tr("Folder renamed completed. Don't forget to commit!\n"));
|
||||||
|
|
||||||
|
_exit:
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
62
MainWindow.h
62
MainWindow.h
@ -8,6 +8,7 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QSet>
|
||||||
#include "SettingsDialog.h"
|
#include "SettingsDialog.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@ -32,11 +33,17 @@ struct RepoFile
|
|||||||
TYPE_ALL = TYPE_UNKNOWN|TYPE_REPO
|
TYPE_ALL = TYPE_UNKNOWN|TYPE_REPO
|
||||||
};
|
};
|
||||||
|
|
||||||
void set(QFileInfo &info, EntryType type, const QString &repoPath)
|
RepoFile(QFileInfo &info, EntryType type, const QString &repoPath)
|
||||||
{
|
{
|
||||||
FileInfo = info;
|
FileInfo = info;
|
||||||
Type = type;
|
Type = type;
|
||||||
Filename = getRelativeFilename(repoPath);
|
FilePath = getRelativeFilename(repoPath);
|
||||||
|
|
||||||
|
if(FilePath.indexOf('/')!=-1)
|
||||||
|
{
|
||||||
|
Path = FilePath;
|
||||||
|
Path = Path.left(Path.indexOf(FileInfo.fileName())-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isType(EntryType t) const
|
bool isType(EntryType t) const
|
||||||
@ -64,9 +71,19 @@ struct RepoFile
|
|||||||
return Type == TYPE_UNCHANGED || Type == TYPE_EDITTED;
|
return Type == TYPE_UNCHANGED || Type == TYPE_EDITTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString &getFilename() const
|
const QString &getFilePath() const
|
||||||
{
|
{
|
||||||
return Filename;
|
return FilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getFilename() const
|
||||||
|
{
|
||||||
|
return FileInfo.fileName();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &getPath() const
|
||||||
|
{
|
||||||
|
return Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getRelativeFilename(const QString &path)
|
QString getRelativeFilename(const QString &path)
|
||||||
@ -84,7 +101,8 @@ struct RepoFile
|
|||||||
private:
|
private:
|
||||||
QFileInfo FileInfo;
|
QFileInfo FileInfo;
|
||||||
EntryType Type;
|
EntryType Type;
|
||||||
QString Filename;
|
QString FilePath;
|
||||||
|
QString Path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -98,6 +116,9 @@ public:
|
|||||||
~MainWindow();
|
~MainWindow();
|
||||||
bool diffFile(QString repoFile);
|
bool diffFile(QString repoFile);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef QSet<QString> pathset_t;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool refresh();
|
bool refresh();
|
||||||
void scanWorkspace();
|
void scanWorkspace();
|
||||||
@ -111,6 +132,9 @@ private:
|
|||||||
void setStatus(const QString &text);
|
void setStatus(const QString &text);
|
||||||
bool uiRunning() const { return fossilUI.state() == QProcess::Running; }
|
bool uiRunning() const { return fossilUI.state() == QProcess::Running; }
|
||||||
void getSelectionFilenames(QStringList &filenames, int includeMask=RepoFile::TYPE_ALL, bool allIfEmpty=false);
|
void getSelectionFilenames(QStringList &filenames, int includeMask=RepoFile::TYPE_ALL, bool allIfEmpty=false);
|
||||||
|
void getFileViewSelection(QStringList &filenames, int includeMask=RepoFile::TYPE_ALL, bool allIfEmpty=false);
|
||||||
|
void getDirViewSelection(QStringList &filenames, int includeMask=RepoFile::TYPE_ALL, bool allIfEmpty=false);
|
||||||
|
void getSelectionPaths(pathset_t &paths);
|
||||||
bool startUI();
|
bool startUI();
|
||||||
void stopUI();
|
void stopUI();
|
||||||
void enableActions(bool on);
|
void enableActions(bool on);
|
||||||
@ -121,6 +145,8 @@ private:
|
|||||||
QString getFossilPath();
|
QString getFossilPath();
|
||||||
QString getFossilHttpAddress();
|
QString getFossilHttpAddress();
|
||||||
bool scanDirectory(QFileInfoList &entries, const QString& dirPath, const QString &baseDir, const QString ignoreSpec);
|
bool scanDirectory(QFileInfoList &entries, const QString& dirPath, const QString &baseDir, const QString ignoreSpec);
|
||||||
|
void updateDirView();
|
||||||
|
void updateFileView();
|
||||||
|
|
||||||
enum RepoStatus
|
enum RepoStatus
|
||||||
{
|
{
|
||||||
@ -131,9 +157,16 @@ private:
|
|||||||
|
|
||||||
RepoStatus getRepoStatus();
|
RepoStatus getRepoStatus();
|
||||||
|
|
||||||
|
enum ViewMode
|
||||||
|
{
|
||||||
|
VIEWMODE_LIST,
|
||||||
|
VIEWMODE_TREE
|
||||||
|
};
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
// Manual slots
|
// Manual slots
|
||||||
void onOpenRecent();
|
void on_openRecent();
|
||||||
|
void on_treeView_selectionChanged(const class QItemSelection &selected, const class QItemSelection &deselected);
|
||||||
|
|
||||||
// Designer slots
|
// Designer slots
|
||||||
void on_actionRefresh_triggered();
|
void on_actionRefresh_triggered();
|
||||||
@ -152,7 +185,6 @@ private slots:
|
|||||||
void on_actionAdd_triggered();
|
void on_actionAdd_triggered();
|
||||||
void on_actionDelete_triggered();
|
void on_actionDelete_triggered();
|
||||||
void on_actionRevert_triggered();
|
void on_actionRevert_triggered();
|
||||||
void on_actionNew_triggered();
|
|
||||||
void on_actionClone_triggered();
|
void on_actionClone_triggered();
|
||||||
void on_actionOpenContaining_triggered();
|
void on_actionOpenContaining_triggered();
|
||||||
void on_actionRename_triggered();
|
void on_actionRename_triggered();
|
||||||
@ -164,8 +196,12 @@ private slots:
|
|||||||
void on_actionViewUnchanged_triggered();
|
void on_actionViewUnchanged_triggered();
|
||||||
void on_actionViewModified_triggered();
|
void on_actionViewModified_triggered();
|
||||||
void on_actionViewUnknown_triggered();
|
void on_actionViewUnknown_triggered();
|
||||||
|
|
||||||
void on_actionViewIgnored_triggered();
|
void on_actionViewIgnored_triggered();
|
||||||
|
void on_actionViewAsList_triggered();
|
||||||
|
void on_actionOpenFolder_triggered();
|
||||||
|
void on_actionRenameFolder_triggered();
|
||||||
|
void on_actionOpenRepository_triggered();
|
||||||
|
void on_actionNewRepository_triggered();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
@ -174,7 +210,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
QStandardItemModel itemModel;
|
QStandardItemModel repoFileModel;
|
||||||
|
QStandardItemModel repoDirModel;
|
||||||
QProcess fossilUI;
|
QProcess fossilUI;
|
||||||
QString fossilUIPort;
|
QString fossilUIPort;
|
||||||
class QAction *recentWorkspaceActs[MAX_RECENT];
|
class QAction *recentWorkspaceActs[MAX_RECENT];
|
||||||
@ -187,11 +224,14 @@ private:
|
|||||||
QStringList workspaceHistory;
|
QStringList workspaceHistory;
|
||||||
QString currentWorkspace;
|
QString currentWorkspace;
|
||||||
QStringList commitMessages;
|
QStringList commitMessages;
|
||||||
|
ViewMode viewMode;
|
||||||
|
QString viewDir; // The directory selected in the tree
|
||||||
|
|
||||||
// Repo State
|
// Repo State
|
||||||
typedef QMap<QString, RepoFile> filemap_t;
|
typedef QList<RepoFile*> filelist_t;
|
||||||
|
typedef QMap<QString, RepoFile*> filemap_t;
|
||||||
filemap_t workspaceFiles;
|
filemap_t workspaceFiles;
|
||||||
|
pathset_t pathSet;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
204
MainWindow.ui
204
MainWindow.ui
@ -26,47 +26,84 @@
|
|||||||
<number>4</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QSplitter" name="splitter">
|
<widget class="QSplitter" name="splitter_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QTableView" name="tableView">
|
<widget class="QSplitter" name="splitter">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>80</verstretch>
|
<verstretch>80</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="contextMenuPolicy">
|
<property name="orientation">
|
||||||
<enum>Qt::ActionsContextMenu</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="editTriggers">
|
<widget class="QTreeView" name="treeView">
|
||||||
<set>QAbstractItemView::NoEditTriggers</set>
|
<property name="sizePolicy">
|
||||||
</property>
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<property name="alternatingRowColors">
|
<horstretch>20</horstretch>
|
||||||
<bool>true</bool>
|
<verstretch>0</verstretch>
|
||||||
</property>
|
</sizepolicy>
|
||||||
<property name="selectionBehavior">
|
</property>
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
<property name="contextMenuPolicy">
|
||||||
</property>
|
<enum>Qt::ActionsContextMenu</enum>
|
||||||
<property name="showGrid">
|
</property>
|
||||||
<bool>false</bool>
|
<property name="editTriggers">
|
||||||
</property>
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
<property name="sortingEnabled">
|
</property>
|
||||||
<bool>true</bool>
|
<property name="selectionMode">
|
||||||
</property>
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
<property name="wordWrap">
|
</property>
|
||||||
<bool>false</bool>
|
<property name="selectionBehavior">
|
||||||
</property>
|
<enum>QAbstractItemView::SelectItems</enum>
|
||||||
<attribute name="horizontalHeaderMinimumSectionSize">
|
</property>
|
||||||
<number>20</number>
|
<property name="sortingEnabled">
|
||||||
</attribute>
|
<bool>true</bool>
|
||||||
<attribute name="verticalHeaderVisible">
|
</property>
|
||||||
<bool>false</bool>
|
<attribute name="headerVisible">
|
||||||
</attribute>
|
<bool>false</bool>
|
||||||
<attribute name="verticalHeaderDefaultSectionSize">
|
</attribute>
|
||||||
<number>30</number>
|
</widget>
|
||||||
</attribute>
|
<widget class="QTableView" name="tableView">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>80</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::ActionsContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="showGrid">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderMinimumSectionSize">
|
||||||
|
<number>20</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderDefaultSectionSize">
|
||||||
|
<number>30</number>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QTextBrowser" name="textBrowser">
|
<widget class="QTextBrowser" name="textBrowser">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -93,11 +130,12 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Workspace</string>
|
<string>Workspace</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionNew"/>
|
|
||||||
<addaction name="actionOpen"/>
|
<addaction name="actionOpen"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionSyncSettings"/>
|
<addaction name="actionNewRepository"/>
|
||||||
|
<addaction name="actionOpenRepository"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionSyncSettings"/>
|
||||||
<addaction name="actionSettings"/>
|
<addaction name="actionSettings"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
@ -117,6 +155,8 @@
|
|||||||
<addaction name="actionViewUnchanged"/>
|
<addaction name="actionViewUnchanged"/>
|
||||||
<addaction name="actionViewUnknown"/>
|
<addaction name="actionViewUnknown"/>
|
||||||
<addaction name="actionViewIgnored"/>
|
<addaction name="actionViewIgnored"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionViewAsList"/>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
<addaction name="menuView"/>
|
<addaction name="menuView"/>
|
||||||
@ -240,6 +280,9 @@
|
|||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Open a fossil checkout folder</string>
|
<string>Open a fossil checkout folder</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Open a fossil checkout folder</string>
|
||||||
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+O</string>
|
<string>Ctrl+O</string>
|
||||||
</property>
|
</property>
|
||||||
@ -294,6 +337,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Quit</string>
|
<string>Quit</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Quit</string>
|
||||||
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+Q</string>
|
<string>Ctrl+Q</string>
|
||||||
</property>
|
</property>
|
||||||
@ -379,7 +425,7 @@
|
|||||||
<string>Ctrl+Return</string>
|
<string>Ctrl+Return</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionNew">
|
<action name="actionNewRepository">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="resources.qrc">
|
<iconset resource="resources.qrc">
|
||||||
<normaloff>:/icons/icons/Book-01.png</normaloff>:/icons/icons/Book-01.png</iconset>
|
<normaloff>:/icons/icons/Book-01.png</normaloff>:/icons/icons/Book-01.png</iconset>
|
||||||
@ -387,11 +433,25 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>New Repository...</string>
|
<string>New Repository...</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Make a new Fossil repository</string>
|
||||||
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Make a new Fossil repository</string>
|
||||||
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+N</string>
|
<string>Ctrl+N</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionClone">
|
<action name="actionOpenRepository">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open Repository...</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Open Repository</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCloneRepository">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="resources.qrc">
|
<iconset resource="resources.qrc">
|
||||||
<normaloff>:/icons/icons/Address Book-01.png</normaloff>:/icons/icons/Address Book-01.png</iconset>
|
<normaloff>:/icons/icons/Address Book-01.png</normaloff>:/icons/icons/Address Book-01.png</iconset>
|
||||||
@ -432,6 +492,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>About...</string>
|
<string>About...</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>About Fuel</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionUpdate">
|
<action name="actionUpdate">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
@ -456,6 +519,9 @@
|
|||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Application Preferences</string>
|
<string>Application Preferences</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Set application preferences</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionSyncSettings">
|
<action name="actionSyncSettings">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -464,6 +530,9 @@
|
|||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Set remote synchronization settings</string>
|
<string>Set remote synchronization settings</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Set remote synchronization settings</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionViewModified">
|
<action name="actionViewModified">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@ -475,6 +544,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Modified</string>
|
<string>Modified</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Show modifed files</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionViewUnchanged">
|
<action name="actionViewUnchanged">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@ -486,6 +558,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Unchanged</string>
|
<string>Unchanged</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Show unchanged files</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionViewUnknown">
|
<action name="actionViewUnknown">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@ -497,6 +572,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Unknown</string>
|
<string>Unknown</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Show unknown files</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionViewIgnored">
|
<action name="actionViewIgnored">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@ -505,28 +583,46 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Ignored</string>
|
<string>Ignored</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Show ignored files</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionViewAsList">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>View as List</string>
|
||||||
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>View workspace as a list of files</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionOpenFolder">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/icons/icons/My Documents-01.png</normaloff>:/icons/icons/My Documents-01.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Open Folder</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRenameFolder">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/icons/icons/Folder Open-01.png</normaloff>:/icons/icons/Folder Open-01.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Rename Folder</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Rename Folder</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="resources.qrc"/>
|
<include location="resources.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections>
|
<connections/>
|
||||||
<connection>
|
|
||||||
<sender>tableView</sender>
|
|
||||||
<signal>customContextMenuRequested(QPoint)</signal>
|
|
||||||
<receiver>MainWindow</receiver>
|
|
||||||
<slot>deleteLater()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>432</x>
|
|
||||||
<y>278</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>432</x>
|
|
||||||
<y>319</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
</ui>
|
||||||
|
16
manifest
16
manifest
@ -1,14 +1,14 @@
|
|||||||
C Added\sInstaller\sfor\sWin32
|
C Added\sWorkspace\sTree\sview\nAdded\sRename\sFolder\saction\nMinor\sGUI\scleanups\n
|
||||||
D 2011-10-15T07:03:12.801
|
D 2011-10-17T14:58:09.384
|
||||||
F CommitDialog.cpp 8965e52d077c300cf1acb1b16fb2dcca5c7070f8
|
F CommitDialog.cpp 8965e52d077c300cf1acb1b16fb2dcca5c7070f8
|
||||||
F CommitDialog.h a9596d99865cf312b419d01d51334ffc916f5508
|
F CommitDialog.h a9596d99865cf312b419d01d51334ffc916f5508
|
||||||
F CommitDialog.ui 5067623f6af6f5a42c87df903278e383e945e154
|
F CommitDialog.ui 5067623f6af6f5a42c87df903278e383e945e154
|
||||||
F FileActionDialog.cpp fcaebf9986f789b3440d5390b3458ad5f86fe0c8
|
F FileActionDialog.cpp fcaebf9986f789b3440d5390b3458ad5f86fe0c8
|
||||||
F FileActionDialog.h 15db1650b3a13d70bc338371e4c033c66e3b79ce
|
F FileActionDialog.h 15db1650b3a13d70bc338371e4c033c66e3b79ce
|
||||||
F FileActionDialog.ui c63644428579741aeb5fa052e237ba799ced9ad7
|
F FileActionDialog.ui c63644428579741aeb5fa052e237ba799ced9ad7
|
||||||
F MainWindow.cpp 25d3453d37711c8bb1b01d329892ef4d58d223d8
|
F MainWindow.cpp 1ca79369fdb5cbe87dcc38d3f2aebd8a007d64f0
|
||||||
F MainWindow.h 55f90fe948661a6b7382470f3cdc80dc592e76c4
|
F MainWindow.h 6fdcb10c8a6da760c83dd05f1d07b69132ba3d4c
|
||||||
F MainWindow.ui d22becfdb32d4b31ed9a6e6d68dd144870d9a957
|
F MainWindow.ui 82a3d869e043314a0c9a4c0821de2469d565b782
|
||||||
F RepoDialog.cpp 8f20e1511526973555c774350ec413dcecf51c9e
|
F RepoDialog.cpp 8f20e1511526973555c774350ec413dcecf51c9e
|
||||||
F RepoDialog.h a958c5f98f1e6882bf41dbdd2e4df3cb89700802
|
F RepoDialog.h a958c5f98f1e6882bf41dbdd2e4df3cb89700802
|
||||||
F RepoDialog.ui be7b18199c04a3003f3c7534a616cd7441b7bb0c
|
F RepoDialog.ui be7b18199c04a3003f3c7534a616cd7441b7bb0c
|
||||||
@ -175,7 +175,7 @@ F installer/fuel.iss 13b6a938bcdf273cbd3649d2549887baa1577214
|
|||||||
F installer/license.txt 4cc77b90af91e615a64ae04893fdffa7939db84c
|
F installer/license.txt 4cc77b90af91e615a64ae04893fdffa7939db84c
|
||||||
F main.cpp f67a9b5c9ca0b634b19ef08e7136032372d37f93
|
F main.cpp f67a9b5c9ca0b634b19ef08e7136032372d37f93
|
||||||
F resources.qrc e98383ed205f4e37100c60057e0129c3b86dea53
|
F resources.qrc e98383ed205f4e37100c60057e0129c3b86dea53
|
||||||
P 4e53a5ec6844f3a210ba2fbfc2185840d697b0bb
|
P a29a3fd0f7f4c26591e1ca168ad63f1f7530edbe
|
||||||
R 62600d2edbddf7a761b84fb85d9cbf33
|
R 4d693a61ebb632ca6600c2150bca11d5
|
||||||
U kostas
|
U kostas
|
||||||
Z eb7bffb75807cc22987af216d0cd4213
|
Z a4c724920b064e72a32c87376626c0ab
|
||||||
|
@ -1 +1 @@
|
|||||||
a29a3fd0f7f4c26591e1ca168ad63f1f7530edbe
|
5fc925ac68148c69db66e88e23be196807ffec22
|
Loading…
x
Reference in New Issue
Block a user