Major reorganization of the project files

FossilOrigin-Name: 821239471319fdd5d530f54b7f67f473dcf7bd8e
This commit is contained in:
kostas
2012-05-13 03:40:24 +00:00
parent d8c9ba062b
commit d1f28461ee
183 changed files with 235 additions and 235 deletions

92
src/CloneDialog.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

270
src/MainWindow.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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();
}
}