#ifndef NALL_QT_FILEDIALOG_HPP #define NALL_QT_FILEDIALOG_HPP #include #include #include namespace nall { class FileDialog; class NewFolderDialog : public Window { Q_OBJECT public: void show(); NewFolderDialog(FileDialog*); protected slots: void createFolderAction(); protected: FileDialog *parent; QVBoxLayout *layout; QLineEdit *folderNameEdit; QHBoxLayout *controlLayout; QPushButton *okButton; QPushButton *cancelButton; }; class FileView : public QListView { Q_OBJECT protected: void keyPressEvent(QKeyEvent*); signals: void changed(const QModelIndex&); void browseUp(); protected slots: void currentChanged(const QModelIndex&, const QModelIndex&); }; class FileDialog : public Window { Q_OBJECT public: void showLoad(); void showSave(); void showFolder(); void setPath(string path); void setNameFilters(const string &filters); FileDialog(); signals: void changed(const string&); void activated(const string&); void accepted(const string&); void rejected(); protected slots: void fileViewChange(const QModelIndex&); void fileViewActivate(const QModelIndex&); void pathBoxChanged(); void filterBoxChanged(); void createNewFolder(); void browseUp(); void acceptAction(); void rejectAction(); protected: NewFolderDialog *newFolderDialog; QVBoxLayout *layout; QHBoxLayout *navigationLayout; QComboBox *pathBox; QPushButton *newFolderButton; QPushButton *upFolderButton; QHBoxLayout *browseLayout; QFileSystemModel *fileSystemModel; FileView *fileView; QGroupBox *previewFrame; QLineEdit *fileNameEdit; QHBoxLayout *controlLayout; QComboBox *filterBox; QPushButton *optionsButton; QPushButton *acceptButton; QPushButton *rejectButton; bool lock; void createFolderAction(const string &name); void closeEvent(QCloseEvent*); friend class NewFolderDialog; }; inline void NewFolderDialog::show() { folderNameEdit->setText(""); Window::show(); folderNameEdit->setFocus(); } inline void NewFolderDialog::createFolderAction() { string name = folderNameEdit->text().toUtf8().constData(); if(name == "") { folderNameEdit->setFocus(); } else { parent->createFolderAction(name); close(); } } inline NewFolderDialog::NewFolderDialog(FileDialog *fileDialog) : parent(fileDialog) { setMinimumWidth(240); setWindowTitle("Create New Folder"); layout = new QVBoxLayout; layout->setAlignment(Qt::AlignTop); layout->setMargin(5); layout->setSpacing(5); setLayout(layout); folderNameEdit = new QLineEdit; layout->addWidget(folderNameEdit); controlLayout = new QHBoxLayout; controlLayout->setAlignment(Qt::AlignRight); layout->addLayout(controlLayout); okButton = new QPushButton("Ok"); controlLayout->addWidget(okButton); cancelButton = new QPushButton("Cancel"); controlLayout->addWidget(cancelButton); connect(folderNameEdit, SIGNAL(returnPressed()), this, SLOT(createFolderAction())); connect(okButton, SIGNAL(released()), this, SLOT(createFolderAction())); connect(cancelButton, SIGNAL(released()), this, SLOT(close())); } inline void FileView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { QAbstractItemView::currentChanged(current, previous); emit changed(current); } inline void FileView::keyPressEvent(QKeyEvent *event) { //enhance consistency: force OS X to act like Windows and Linux; enter = activate item if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { emit activated(currentIndex()); return; } //simulate popular file manager behavior; backspace = go up one directory if(event->key() == Qt::Key_Backspace) { emit browseUp(); return; } //fallback: unrecognized keypresses get handled by the widget itself QListView::keyPressEvent(event); } inline void FileDialog::showLoad() { acceptButton->setText("Load"); fileNameEdit->hide(); filterBox->show(); show(); } inline void FileDialog::showSave() { acceptButton->setText("Save"); fileNameEdit->show(); filterBox->show(); show(); } inline void FileDialog::showFolder() { acceptButton->setText("Choose"); fileNameEdit->hide(); filterBox->hide(); setNameFilters("Folders ()"); show(); } inline void FileDialog::fileViewChange(const QModelIndex &index) { string path = fileSystemModel->filePath(index).toUtf8().constData(); if(path == fileSystemModel->rootPath().toUtf8().constData()) path = ""; fileNameEdit->setText(notdir(path)); emit changed(path); } inline void FileDialog::fileViewActivate(const QModelIndex &index) { string path = fileSystemModel->filePath(index).toUtf8().constData(); if(fileSystemModel->isDir(index)) { emit activated(path); setPath(path); } else { emit activated(path); close(); } } inline void FileDialog::pathBoxChanged() { if(lock) return; setPath(pathBox->currentText().toUtf8().constData()); } inline void FileDialog::filterBoxChanged() { if(lock) return; string filters = filterBox->currentText().toUtf8().constData(); if(filters.length() == 0) { fileSystemModel->setNameFilters(QStringList() << "*"); } else { filters = substr(filters, strpos(filters, "(")()); ltrim(filters, "("); rtrim(filters, ")"); lstring part; part.split(" ", filters); QStringList list; for(unsigned i = 0; i < part.size(); i++) list << part[i]; fileSystemModel->setNameFilters(list); } } inline void FileDialog::createNewFolder() { newFolderDialog->show(); } inline void FileDialog::browseUp() { if(pathBox->count() > 1) pathBox->setCurrentIndex(1); } inline void FileDialog::setPath(string path) { lock = true; newFolderDialog->close(); if(QDir(path).exists()) { newFolderButton->setEnabled(true); } else { newFolderButton->setEnabled(false); path = ""; } fileSystemModel->setRootPath(path); fileView->setRootIndex(fileSystemModel->index(path)); fileView->setCurrentIndex(fileView->rootIndex()); fileView->setFocus(); pathBox->clear(); if(path.length() > 0) { QDir directory(path); while(true) { pathBox->addItem(directory.absolutePath()); if(directory.isRoot()) break; directory.cdUp(); } } pathBox->addItem(""); fileNameEdit->setText(""); lock = false; } inline void FileDialog::setNameFilters(const string &filters) { lock = true; lstring list; list.split("\n", filters); filterBox->clear(); for(unsigned i = 0; i < list.size(); i++) { filterBox->addItem(list[i]); } lock = false; filterBoxChanged(); } inline void FileDialog::acceptAction() { string path = fileSystemModel->rootPath().toUtf8().constData(); path << "/" << notdir(fileNameEdit->text().toUtf8().constData()); rtrim(path, "/"); if(QDir(path).exists()) { emit accepted(path); setPath(path); } else { emit accepted(path); close(); } } inline void FileDialog::rejectAction() { emit rejected(); close(); } inline void FileDialog::createFolderAction(const string &name) { string path = fileSystemModel->rootPath().toUtf8().constData(); path << "/" << notdir(name); mkdir(path, 0755); } inline void FileDialog::closeEvent(QCloseEvent *event) { newFolderDialog->close(); Window::closeEvent(event); } inline FileDialog::FileDialog() { newFolderDialog = new NewFolderDialog(this); resize(640, 360); layout = new QVBoxLayout; layout->setMargin(5); layout->setSpacing(5); setLayout(layout); navigationLayout = new QHBoxLayout; layout->addLayout(navigationLayout); pathBox = new QComboBox; pathBox->setEditable(true); pathBox->setMinimumContentsLength(16); pathBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength); pathBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); navigationLayout->addWidget(pathBox); newFolderButton = new QPushButton; newFolderButton->setIconSize(QSize(16, 16)); newFolderButton->setIcon(QIcon(":/16x16/folder-new.png")); navigationLayout->addWidget(newFolderButton); upFolderButton = new QPushButton; upFolderButton->setIconSize(QSize(16, 16)); upFolderButton->setIcon(QIcon(":/16x16/go-up.png")); navigationLayout->addWidget(upFolderButton); browseLayout = new QHBoxLayout; layout->addLayout(browseLayout); fileSystemModel = new QFileSystemModel; fileSystemModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); fileSystemModel->setNameFilterDisables(false); fileView = new FileView; fileView->setMinimumWidth(320); fileView->setModel(fileSystemModel); fileView->setIconSize(QSize(16, 16)); browseLayout->addWidget(fileView); previewFrame = new QGroupBox; previewFrame->hide(); browseLayout->addWidget(previewFrame); fileNameEdit = new QLineEdit; layout->addWidget(fileNameEdit); controlLayout = new QHBoxLayout; controlLayout->setAlignment(Qt::AlignRight); layout->addLayout(controlLayout); filterBox = new QComboBox; filterBox->setMinimumContentsLength(16); filterBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength); filterBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); controlLayout->addWidget(filterBox); optionsButton = new QPushButton("Options"); optionsButton->hide(); controlLayout->addWidget(optionsButton); acceptButton = new QPushButton("Ok"); controlLayout->addWidget(acceptButton); rejectButton = new QPushButton("Cancel"); controlLayout->addWidget(rejectButton); lock = false; connect(pathBox, SIGNAL(currentIndexChanged(int)), this, SLOT(pathBoxChanged())); connect(newFolderButton, SIGNAL(released()), this, SLOT(createNewFolder())); connect(upFolderButton, SIGNAL(released()), this, SLOT(browseUp())); connect(fileView, SIGNAL(changed(const QModelIndex&)), this, SLOT(fileViewChange(const QModelIndex&))); connect(fileView, SIGNAL(activated(const QModelIndex&)), this, SLOT(fileViewActivate(const QModelIndex&))); connect(fileView, SIGNAL(browseUp()), this, SLOT(browseUp())); connect(fileNameEdit, SIGNAL(returnPressed()), this, SLOT(acceptAction())); connect(filterBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterBoxChanged())); connect(acceptButton, SIGNAL(released()), this, SLOT(acceptAction())); connect(rejectButton, SIGNAL(released()), this, SLOT(rejectAction())); } } #endif