Major reorganization of the project files
FossilOrigin-Name: 821239471319fdd5d530f54b7f67f473dcf7bd8e
This commit is contained in:
92
src/CloneDialog.cpp
Normal file
92
src/CloneDialog.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
#include "CloneDialog.h"
|
||||
#include "ui_CloneDialog.h"
|
||||
#include <QFileDialog>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QClipboard>
|
||||
#include <QUrl>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CloneDialog::CloneDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::CloneDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CloneDialog::~CloneDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CloneDialog::run(QWidget *parent, QUrl &url, QString &repository)
|
||||
{
|
||||
CloneDialog dlg(parent);
|
||||
|
||||
// Try to parse a url from the clipboard
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
if(clipboard)
|
||||
{
|
||||
QUrl nurl = QUrl::fromUserInput(clipboard->text());
|
||||
|
||||
// If we have a valid url
|
||||
if(nurl.isValid() && !nurl.isEmpty())
|
||||
{
|
||||
// Fill in dialog
|
||||
dlg.ui->lineUserName->setText(nurl.userName());
|
||||
dlg.ui->linePassword->setText(nurl.password());
|
||||
nurl.setUserName("");
|
||||
nurl.setPassword("");
|
||||
dlg.ui->lineURL->setText(nurl.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if(dlg.exec() != QDialog::Accepted)
|
||||
return false;
|
||||
|
||||
url.setUrl(dlg.ui->lineURL->text());
|
||||
if(url.isEmpty() || !url.isValid())
|
||||
{
|
||||
QMessageBox::critical(parent, tr("Error"), tr("Invalid URL."), QMessageBox::Ok );
|
||||
return false;
|
||||
}
|
||||
|
||||
url.setUserName(dlg.ui->lineUserName->text());
|
||||
url.setPassword(dlg.ui->linePassword->text());
|
||||
|
||||
if(dlg.ui->lineRepository->text().isEmpty() )
|
||||
{
|
||||
QMessageBox::critical(parent, tr("Error"), tr("Invalid Repository File."), QMessageBox::Ok );
|
||||
return false;
|
||||
}
|
||||
|
||||
repository = dlg.ui->lineRepository->text();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CloneDialog::on_btnSelectRepository_clicked()
|
||||
{
|
||||
QString filter(tr("Fossil Repository (*.fossil)"));
|
||||
|
||||
QString path = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
tr("Select Fossil Repository"),
|
||||
QDir::toNativeSeparators(ui->lineRepository->text()),
|
||||
filter,
|
||||
&filter,
|
||||
QFileDialog::DontConfirmOverwrite);
|
||||
|
||||
if(path.isEmpty())
|
||||
return;
|
||||
|
||||
if(QFile::exists(path))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("This repository file already exists."), QMessageBox::Ok );
|
||||
return;
|
||||
}
|
||||
|
||||
ui->lineRepository->setText(QDir::toNativeSeparators(path));
|
||||
}
|
27
src/CloneDialog.h
Normal file
27
src/CloneDialog.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef CLONEDIALOG_H
|
||||
#define CLONEDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class CloneDialog;
|
||||
}
|
||||
|
||||
class CloneDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CloneDialog(QWidget *parent = 0);
|
||||
~CloneDialog();
|
||||
|
||||
static bool run(QWidget *parent, class QUrl &url, QString &repository);
|
||||
|
||||
private slots:
|
||||
void on_btnSelectRepository_clicked();
|
||||
|
||||
private:
|
||||
Ui::CloneDialog *ui;
|
||||
};
|
||||
|
||||
#endif // CLONEDIALOG_H
|
130
src/CommitDialog.cpp
Normal file
130
src/CommitDialog.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
#include "CommitDialog.h"
|
||||
#include <QPushButton>
|
||||
#include "ui_CommitDialog.h"
|
||||
#include "MainWindow.h" // Ugly. I know.
|
||||
|
||||
CommitDialog::CommitDialog(QWidget *parent, QString title, QStringList &files, const QStringList *history, bool singleLineEntry, const QString *checkBoxText, bool *checkBoxValue) :
|
||||
QDialog(parent, Qt::Sheet),
|
||||
ui(new Ui::CommitDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->plainTextEdit->clear();
|
||||
ui->listView->setModel(&itemModel);
|
||||
|
||||
setWindowTitle(title);
|
||||
|
||||
// Activate the appropriate control based on mode
|
||||
ui->plainTextEdit->setVisible(!singleLineEntry);
|
||||
ui->lineEdit->setVisible(singleLineEntry);
|
||||
|
||||
// Activate the checkbox if we have some text
|
||||
ui->checkBox->setVisible(checkBoxText!=0);
|
||||
if(checkBoxText && checkBoxValue)
|
||||
{
|
||||
ui->checkBox->setText(*checkBoxText);
|
||||
ui->checkBox->setCheckState(*checkBoxValue ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
|
||||
// Activate the combo if we have history
|
||||
ui->comboBox->setVisible(history!=0);
|
||||
if(history)
|
||||
{
|
||||
// Generate the history combo
|
||||
foreach(const QString msg, *history)
|
||||
{
|
||||
QString trimmed = msg.trimmed();
|
||||
if(trimmed.isEmpty())
|
||||
continue;
|
||||
|
||||
commitMessages.append(trimmed);
|
||||
QStringList lines = trimmed.split('\n');
|
||||
QString first_line;
|
||||
if(!lines.empty())
|
||||
first_line = lines[0] + "...";
|
||||
|
||||
ui->comboBox->addItem(first_line);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate file list
|
||||
for(QStringList::const_iterator it=files.begin(); it!=files.end(); ++it)
|
||||
{
|
||||
QStandardItem *si = new QStandardItem(*it);
|
||||
si->setCheckable(true);
|
||||
si->setCheckState(Qt::Checked);
|
||||
itemModel.appendRow(si);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
CommitDialog::~CommitDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool CommitDialog::run(QWidget *parent, QString title, QStringList &files, QString &commitMsg, const QStringList *history, bool singleLineEntry, const QString *checkBoxText, bool *checkBoxValue)
|
||||
{
|
||||
CommitDialog dlg(parent, title, files, history, singleLineEntry, checkBoxText, checkBoxValue);
|
||||
int res = dlg.exec();
|
||||
|
||||
if(singleLineEntry)
|
||||
commitMsg = dlg.ui->lineEdit->text();
|
||||
else
|
||||
commitMsg = dlg.ui->plainTextEdit->toPlainText();
|
||||
|
||||
|
||||
if(res!=QDialog::Accepted)
|
||||
return false;
|
||||
|
||||
files.clear();
|
||||
for(int i=0; i<dlg.itemModel.rowCount(); ++i)
|
||||
{
|
||||
QStandardItem *si = dlg.itemModel.item(i);
|
||||
if(si->checkState()!=Qt::Checked)
|
||||
continue;
|
||||
files.append(si->text());
|
||||
}
|
||||
|
||||
if(checkBoxText)
|
||||
{
|
||||
Q_ASSERT(checkBoxValue);
|
||||
*checkBoxValue = dlg.ui->checkBox->checkState() == Qt::Checked;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CommitDialog::on_comboBox_activated(int index)
|
||||
{
|
||||
Q_ASSERT(index < commitMessages.length());
|
||||
|
||||
if(ui->plainTextEdit->isVisible())
|
||||
ui->plainTextEdit->setPlainText(commitMessages[index]);
|
||||
|
||||
if(ui->lineEdit->isVisible())
|
||||
ui->lineEdit->setText(commitMessages[index]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CommitDialog::on_listView_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
QVariant data = itemModel.data(index);
|
||||
QString filename = data.toString();
|
||||
reinterpret_cast<MainWindow*>(parent())->diffFile(filename);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CommitDialog::on_listView_clicked(const QModelIndex &)
|
||||
{
|
||||
int num_selected = 0;
|
||||
for(int i=0; i<itemModel.rowCount(); ++i)
|
||||
{
|
||||
QStandardItem *si = itemModel.item(i);
|
||||
if(si->checkState()==Qt::Checked)
|
||||
++num_selected;
|
||||
}
|
||||
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(num_selected>0);
|
||||
}
|
32
src/CommitDialog.h
Normal file
32
src/CommitDialog.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef COMMITDIALOG_H
|
||||
#define COMMITDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace Ui {
|
||||
class CommitDialog;
|
||||
}
|
||||
|
||||
class CommitDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CommitDialog(QWidget *parent, QString title, QStringList &files, const QStringList *history=0, bool singleLineEntry=false, const QString *checkBoxText=0, bool *checkBoxValue=0);
|
||||
~CommitDialog();
|
||||
|
||||
static bool run(QWidget *parent, QString title, QStringList &files, QString &commitMsg, const QStringList *history=0, bool singleLineEntry=false, const QString *checkBoxText=0, bool *checkBoxValue=0);
|
||||
|
||||
private slots:
|
||||
void on_comboBox_activated(int index);
|
||||
void on_listView_doubleClicked(const QModelIndex &index);
|
||||
void on_listView_clicked(const QModelIndex &index);
|
||||
|
||||
private:
|
||||
Ui::CommitDialog *ui;
|
||||
QStandardItemModel itemModel;
|
||||
QStringList commitMessages;
|
||||
};
|
||||
|
||||
#endif // COMMITDIALOG_H
|
64
src/FileActionDialog.cpp
Normal file
64
src/FileActionDialog.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <QCheckBox>
|
||||
#include "FileActionDialog.h"
|
||||
#include "ui_FileActionDialog.h"
|
||||
|
||||
FileActionDialog::FileActionDialog(QWidget *parent, const QString &title, const QString &message, const QStringList &listData, const QString &checkBoxText, bool *checkBoxResult) :
|
||||
QDialog(parent, Qt::Sheet),
|
||||
ui(new Ui::FileActionDialog),
|
||||
clickedButton(QDialogButtonBox::NoButton)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(title);
|
||||
ui->label->setText(message);
|
||||
ui->listView->setModel(&itemModel);
|
||||
|
||||
if(!checkBoxText.isEmpty() && checkBoxResult)
|
||||
{
|
||||
checkBox = new QCheckBox(this);
|
||||
checkBox->setText(checkBoxText);
|
||||
checkBox->setEnabled(true);
|
||||
checkBox->setChecked(*checkBoxResult);
|
||||
this->checkBoxResult = checkBoxResult;
|
||||
ui->verticalLayout->insertWidget(2, checkBox);
|
||||
}
|
||||
|
||||
if(listData.empty())
|
||||
ui->listView->setVisible(false);
|
||||
else
|
||||
{
|
||||
foreach(const QString &s, listData)
|
||||
itemModel.appendRow(new QStandardItem(s));
|
||||
}
|
||||
}
|
||||
|
||||
FileActionDialog::~FileActionDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool FileActionDialog::run(QWidget *parent, const QString &title, const QString &message, const QStringList &listData, const QString &checkBoxText, bool *checkBoxResult)
|
||||
{
|
||||
FileActionDialog dlg(parent, title, message, listData, checkBoxText, checkBoxResult);
|
||||
int res = dlg.exec();
|
||||
|
||||
if(!checkBoxText.isEmpty() && checkBoxResult && dlg.checkBox)
|
||||
*checkBoxResult = dlg.checkBox->isChecked();
|
||||
|
||||
return res == QDialog::Accepted;
|
||||
}
|
||||
|
||||
QDialogButtonBox::StandardButton FileActionDialog::runStandardButtons(QWidget *parent, StandardButtons buttons, const QString &title, const QString &message, const QStringList &listData)
|
||||
{
|
||||
FileActionDialog dlg(parent, title, message, listData);
|
||||
dlg.ui->buttonBox->setStandardButtons(buttons);
|
||||
|
||||
dlg.exec();
|
||||
return dlg.clickedButton;
|
||||
}
|
||||
|
||||
void FileActionDialog::on_buttonBox_clicked(QAbstractButton *button)
|
||||
{
|
||||
// Retrieve the flag corresponding to the standard clicked
|
||||
clickedButton = ui->buttonBox->standardButton(button);
|
||||
}
|
||||
|
38
src/FileActionDialog.h
Normal file
38
src/FileActionDialog.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef FILEACTIONDIALOG_H
|
||||
#define FILEACTIONDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QStandardItemModel>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
namespace Ui {
|
||||
class FileActionDialog;
|
||||
}
|
||||
|
||||
class FileActionDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FileActionDialog(QWidget *parent, const QString &title, const QString &message, const QStringList &listData, const QString &checkBoxText=QString(), bool *checkBoxResult=0);
|
||||
~FileActionDialog();
|
||||
|
||||
static bool run(QWidget *parent, const QString &title, const QString &message, const QStringList &listData, const QString &checkBoxText=QString(), bool *checkBoxResult=0);
|
||||
|
||||
typedef QDialogButtonBox::StandardButton StandardButton;
|
||||
typedef QDialogButtonBox::StandardButtons StandardButtons;
|
||||
|
||||
static StandardButton runStandardButtons(QWidget *parent, StandardButtons, const QString &title, const QString &message, const QStringList &listData);
|
||||
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_clicked(QAbstractButton *button);
|
||||
|
||||
private:
|
||||
Ui::FileActionDialog *ui;
|
||||
QStandardItemModel itemModel;
|
||||
class QCheckBox *checkBox;
|
||||
bool *checkBoxResult;
|
||||
StandardButton clickedButton;
|
||||
};
|
||||
|
||||
#endif // FILEACTIONDIALOG_H
|
31
src/FileTableView.cpp
Normal file
31
src/FileTableView.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include "FileTableView.h"
|
||||
#include <QMouseEvent>
|
||||
#include <QApplication>
|
||||
|
||||
FileTableView::FileTableView(QWidget *parent) :
|
||||
QTableView(parent)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FileTableView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
dragStartPos = event->pos();
|
||||
|
||||
QTableView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FileTableView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
int distance = (event->pos() - dragStartPos).manhattanLength();
|
||||
if (event->buttons() & Qt::LeftButton && distance >= QApplication::startDragDistance())
|
||||
{
|
||||
dragOutEvent();
|
||||
QTableView::mouseReleaseEvent(event);
|
||||
}
|
||||
else
|
||||
QTableView::mouseMoveEvent(event);
|
||||
|
||||
}
|
24
src/FileTableView.h
Normal file
24
src/FileTableView.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef FILETABLEVIEW_H
|
||||
#define FILETABLEVIEW_H
|
||||
|
||||
#include <QTableView>
|
||||
#include <QPoint>
|
||||
|
||||
class FileTableView : public QTableView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FileTableView(QWidget *parent = 0);
|
||||
|
||||
signals:
|
||||
void dragOutEvent();
|
||||
|
||||
private:
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
|
||||
private:
|
||||
QPoint dragStartPos;
|
||||
};
|
||||
|
||||
#endif // FILETABLEVIEW_H
|
22
src/LoggedProcess.cpp
Normal file
22
src/LoggedProcess.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "LoggedProcess.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
|
||||
{
|
||||
setProcessChannelMode(QProcess::MergedChannels);
|
||||
connect(this, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyReadStandardOutput()));
|
||||
}
|
||||
|
||||
void LoggedProcess::getLogAndClear(QByteArray &buffer)
|
||||
{
|
||||
QMutexLocker lck(&mutex);
|
||||
buffer = log;
|
||||
log.clear();
|
||||
}
|
||||
|
||||
void LoggedProcess::onReadyReadStandardOutput()
|
||||
{
|
||||
QMutexLocker lck(&mutex);
|
||||
log.append(readAllStandardOutput());
|
||||
}
|
||||
|
24
src/LoggedProcess.h
Normal file
24
src/LoggedProcess.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef LOGGEDPROCESS_H
|
||||
#define LOGGEDPROCESS_H
|
||||
|
||||
#include <QProcess>
|
||||
#include <QMutex>
|
||||
|
||||
class LoggedProcess : public QProcess
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LoggedProcess(QObject *parent = 0);
|
||||
void getLogAndClear(QByteArray &buffer);
|
||||
bool isLogEmpty() const { return log.isEmpty(); }
|
||||
qint64 logBytesAvailable() const { return log.size(); }
|
||||
|
||||
private slots:
|
||||
void onReadyReadStandardOutput();
|
||||
|
||||
private:
|
||||
QMutex mutex;
|
||||
QByteArray log;
|
||||
};
|
||||
|
||||
#endif // LOGGEDPROCESS_H
|
2523
src/MainWindow.cpp
Normal file
2523
src/MainWindow.cpp
Normal file
File diff suppressed because it is too large
Load Diff
270
src/MainWindow.h
Normal file
270
src/MainWindow.h
Normal file
@ -0,0 +1,270 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QStandardItemModel>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
#include <QSet>
|
||||
#include "SettingsDialog.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
|
||||
class QStringList;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// RepoFile
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
struct RepoFile
|
||||
{
|
||||
enum EntryType
|
||||
{
|
||||
TYPE_UNKNOWN = 1<<0,
|
||||
TYPE_UNCHANGED = 1<<1,
|
||||
TYPE_EDITTED = 1<<2,
|
||||
TYPE_ADDED = 1<<3,
|
||||
TYPE_DELETED = 1<<4,
|
||||
TYPE_MISSING = 1<<5,
|
||||
TYPE_RENAMED = 1<<6,
|
||||
TYPE_MODIFIED = TYPE_EDITTED|TYPE_ADDED|TYPE_DELETED|TYPE_MISSING|TYPE_RENAMED,
|
||||
TYPE_REPO = TYPE_UNCHANGED|TYPE_MODIFIED,
|
||||
TYPE_ALL = TYPE_UNKNOWN|TYPE_REPO
|
||||
};
|
||||
|
||||
RepoFile(QFileInfo &info, EntryType type, const QString &repoPath)
|
||||
{
|
||||
FileInfo = info;
|
||||
Type = type;
|
||||
FilePath = getRelativeFilename(repoPath);
|
||||
Path = FileInfo.absolutePath();
|
||||
|
||||
// Strip the workspace path from the path
|
||||
Q_ASSERT(Path.indexOf(repoPath)==0);
|
||||
Path = Path.mid(repoPath.length()+1);
|
||||
}
|
||||
|
||||
bool isType(EntryType t) const
|
||||
{
|
||||
return Type == t;
|
||||
}
|
||||
|
||||
void setType(EntryType t)
|
||||
{
|
||||
Type = t;
|
||||
}
|
||||
|
||||
EntryType getType() const
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
|
||||
QFileInfo getFileInfo() const
|
||||
{
|
||||
return FileInfo;
|
||||
}
|
||||
|
||||
bool isRepo() const
|
||||
{
|
||||
return Type == TYPE_UNCHANGED || Type == TYPE_EDITTED;
|
||||
}
|
||||
|
||||
const QString &getFilePath() const
|
||||
{
|
||||
return FilePath;
|
||||
}
|
||||
|
||||
QString getFilename() const
|
||||
{
|
||||
return FileInfo.fileName();
|
||||
}
|
||||
|
||||
const QString &getPath() const
|
||||
{
|
||||
return Path;
|
||||
}
|
||||
|
||||
QString getRelativeFilename(const QString &path)
|
||||
{
|
||||
QString abs_base_dir = QDir(path).absolutePath();
|
||||
|
||||
QString relative = FileInfo.absoluteFilePath();
|
||||
int index = relative.indexOf(abs_base_dir);
|
||||
if(index<0)
|
||||
return QString("");
|
||||
|
||||
return relative.right(relative.length() - abs_base_dir.length()-1);
|
||||
}
|
||||
|
||||
private:
|
||||
QFileInfo FileInfo;
|
||||
EntryType Type;
|
||||
QString FilePath;
|
||||
QString Path;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MainWindow
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0, QString *workspacePath = 0, bool portableMode = false);
|
||||
~MainWindow();
|
||||
bool diffFile(QString repoFile);
|
||||
|
||||
private:
|
||||
typedef QSet<QString> stringset_t;
|
||||
enum RunFlags
|
||||
{
|
||||
RUNFLAGS_NONE = 0<<0,
|
||||
RUNGLAGS_SILENT_INPUT = 1<<0,
|
||||
RUNGLAGS_SILENT_OUTPUT = 1<<1,
|
||||
RUNGLAGS_SILENT_ALL = RUNGLAGS_SILENT_INPUT | RUNGLAGS_SILENT_OUTPUT,
|
||||
RUNGLAGS_DETACHED = 1<<2
|
||||
};
|
||||
|
||||
private:
|
||||
bool refresh();
|
||||
void scanWorkspace();
|
||||
bool runFossil(const QStringList &args, QStringList *output=0, int runFlags=RUNFLAGS_NONE);
|
||||
bool runFossilRaw(const QStringList &args, QStringList *output=0, int *exitCode=0, int runFlags=RUNFLAGS_NONE);
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
const QString &getCurrentWorkspace();
|
||||
void setCurrentWorkspace(const QString &workspace);
|
||||
void log(const QString &text, bool isHTML=false);
|
||||
void setStatus(const QString &text);
|
||||
bool uiRunning() const { return fossilUI.state() == QProcess::Running; }
|
||||
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 getStashViewSelection(QStringList &stashNames, bool allIfEmpty=false);
|
||||
void getSelectionPaths(stringset_t &paths);
|
||||
void getAllFilenames(QStringList &filenames, int includeMask=RepoFile::TYPE_ALL);
|
||||
bool startUI();
|
||||
void stopUI();
|
||||
void enableActions(bool on);
|
||||
void addWorkspace(const QString &dir);
|
||||
void rebuildRecent();
|
||||
bool openWorkspace(const QString &path);
|
||||
void loadFossilSettings();
|
||||
QString getFossilPath();
|
||||
QString getFossilHttpAddress();
|
||||
bool scanDirectory(QFileInfoList &entries, const QString& dirPath, const QString &baseDir, const QString ignoreSpec);
|
||||
void updateDirView();
|
||||
void updateFileView();
|
||||
void updateStashView();
|
||||
void selectRootDir();
|
||||
|
||||
virtual QMenu *createPopupMenu();
|
||||
|
||||
enum RepoStatus
|
||||
{
|
||||
REPO_OK,
|
||||
REPO_NOT_FOUND,
|
||||
REPO_OLD_SCHEMA
|
||||
};
|
||||
|
||||
RepoStatus getRepoStatus();
|
||||
|
||||
enum ViewMode
|
||||
{
|
||||
VIEWMODE_LIST,
|
||||
VIEWMODE_TREE
|
||||
};
|
||||
|
||||
private slots:
|
||||
// Manual slots.
|
||||
// Use a different naming scheme to prevent warnings from Qt's automatic signaling
|
||||
void onOpenRecent();
|
||||
void onTreeViewSelectionChanged(const class QItemSelection &selected, const class QItemSelection &deselected);
|
||||
void onFileViewDragOut();
|
||||
|
||||
// Designer slots
|
||||
void on_actionRefresh_triggered();
|
||||
void on_actionDiff_triggered();
|
||||
void on_actionFossilUI_triggered();
|
||||
void on_actionQuit_triggered();
|
||||
void on_actionTimeline_triggered();
|
||||
void on_actionHistory_triggered();
|
||||
void on_actionClearLog_triggered();
|
||||
void on_tableView_doubleClicked(const QModelIndex &index);
|
||||
void on_treeView_doubleClicked(const QModelIndex &index);
|
||||
void on_actionOpenFile_triggered();
|
||||
void on_actionPush_triggered();
|
||||
void on_actionPull_triggered();
|
||||
void on_actionCommit_triggered();
|
||||
void on_actionAdd_triggered();
|
||||
void on_actionDelete_triggered();
|
||||
void on_actionRevert_triggered();
|
||||
void on_actionOpenContaining_triggered();
|
||||
void on_actionRename_triggered();
|
||||
void on_actionUndo_triggered();
|
||||
void on_actionAbout_triggered();
|
||||
void on_actionUpdate_triggered();
|
||||
void on_actionSettings_triggered();
|
||||
void on_actionViewUnchanged_triggered();
|
||||
void on_actionViewModified_triggered();
|
||||
void on_actionViewUnknown_triggered();
|
||||
void on_actionViewIgnored_triggered();
|
||||
void on_actionViewAsList_triggered();
|
||||
void on_actionOpenFolder_triggered();
|
||||
void on_actionRenameFolder_triggered();
|
||||
void on_actionNewRepository_triggered();
|
||||
void on_actionOpenRepository_triggered();
|
||||
void on_actionCloseRepository_triggered();
|
||||
void on_actionCloneRepository_triggered();
|
||||
void on_actionViewStash_triggered();
|
||||
void on_actionNewStash_triggered();
|
||||
void on_actionApplyStash_triggered();
|
||||
void on_actionDeleteStash_triggered();
|
||||
void on_actionDiffStash_triggered();
|
||||
void on_textBrowser_customContextMenuRequested(const QPoint &pos);
|
||||
void on_tableView_customContextMenuRequested(const QPoint &pos);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
MAX_RECENT=5
|
||||
};
|
||||
|
||||
|
||||
Ui::MainWindow *ui;
|
||||
QStandardItemModel repoFileModel;
|
||||
QStandardItemModel repoDirModel;
|
||||
QStandardItemModel repoStashModel;
|
||||
QProcess fossilUI;
|
||||
QString fossilUIPort;
|
||||
class QAction *recentWorkspaceActs[MAX_RECENT];
|
||||
class QProgressBar *progressBar;
|
||||
bool fossilAbort; // FIXME: No GUI for it yet
|
||||
|
||||
Settings settings;
|
||||
QString projectName;
|
||||
QString repositoryFile;
|
||||
QStringList workspaceHistory;
|
||||
QString currentWorkspace;
|
||||
ViewMode viewMode;
|
||||
stringset_t selectedDirs; // The directory selected in the tree
|
||||
|
||||
class QSettings *qsettings;
|
||||
|
||||
// Repository State
|
||||
typedef QList<RepoFile*> filelist_t;
|
||||
typedef QMap<QString, RepoFile*> filemap_t;
|
||||
typedef QMap<QString, QString> stashmap_t;
|
||||
filemap_t workspaceFiles;
|
||||
stringset_t pathSet;
|
||||
stashmap_t stashMap;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
106
src/SettingsDialog.cpp
Normal file
106
src/SettingsDialog.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include "SettingsDialog.h"
|
||||
#include "ui_SettingsDialog.h"
|
||||
#include <QFileDialog>
|
||||
#include "Utils.h"
|
||||
|
||||
QString SettingsDialog::SelectExe(QWidget *parent, const QString &description)
|
||||
{
|
||||
QString filter(tr("Applications"));
|
||||
#ifdef Q_WS_WIN
|
||||
filter += " (*.exe)";
|
||||
#else
|
||||
filter += " (*)";
|
||||
#endif
|
||||
QString path = QFileDialog::getOpenFileName(
|
||||
parent,
|
||||
tr("Select %1").arg(description),
|
||||
QString(),
|
||||
filter,
|
||||
&filter);
|
||||
|
||||
if(!QFile::exists(path))
|
||||
return QString();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) :
|
||||
QDialog(parent, Qt::Sheet),
|
||||
ui(new Ui::SettingsDialog),
|
||||
settings(&_settings)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->cmbDoubleClickAction->addItem(tr("Diff File"));
|
||||
ui->cmbDoubleClickAction->addItem(tr("Open File"));
|
||||
ui->cmbDoubleClickAction->addItem(tr("Open Containing Folder"));
|
||||
|
||||
// App Settings
|
||||
ui->lineFossilPath->setText(QDir::toNativeSeparators(settings->Mappings[FUEL_SETTING_FOSSIL_PATH].Value.toString()));
|
||||
ui->lineGDiffCommand->setText(QDir::toNativeSeparators(settings->Mappings[FUEL_SETTING_GDIFF_CMD].Value.toString()));
|
||||
ui->lineGMergeCommand->setText(QDir::toNativeSeparators(settings->Mappings[FUEL_SETTING_GMERGE_CMD].Value.toString()));
|
||||
ui->cmbDoubleClickAction->setCurrentIndex(settings->Mappings[FUEL_SETTING_FILE_DBLCLICK].Value.toInt());
|
||||
|
||||
// Repo Settings
|
||||
ui->lineRemoteURL->setText(settings->Mappings[FUEL_SETTING_REMOTE_URL].Value.toString());
|
||||
ui->lineIgnore->setText(settings->Mappings[FUEL_SETTING_IGNORE_GLOB].Value.toString());
|
||||
ui->lineIgnoreCRNL->setText(settings->Mappings[FUEL_SETTING_CRNL_GLOB].Value.toString());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
SettingsDialog::~SettingsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SettingsDialog::run(QWidget *parent, Settings &settings)
|
||||
{
|
||||
SettingsDialog dlg(parent, settings);
|
||||
return dlg.exec() == QDialog::Accepted;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::on_buttonBox_accepted()
|
||||
{
|
||||
settings->Mappings[FUEL_SETTING_FOSSIL_PATH].Value = QDir::fromNativeSeparators(ui->lineFossilPath->text());
|
||||
settings->Mappings[FUEL_SETTING_GDIFF_CMD].Value = QDir::fromNativeSeparators(ui->lineGDiffCommand->text());
|
||||
settings->Mappings[FUEL_SETTING_GMERGE_CMD].Value = QDir::fromNativeSeparators(ui->lineGMergeCommand->text());
|
||||
Q_ASSERT(ui->cmbDoubleClickAction->currentIndex()>=FILE_DLBCLICK_ACTION_DIFF && ui->cmbDoubleClickAction->currentIndex()<FILE_DLBCLICK_ACTION_MAX);
|
||||
settings->Mappings[FUEL_SETTING_FILE_DBLCLICK].Value = ui->cmbDoubleClickAction->currentIndex();
|
||||
|
||||
settings->Mappings[FUEL_SETTING_REMOTE_URL].Value = ui->lineRemoteURL->text();
|
||||
settings->Mappings[FUEL_SETTING_IGNORE_GLOB].Value = ui->lineIgnore->text();
|
||||
settings->Mappings[FUEL_SETTING_CRNL_GLOB].Value = ui->lineIgnoreCRNL->text();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::on_btnSelectFossil_clicked()
|
||||
{
|
||||
QString path = SelectExe(this, tr("Fossil executable"));
|
||||
if(!path.isEmpty())
|
||||
ui->lineFossilPath->setText(QDir::toNativeSeparators(path));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::on_btnSelectFossilGDiff_clicked()
|
||||
{
|
||||
QString path = SelectExe(this, tr("Graphical Diff application"));
|
||||
if(!path.isEmpty())
|
||||
ui->lineGDiffCommand->setText(QDir::toNativeSeparators(path));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::on_btnSelectGMerge_clicked()
|
||||
{
|
||||
QString path = SelectExe(this, tr("Graphical Merge application"));
|
||||
if(!path.isEmpty())
|
||||
ui->lineGMergeCommand->setText(QDir::toNativeSeparators(path));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::on_btnClearMessageHistory_clicked()
|
||||
{
|
||||
if(DialogQuery(this, tr("Clear Commit Message History"), tr("Are you sure want to clear the commit message history?"))==QMessageBox::Yes)
|
||||
settings->Mappings[FUEL_SETTING_COMMIT_MSG].Value = QStringList();
|
||||
}
|
89
src/SettingsDialog.h
Normal file
89
src/SettingsDialog.h
Normal file
@ -0,0 +1,89 @@
|
||||
#ifndef SETTINGSDIALOG_H
|
||||
#define SETTINGSDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
|
||||
namespace Ui {
|
||||
class SettingsDialog;
|
||||
}
|
||||
|
||||
#define FUEL_SETTING_FOSSIL_PATH "FossilPath"
|
||||
#define FUEL_SETTING_COMMIT_MSG "CommitMsgHistory"
|
||||
#define FUEL_SETTING_FILE_DBLCLICK "FileDblClickAction"
|
||||
#define FUEL_SETTING_GDIFF_CMD "gdiff-command"
|
||||
#define FUEL_SETTING_GMERGE_CMD "gmerge-command"
|
||||
#define FUEL_SETTING_IGNORE_GLOB "ignore-glob"
|
||||
#define FUEL_SETTING_CRNL_GLOB "crnl-glob"
|
||||
#define FUEL_SETTING_REMOTE_URL "remote-url"
|
||||
|
||||
enum FileDblClickAction
|
||||
{
|
||||
FILE_DLBCLICK_ACTION_DIFF,
|
||||
FILE_DLBCLICK_ACTION_OPEN,
|
||||
FILE_DLBCLICK_ACTION_OPENCONTAINING,
|
||||
FILE_DLBCLICK_ACTION_MAX
|
||||
};
|
||||
|
||||
struct Settings
|
||||
{
|
||||
struct Setting
|
||||
{
|
||||
enum SettingType
|
||||
{
|
||||
TYPE_INTERNAL,
|
||||
TYPE_FOSSIL_GLOBAL,
|
||||
TYPE_FOSSIL_LOCAL,
|
||||
TYPE_FOSSIL_COMMAND
|
||||
};
|
||||
|
||||
Setting(QVariant value=QVariant(), SettingType type=TYPE_INTERNAL) : Value(value), Type(type)
|
||||
{}
|
||||
QVariant Value;
|
||||
SettingType Type;
|
||||
};
|
||||
|
||||
typedef QMap<QString, Setting> mappings_t;
|
||||
mappings_t Mappings;
|
||||
|
||||
Settings()
|
||||
{
|
||||
Mappings[FUEL_SETTING_FOSSIL_PATH] = Setting();
|
||||
Mappings[FUEL_SETTING_COMMIT_MSG] = Setting();
|
||||
Mappings[FUEL_SETTING_FILE_DBLCLICK] = Setting(0); // Maps to FileDblClickAction
|
||||
Mappings[FUEL_SETTING_GDIFF_CMD] = Setting("", Setting::TYPE_FOSSIL_GLOBAL);
|
||||
Mappings[FUEL_SETTING_GMERGE_CMD] = Setting("", Setting::TYPE_FOSSIL_GLOBAL);
|
||||
Mappings[FUEL_SETTING_IGNORE_GLOB] = Setting("", Setting::TYPE_FOSSIL_LOCAL);
|
||||
Mappings[FUEL_SETTING_CRNL_GLOB] = Setting("", Setting::TYPE_FOSSIL_LOCAL);
|
||||
Mappings[FUEL_SETTING_REMOTE_URL] = Setting("off", Setting::TYPE_FOSSIL_COMMAND);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SettingsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SettingsDialog(QWidget *parent, Settings &_settings);
|
||||
~SettingsDialog();
|
||||
|
||||
static bool run(QWidget *parent, Settings &_settings);
|
||||
|
||||
|
||||
private slots:
|
||||
void on_btnSelectFossil_clicked();
|
||||
void on_buttonBox_accepted();
|
||||
void on_btnSelectFossilGDiff_clicked();
|
||||
void on_btnSelectGMerge_clicked();
|
||||
void on_btnClearMessageHistory_clicked();
|
||||
|
||||
private:
|
||||
static QString SelectExe(QWidget *parent, const QString &description);
|
||||
|
||||
Ui::SettingsDialog *ui;
|
||||
Settings *settings;
|
||||
};
|
||||
|
||||
#endif // SETTINGSDIALOG_H
|
293
src/Utils.cpp
Normal file
293
src/Utils.cpp
Normal file
@ -0,0 +1,293 @@
|
||||
#include "Utils.h"
|
||||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons)
|
||||
{
|
||||
QMessageBox mb(QMessageBox::Question, title, query, buttons, parent, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::Sheet );
|
||||
mb.setDefaultButton(QMessageBox::No);
|
||||
mb.setWindowModality(Qt::WindowModal);
|
||||
mb.setModal(true);
|
||||
mb.exec();
|
||||
QMessageBox::StandardButton res = mb.standardButton(mb.clickedButton());
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#if 0 // Unused
|
||||
#include <QInputDialog>
|
||||
|
||||
static bool DialogQueryText(QWidget *parent, const QString &title, const QString &query, QString &text, bool isPassword=false)
|
||||
{
|
||||
QInputDialog dlg(parent, Qt::Sheet);
|
||||
dlg.setWindowTitle(title);
|
||||
dlg.setInputMode(QInputDialog::TextInput);
|
||||
dlg.setWindowModality(Qt::WindowModal);
|
||||
dlg.setModal(true);
|
||||
dlg.setLabelText(query);
|
||||
dlg.setTextValue(text);
|
||||
if(isPassword)
|
||||
dlg.setTextEchoMode(QLineEdit::Password);
|
||||
|
||||
if(dlg.exec() == QDialog::Rejected)
|
||||
return false;
|
||||
|
||||
text = dlg.textValue();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
// Explorer File Context Menu support. Based on http://www.microsoft.com/msj/0497/wicked/wicked0497.aspx
|
||||
#include <shlobj.h>
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// FUNCTION: DoExplorerMenu
|
||||
//
|
||||
// DESCRIPTION: Given a path name to a file or folder object, displays
|
||||
// the shell's context menu for that object and executes
|
||||
// the menu command (if any) selected by the user.
|
||||
//
|
||||
// INPUT: hwnd = Handle of the window in which the menu will be
|
||||
// displayed.
|
||||
//
|
||||
// pszPath = Pointer to an ANSI or Unicode string
|
||||
// specifying the path to the object.
|
||||
//
|
||||
// point = x and y coordinates of the point where the
|
||||
// menu's upper left corner should be located, in
|
||||
// client coordinates relative to hwnd.
|
||||
//
|
||||
// RETURNS: TRUE if successful, FALSE if not.
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint)
|
||||
{
|
||||
struct Util
|
||||
{
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// FUNCTION: GetNextItem
|
||||
// DESCRIPTION: Finds the next item in an item ID list.
|
||||
// INPUT: pidl = Pointer to an item ID list.
|
||||
// RETURNS: Pointer to the next item.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
static LPITEMIDLIST GetNextItem (LPITEMIDLIST pidl)
|
||||
{
|
||||
USHORT nLen;
|
||||
|
||||
if ((nLen = pidl->mkid.cb) == 0)
|
||||
return NULL;
|
||||
|
||||
return (LPITEMIDLIST) (((LPBYTE) pidl) + nLen);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// FUNCTION: GetItemCount
|
||||
// DESCRIPTION: Computes the number of item IDs in an item ID list.
|
||||
// INPUT: pidl = Pointer to an item ID list.
|
||||
// RETURNS: Number of item IDs in the list.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
static UINT GetItemCount (LPITEMIDLIST pidl)
|
||||
{
|
||||
USHORT nLen;
|
||||
UINT nCount;
|
||||
|
||||
nCount = 0;
|
||||
while ((nLen = pidl->mkid.cb) != 0) {
|
||||
pidl = GetNextItem (pidl);
|
||||
nCount++;
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// FUNCTION: DuplicateItem
|
||||
// DESCRIPTION: Makes a copy of the next item in an item ID list.
|
||||
// INPUT: pMalloc = Pointer to an IMalloc interface.
|
||||
// pidl = Pointer to an item ID list.
|
||||
// RETURNS: Pointer to an ITEMIDLIST containing the copied item ID.
|
||||
// NOTES: It is the caller's responsibility to free the memory
|
||||
// allocated by this function when the item ID is no longer
|
||||
// needed. Example:
|
||||
// pidlItem = DuplicateItem (pMalloc, pidl);
|
||||
// .
|
||||
// .
|
||||
// .
|
||||
// pMalloc->lpVtbl->Free (pMalloc, pidlItem);
|
||||
// Failure to free the ITEMIDLIST will result in memory
|
||||
// leaks.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
static LPITEMIDLIST DuplicateItem (LPMALLOC pMalloc, LPITEMIDLIST pidl)
|
||||
{
|
||||
USHORT nLen;
|
||||
LPITEMIDLIST pidlNew;
|
||||
|
||||
nLen = pidl->mkid.cb;
|
||||
if (nLen == 0)
|
||||
return NULL;
|
||||
|
||||
pidlNew = (LPITEMIDLIST) pMalloc->Alloc (
|
||||
nLen + sizeof (USHORT));
|
||||
if (pidlNew == NULL)
|
||||
return NULL;
|
||||
|
||||
CopyMemory (pidlNew, pidl, nLen);
|
||||
*((USHORT*) (((LPBYTE) pidlNew) + nLen)) = 0;
|
||||
|
||||
return pidlNew;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
LPITEMIDLIST pidlMain, pidlItem, pidlNextItem, *ppidl;
|
||||
UINT nCount;
|
||||
POINT point;
|
||||
point.x = qpoint.x();
|
||||
point.y = qpoint.y();
|
||||
|
||||
WCHAR wchPath[MAX_PATH];
|
||||
memset(wchPath, 0, sizeof(wchPath));
|
||||
Q_ASSERT(path.length()<MAX_PATH);
|
||||
path.toWCharArray(wchPath);
|
||||
|
||||
//
|
||||
// Get pointers to the shell's IMalloc interface and the desktop's
|
||||
// IShellFolder interface.
|
||||
//
|
||||
bool bResult = false;
|
||||
|
||||
LPMALLOC pMalloc;
|
||||
if (!SUCCEEDED (SHGetMalloc (&pMalloc)))
|
||||
return bResult;
|
||||
|
||||
LPSHELLFOLDER psfFolder;
|
||||
if (!SUCCEEDED (SHGetDesktopFolder (&psfFolder))) {
|
||||
pMalloc->Release();
|
||||
return bResult;
|
||||
}
|
||||
|
||||
//
|
||||
// Convert the path name into a pointer to an item ID list (pidl).
|
||||
//
|
||||
ULONG ulCount, ulAttr;
|
||||
if (SUCCEEDED (psfFolder->ParseDisplayName (hwnd,
|
||||
NULL, wchPath, &ulCount, &pidlMain, &ulAttr)) && (pidlMain != NULL)) {
|
||||
|
||||
if ( (nCount = Util::GetItemCount (pidlMain))>0) { // nCount must be > 0
|
||||
//
|
||||
// Initialize psfFolder with a pointer to the IShellFolder
|
||||
// interface of the folder that contains the item whose context
|
||||
// menu we're after, and initialize pidlItem with a pointer to
|
||||
// the item's item ID. If nCount > 1, this requires us to walk
|
||||
// the list of item IDs stored in pidlMain and bind to each
|
||||
// subfolder referenced in the list.
|
||||
//
|
||||
pidlItem = pidlMain;
|
||||
|
||||
while (--nCount) {
|
||||
//
|
||||
// Create a 1-item item ID list for the next item in pidlMain.
|
||||
//
|
||||
pidlNextItem = Util::DuplicateItem (pMalloc, pidlItem);
|
||||
if (pidlNextItem == NULL) {
|
||||
pMalloc->Free(pidlMain);
|
||||
psfFolder->Release ();
|
||||
pMalloc->Release ();
|
||||
return bResult;
|
||||
}
|
||||
|
||||
//
|
||||
// Bind to the folder specified in the new item ID list.
|
||||
//
|
||||
LPSHELLFOLDER psfNextFolder;
|
||||
if (!SUCCEEDED (psfFolder->BindToObject (
|
||||
pidlNextItem, NULL, IID_IShellFolder, (void**)&psfNextFolder))) {
|
||||
pMalloc->Free (pidlNextItem);
|
||||
pMalloc->Free (pidlMain);
|
||||
psfFolder->Release ();
|
||||
pMalloc->Release ();
|
||||
return bResult;
|
||||
}
|
||||
|
||||
//
|
||||
// Release the IShellFolder pointer to the parent folder
|
||||
// and set psfFolder equal to the IShellFolder pointer for
|
||||
// the current folder.
|
||||
//
|
||||
psfFolder->Release ();
|
||||
psfFolder = psfNextFolder;
|
||||
|
||||
//
|
||||
// Release the storage for the 1-item item ID list we created
|
||||
// just a moment ago and initialize pidlItem so that it points
|
||||
// to the next item in pidlMain.
|
||||
//
|
||||
pMalloc->Free(pidlNextItem);
|
||||
pidlItem = Util::GetNextItem (pidlItem);
|
||||
}
|
||||
|
||||
//
|
||||
// Get a pointer to the item's IContextMenu interface and call
|
||||
// IContextMenu::QueryContextMenu to initialize a context menu.
|
||||
//
|
||||
ppidl = &pidlItem;
|
||||
LPCONTEXTMENU pContextMenu;
|
||||
if (SUCCEEDED (psfFolder->GetUIObjectOf (
|
||||
hwnd, 1, (const ITEMIDLIST **)ppidl, IID_IContextMenu, NULL, (void**)&pContextMenu))) {
|
||||
|
||||
HMENU hMenu = CreatePopupMenu ();
|
||||
if (SUCCEEDED (pContextMenu->QueryContextMenu (
|
||||
hMenu, 0, 1, 0x7FFF, CMF_EXPLORE))) {
|
||||
|
||||
|
||||
//
|
||||
// Display the context menu.
|
||||
//
|
||||
UINT nCmd = TrackPopupMenu (hMenu, TPM_LEFTALIGN |
|
||||
TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD,
|
||||
point.x, point.y, 0, hwnd, NULL);
|
||||
|
||||
|
||||
//
|
||||
// If a command was selected from the menu, execute it.
|
||||
//
|
||||
if (nCmd) {
|
||||
CMINVOKECOMMANDINFO ici;
|
||||
memset(&ici, 0, sizeof(ici) );
|
||||
ici.cbSize = sizeof (CMINVOKECOMMANDINFO);
|
||||
ici.fMask = 0;
|
||||
ici.hwnd = hwnd;
|
||||
ici.lpVerb = MAKEINTRESOURCEA (nCmd - 1);
|
||||
ici.lpParameters = NULL;
|
||||
ici.lpDirectory = NULL;
|
||||
ici.nShow = SW_SHOWNORMAL;
|
||||
ici.dwHotKey = 0;
|
||||
ici.hIcon = NULL;
|
||||
|
||||
if (SUCCEEDED (
|
||||
pContextMenu->InvokeCommand (
|
||||
(CMINVOKECOMMANDINFO*)&ici)))
|
||||
bResult = true;
|
||||
}
|
||||
}
|
||||
DestroyMenu (hMenu);
|
||||
pContextMenu->Release ();
|
||||
}
|
||||
}
|
||||
pMalloc->Free (pidlMain);
|
||||
}
|
||||
|
||||
//
|
||||
// Clean up and return.
|
||||
//
|
||||
psfFolder->Release ();
|
||||
pMalloc->Release ();
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
14
src/Utils.h
Normal file
14
src/Utils.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <QString>
|
||||
#include <QMessageBox>
|
||||
|
||||
QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons = QMessageBox::Yes|QMessageBox::No);
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint);
|
||||
#endif
|
||||
|
||||
|
||||
#endif // UTILS_H
|
41
src/main.cpp
Normal file
41
src/main.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include <QtGui/QApplication>
|
||||
#include "MainWindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
app.setApplicationName("Fuel");
|
||||
app.setApplicationVersion("0.9.6");
|
||||
app.setOrganizationDomain("fuel-scm.org");
|
||||
app.setOrganizationName("Fuel-SCM");
|
||||
|
||||
#ifdef Q_WS_MACX
|
||||
// Native OSX applications don't use menu icons
|
||||
app.setAttribute(Qt::AA_DontShowIconsInMenus);
|
||||
#endif
|
||||
{
|
||||
bool portable = false;
|
||||
QString workspace;
|
||||
|
||||
Q_ASSERT(app.arguments().size()>0);
|
||||
for(int i=1; i<app.arguments().size(); ++i)
|
||||
{
|
||||
QString arg = app.arguments()[i];
|
||||
// Parse options
|
||||
if(arg.indexOf("--")!=-1)
|
||||
{
|
||||
if(arg.indexOf("portable")!=-1)
|
||||
portable = true;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
workspace = arg;
|
||||
}
|
||||
|
||||
MainWindow mainwin(0,
|
||||
workspace.isEmpty() ? 0 : &workspace,
|
||||
portable);
|
||||
mainwin.show();
|
||||
return app.exec();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user