Add possibility to open multiple files at once (fix #1163)

This commit is contained in:
David Capello 2017-04-08 00:06:25 -03:00
parent eee87ed1ec
commit 1350d6d7f7
19 changed files with 411 additions and 207 deletions

View File

@ -448,12 +448,15 @@ private:
void onImageFilename() {
std::string exts = get_writable_extensions();
std::string newFilename = app::show_file_selector(
"Save Sprite Sheet", m_filename, exts, FileSelectorType::Save);
if (newFilename.empty())
FileSelectorFiles newFilename;
if (!app::show_file_selector(
"Save Sprite Sheet", m_filename, exts,
FileSelectorType::Save, newFilename))
return;
m_filename = newFilename;
ASSERT(!newFilename.empty());
m_filename = newFilename.front();
m_filenameAskOverwrite = false; // Already asked in file selector
onFileNamesChange();
}
@ -468,12 +471,15 @@ private:
void onDataFilename() {
// TODO hardcoded "json" extension
std::string newFilename = app::show_file_selector(
"Save JSON Data", m_dataFilename, "json", FileSelectorType::Save);
if (newFilename.empty())
FileSelectorFiles newFilename;
if (!app::show_file_selector(
"Save JSON Data", m_dataFilename, "json",
FileSelectorType::Save, newFilename))
return;
m_dataFilename = newFilename;
ASSERT(!newFilename.empty());
m_dataFilename = newFilename.front();
m_dataFilenameAskOverwrite = false; // Already asked in file selector
onFileNamesChange();
}

View File

@ -556,24 +556,34 @@ private:
}
void onImport() {
std::string filename = app::show_file_selector("Import Keyboard Shortcuts", "",
KEYBOARD_FILENAME_EXTENSION, FileSelectorType::Open);
if (filename.empty())
FileSelectorFiles filename;
if (!app::show_file_selector(
"Import Keyboard Shortcuts", "",
KEYBOARD_FILENAME_EXTENSION,
FileSelectorType::Open, filename))
return;
app::KeyboardShortcuts::instance()->importFile(filename.c_str(), KeySource::UserDefined);
ASSERT(!filename.empty());
app::KeyboardShortcuts::instance()->importFile(
filename.front(), KeySource::UserDefined);
fillAllLists();
layout();
}
void onExport() {
std::string filename = app::show_file_selector(
FileSelectorFiles filename;
if (!app::show_file_selector(
"Export Keyboard Shortcuts", "",
KEYBOARD_FILENAME_EXTENSION, FileSelectorType::Save);
if (filename.empty())
KEYBOARD_FILENAME_EXTENSION,
FileSelectorType::Save, filename))
return;
app::KeyboardShortcuts::instance()->exportFile(filename.c_str());
ASSERT(!filename.empty());
app::KeyboardShortcuts::instance()->exportFile(filename.front());
}
void onReset() {

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -57,17 +57,14 @@ void LoadMaskCommand::onExecute(Context* context)
{
const ContextReader reader(context);
std::string filename = m_filename;
if (context->isUIAvailable()) {
filename = app::show_file_selector(
"Load .msk File", filename, "msk",
FileSelectorType::Open);
if (filename.empty())
FileSelectorFiles selectedFilename;
if (!app::show_file_selector(
"Load .msk File", m_filename, "msk",
FileSelectorType::Open, selectedFilename))
return;
m_filename = filename;
m_filename = selectedFilename.front();
}
base::UniquePtr<Mask> mask(load_msk_file(m_filename.c_str()));

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -65,8 +65,12 @@ void LoadPaletteCommand::onExecute(Context* context)
}
else {
std::string exts = get_readable_palette_extensions();
filename = app::show_file_selector("Load Palette", "", exts,
FileSelectorType::Open);
FileSelectorFiles filenames;
if (app::show_file_selector("Load Palette", "", exts,
FileSelectorType::Open, filenames)) {
filename = filenames.front();
}
}
// Do nothing

View File

@ -106,6 +106,8 @@ void OpenFileCommand::onExecute(Context* context)
m_usedFiles.clear();
FileSelectorFiles filenames;
// interactive
if (context->isUIAvailable() && m_filename.empty()) {
std::string exts = get_readable_extensions();
@ -115,13 +117,18 @@ void OpenFileCommand::onExecute(Context* context)
if (!m_folder.empty() && !base::is_path_separator(m_folder[m_folder.size()-1]))
m_folder.push_back(base::path_separator);
m_filename = app::show_file_selector("Open", m_folder, exts,
FileSelectorType::Open);
if (!app::show_file_selector("Open", m_folder, exts,
FileSelectorType::OpenMultiple,
filenames)) {
// The user cancelled the operation through UI
return;
}
}
else if (!m_filename.empty()) {
filenames.push_back(m_filename);
}
// The user cancelled the operation through UI or isn't a filename
// specified in params.
if (m_filename.empty())
if (filenames.empty())
return;
int flags =
@ -143,9 +150,10 @@ void OpenFileCommand::onExecute(Context* context)
if (m_oneFrame)
flags |= FILE_LOAD_ONE_FRAME;
for (const auto& filename : filenames) {
base::UniquePtr<FileOp> fop(
FileOp::createLoadDocumentOperation(
context, m_filename, flags));
context, filename, flags));
bool unrecent = false;
// Do nothing (the user cancelled or something like that)
@ -200,6 +208,7 @@ void OpenFileCommand::onExecute(Context* context)
App::instance()->recentFiles()->removeRecentFile(m_filename.c_str());
}
}
}
Command* CommandFactory::createOpenFileCommand()
{

View File

@ -90,16 +90,16 @@ private:
}
void onSelectFontFile() {
std::string face = show_file_selector(
FileSelectorFiles face;
if (!show_file_selector(
"Select a TrueType Font",
m_face,
"ttf,ttc,otf,dfont",
FileSelectorType::Open,
nullptr);
FileSelectorType::Open, face))
return;
if (!face.empty()) {
setFontFace(face);
}
ASSERT(!face.empty());
setFontFace(face.front());
}
void setFontFace(const std::string& face) {

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -192,15 +192,14 @@ bool SaveFileBaseCommand::saveAsDialog(Context* context,
std::string exts = get_writable_extensions();
filename = document->filename();
std::string newfilename = app::show_file_selector(
FileSelectorFiles newfilename;
if (!app::show_file_selector(
dlgTitle, filename, exts,
FileSelectorType::Save,
delegate);
if (newfilename.empty())
FileSelectorType::Save, newfilename,
delegate))
return false;
filename = newfilename;
filename = newfilename.front();
if (delegate &&
delegate->hasResizeCombobox()) {
xscale = yscale = delegate->getResizeScale();

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -45,13 +45,15 @@ void SaveMaskCommand::onExecute(Context* context)
{
const ContextReader reader(context);
const Document* document(reader.document());
std::string filename = "default.msk";
filename = app::show_file_selector(
"Save .msk File", filename, "msk", FileSelectorType::Save);
if (filename.empty())
FileSelectorFiles selFilename;
if (!app::show_file_selector(
"Save .msk File", "default.msk", "msk",
FileSelectorType::Save, selFilename))
return;
std::string filename = selFilename.front();
if (save_msk_file(document->mask(), filename.c_str()) != 0)
ui::Alert::show("Error<<Error saving .msk file<<%s||&Close", filename.c_str());
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -58,10 +58,13 @@ void SavePaletteCommand::onExecute(Context* context)
}
else {
std::string exts = get_writable_palette_extensions();
filename = app::show_file_selector("Save Palette", "", exts,
FileSelectorType::Save);
if (filename.empty())
FileSelectorFiles selFilename;
if (!app::show_file_selector("Save Palette", "", exts,
FileSelectorType::Save,
selFilename))
return;
filename = selFilename.front();
}
if (!save_palette(filename.c_str(), palette, 16)) // TODO 16 should be configurable

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -20,11 +20,12 @@
namespace app {
std::string show_file_selector(
bool show_file_selector(
const std::string& title,
const std::string& initialPath,
const std::string& showExtensions,
FileSelectorType type,
FileSelectorFiles& output,
FileSelectorDelegate* delegate)
{
if (Preferences::instance().experimental.useNativeFileDialog() &&
@ -33,31 +34,40 @@ std::string show_file_selector(
she::instance()->nativeDialogs()->createFileDialog();
if (dlg) {
std::string res;
dlg->setTitle(title);
dlg->setFileName(initialPath);
if (type == FileSelectorType::Save)
dlg->toSaveFile();
else
switch (type) {
case FileSelectorType::Open:
case FileSelectorType::OpenMultiple:
dlg->toOpenFile();
if (type == FileSelectorType::OpenMultiple)
dlg->setMultipleSelection(true);
break;
case FileSelectorType::Save:
dlg->toSaveFile();
break;
}
std::vector<std::string> tokens;
base::split_string(showExtensions, tokens, ",");
for (const auto& tok : tokens)
dlg->addFilter(tok, tok + " files (*." + tok + ")");
if (dlg->show(she::instance()->defaultDisplay()))
res = dlg->fileName();
bool res = dlg->show(she::instance()->defaultDisplay());
if (res) {
if (type == FileSelectorType::OpenMultiple)
dlg->getMultipleFileNames(output);
else
output.push_back(dlg->fileName());
}
dlg->dispose();
return res;
}
}
FileSelector fileSelector(type, delegate);
return fileSelector.show(title, initialPath, showExtensions);
return fileSelector.show(title, initialPath, showExtensions, output);
}
} // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -8,17 +8,20 @@
#define APP_FILE_SELECTOR_H_INCLUDED
#pragma once
#include <string>
#include "doc/pixel_ratio.h"
#include <string>
#include <vector>
namespace ui {
class ComboBox;
}
namespace app {
enum class FileSelectorType { Open, Save };
enum class FileSelectorType { Open, OpenMultiple, Save };
typedef std::vector<std::string> FileSelectorFiles;
class FileSelectorDelegate {
public:
@ -41,11 +44,12 @@ namespace app {
virtual doc::PixelRatio pixelRatio() = 0;
};
std::string show_file_selector(
bool show_file_selector(
const std::string& title,
const std::string& initialPath,
const std::string& showExtensions,
FileSelectorType type,
FileSelectorFiles& output,
FileSelectorDelegate* delegate = nullptr);
} // namespace app

View File

@ -33,20 +33,19 @@ using namespace ui;
FileList::FileList()
: Widget(kGenericWidget)
, m_currentFolder(FileSystemModule::instance()->getRootFileItem())
, m_req_valid(false)
, m_selected(nullptr)
, m_isearchClock(0)
, m_generateThumbnailTimer(200, this)
, m_monitoringTimer(50, this)
, m_itemToGenerateThumbnail(nullptr)
, m_thumbnail(nullptr)
, m_multiselect(false)
{
setFocusStop(true);
setDoubleBuffered(true);
m_currentFolder = FileSystemModule::instance()->getRootFileItem();
m_req_valid = false;
m_selected = NULL;
m_isearchClock = 0;
m_itemToGenerateThumbnail = NULL;
m_generateThumbnailTimer.Tick.connect(&FileList::onGenerateThumbnailTick, this);
m_monitoringTimer.Tick.connect(&FileList::onMonitoringTick, this);
m_monitoringTimer.start();
@ -80,7 +79,7 @@ void FileList::setCurrentFolder(IFileItem* folder)
m_currentFolder = folder;
m_req_valid = false;
m_selected = NULL;
m_selected = nullptr;
regenerateList();
@ -95,13 +94,56 @@ void FileList::setCurrentFolder(IFileItem* folder)
View::getView(this)->updateView();
}
FileItemList FileList::selectedFileItems() const
{
ASSERT(m_selectedItems.size() == m_list.size());
FileItemList result;
for (int i=0; i<int(m_list.size()); ++i) {
if (m_selectedItems[i])
result.push_back(m_list[i]);
}
return result;
}
void FileList::deselectedFileItems()
{
if (!m_multiselect)
return;
bool redraw = false;
for (int i=0; i<int(m_list.size()); ++i) {
if (m_selected == m_list[i]) {
if (!m_selectedItems[i]) {
m_selectedItems[i] = true;
redraw = true;
}
}
else if (m_selectedItems[i]) {
m_selectedItems[i] = false;
redraw = true;
}
}
if (redraw)
invalidate();
}
void FileList::setMultipleSelection(bool multiple)
{
m_multiselect = multiple;
}
void FileList::goUp()
{
IFileItem* folder = m_currentFolder;
IFileItem* parent = folder->parent();
if (parent) {
setCurrentFolder(parent);
m_selected = folder;
deselectedFileItems();
// Make the selected item visible.
makeSelectedFileitemVisible();
@ -120,21 +162,38 @@ bool FileList::onProcessMessage(Message* msg)
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
int th = textHeight();
int y = bounds().y;
IFileItem* old_selected = m_selected;
m_selected = NULL;
IFileItem* oldSelected = m_selected;
m_selected = nullptr;
// rows
for (FileItemList::iterator
it=m_list.begin();
it!=m_list.end(); ++it) {
int i = 0;
for (auto begin=m_list.begin(), end=m_list.end(), it=begin;
it!=end; ++it, ++i) {
IFileItem* fi = *it;
gfx::Size itemSize = getFileItemSize(fi);
if (((mouseMsg->position().y >= y) &&
(mouseMsg->position().y < y+th+4*guiscale())) ||
(it == m_list.begin() && mouseMsg->position().y < y) ||
(it == m_list.end()-1 && mouseMsg->position().y >= y+th+4*guiscale())) {
(it == begin && mouseMsg->position().y < y) ||
(it == end-1 && mouseMsg->position().y >= y+th+4*guiscale())) {
m_selected = fi;
if (m_multiselect &&
oldSelected != fi &&
m_selectedItems.size() == m_list.size()) {
if (msg->shiftPressed() ||
msg->ctrlPressed() ||
msg->cmdPressed()) {
m_selectedItems[i] = !m_selectedItems[i];
}
else {
std::fill(m_selectedItems.begin(),
m_selectedItems.end(), false);
m_selectedItems[i] = true;
}
invalidate();
}
makeSelectedFileitemVisible();
break;
}
@ -142,7 +201,7 @@ bool FileList::onProcessMessage(Message* msg)
y += itemSize.h;
}
if (old_selected != m_selected) {
if (oldSelected != m_selected) {
generatePreviewOfSelectedItem();
invalidate();
@ -164,7 +223,7 @@ bool FileList::onProcessMessage(Message* msg)
KeyMessage* keyMsg = static_cast<KeyMessage*>(msg);
KeyScancode scancode = keyMsg->scancode();
int unicodeChar = keyMsg->unicodeChar();
int select = getSelectedIndex();
int select = selectedIndex();
View* view = View::getView(this);
int bottom = m_list.size();
@ -328,7 +387,6 @@ void FileList::onPaint(ui::PaintEvent& ev)
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
gfx::Rect bounds = clientBounds();
int x, y = bounds.y;
int evenRow = 0;
gfx::Color bgcolor;
gfx::Color fgcolor;
@ -336,10 +394,15 @@ void FileList::onPaint(ui::PaintEvent& ev)
// rows
m_thumbnail = nullptr;
int i = 0;
for (IFileItem* fi : m_list) {
gfx::Size itemSize = getFileItemSize(fi);
const bool evenRow = ((i & 1) == 0);
if (fi == m_selected) {
if ((!m_multiselect && fi == m_selected) ||
(m_multiselect &&
m_selectedItems.size() == m_list.size() &&
m_selectedItems[i])) {
fgcolor = theme->colors.filelistSelectedRowText();
bgcolor = theme->colors.filelistSelectedRowFace();
}
@ -392,7 +455,7 @@ void FileList::onPaint(ui::PaintEvent& ev)
m_thumbnail = fi->getThumbnail();
y += itemSize.h;
evenRow ^= 1;
++i;
}
// Draw the thumbnail
@ -524,6 +587,7 @@ void FileList::regenerateList()
it=m_list.begin();
it!=m_list.end(); ) {
IFileItem* fileitem = *it;
if (fileitem->isHidden())
it = m_list.erase(it);
else if (!fileitem->isFolder() &&
@ -534,26 +598,33 @@ void FileList::regenerateList()
++it;
}
}
if (m_multiselect && !m_list.empty()) {
m_selectedItems.resize(m_list.size());
deselectedFileItems();
}
else
m_selectedItems.clear();
}
int FileList::getSelectedIndex()
int FileList::selectedIndex() const
{
for (FileItemList::iterator
it = m_list.begin();
it != m_list.end(); ++it) {
for (auto it = m_list.begin(), end = m_list.end();
it != end; ++it) {
if (*it == m_selected)
return it - m_list.begin();
}
return -1;
}
void FileList::selectIndex(int index)
{
IFileItem* old_selected = m_selected;
IFileItem* oldSelected = m_selected;
m_selected = m_list.at(index);
if (old_selected != m_selected) {
deselectedFileItems();
if (oldSelected != m_selected) {
makeSelectedFileitemVisible();
invalidate();

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -15,6 +15,7 @@
#include "ui/widget.h"
#include <string>
#include <vector>
namespace she {
class Surface;
@ -30,11 +31,16 @@ namespace app {
const std::string& extensions() const { return m_exts; }
void setExtensions(const char* extensions);
IFileItem* getCurrentFolder() const { return m_currentFolder; }
IFileItem* currentFolder() const { return m_currentFolder; }
void setCurrentFolder(IFileItem* folder);
IFileItem* getSelectedFileItem() const { return m_selected; }
const FileItemList& getFileList() const { return m_list; }
IFileItem* selectedFileItem() const { return m_selected; }
const FileItemList& fileList() const { return m_list; }
FileItemList selectedFileItems() const;
void deselectedFileItems();
bool multipleSelection() { return m_multiselect; }
void setMultipleSelection(bool multiple);
void goUp();
@ -58,16 +64,18 @@ namespace app {
gfx::Size getFileItemSize(IFileItem* fi) const;
void makeSelectedFileitemVisible();
void regenerateList();
int getSelectedIndex();
int selectedIndex() const;
void selectIndex(int index);
void generatePreviewOfSelectedItem();
int thumbnailY();
IFileItem* m_currentFolder;
FileItemList m_list;
bool m_req_valid;
int m_req_w, m_req_h;
IFileItem* m_selected;
std::vector<bool> m_selectedItems;
std::string m_exts;
// Incremental-search
@ -86,6 +94,10 @@ namespace app {
IFileItem* m_itemToGenerateThumbnail;
she::Surface* m_thumbnail;
// True if this listbox accepts selecting multiple items at the
// same time.
bool m_multiselect;
};
} // namespace app

View File

@ -109,6 +109,10 @@ public:
protected:
void onEntryChange() {
// Deselect multiple-selection
if (m_fileList->multipleSelection())
m_fileList->deselectedFileItems();
removeAllItems();
// String to be autocompleted
@ -118,7 +122,7 @@ protected:
if (left_part.empty())
return;
for (const IFileItem* child : m_fileList->getFileList()) {
for (const IFileItem* child : m_fileList->fileList()) {
std::string child_name = child->displayName();
std::string::const_iterator it1, it2;
@ -376,20 +380,19 @@ void FileSelector::goUp()
void FileSelector::goInsideFolder()
{
if (m_fileList->getSelectedFileItem() &&
m_fileList->getSelectedFileItem()->isBrowsable()) {
if (m_fileList->selectedFileItem() &&
m_fileList->selectedFileItem()->isBrowsable()) {
m_fileList->setCurrentFolder(
m_fileList->getSelectedFileItem());
m_fileList->selectedFileItem());
}
}
std::string FileSelector::show(
bool FileSelector::show(
const std::string& title,
const std::string& initialPath,
const std::string& showExtensions)
const std::string& showExtensions,
FileSelectorFiles& output)
{
std::string result;
FileSystemModule* fs = FileSystemModule::instance();
LockFS lock(fs);
@ -432,7 +435,8 @@ std::string FileSelector::show(
// Change the file formats/extensions to be shown
std::string initialExtension = base::get_file_extension(initialPath);
std::string exts = showExtensions;
if (m_type == FileSelectorType::Open) {
if (m_type == FileSelectorType::Open ||
m_type == FileSelectorType::OpenMultiple) {
auto it = preferred_open_extensions.find(exts);
if (it == preferred_open_extensions.end())
exts = showExtensions;
@ -444,13 +448,14 @@ std::string FileSelector::show(
if (!initialExtension.empty())
exts = initialExtension;
}
m_fileList->setMultipleSelection(m_type == FileSelectorType::OpenMultiple);
m_fileList->setExtensions(exts.c_str());
if (start_folder)
m_fileList->setCurrentFolder(start_folder);
// current location
navigation_position.reset();
addInNavigationHistory(m_fileList->getCurrentFolder());
addInNavigationHistory(m_fileList->currentFolder());
// fill the location combo-box
updateLocation();
@ -501,18 +506,19 @@ std::string FileSelector::show(
// update the view
View::getView(m_fileList)->updateView();
// open the window and run... the user press ok?
// TODO this loop needs a complete refactor
// Open the window and run... the user press ok?
again:
openWindowInForeground();
if (closer() == ok ||
closer() == m_fileList) {
// open the selected file
IFileItem* folder = m_fileList->getCurrentFolder();
IFileItem* folder = m_fileList->currentFolder();
ASSERT(folder);
// File name in the text entry field/combobox
std::string fn = m_fileName->getValue();
std::string buf;
IFileItem* enter_folder = NULL;
IFileItem* enter_folder = nullptr;
// up a level?
if (fn == "..") {
@ -521,13 +527,15 @@ again:
enter_folder = folder;
}
else if (fn.empty()) {
// show the window again
if (m_type != FileSelectorType::OpenMultiple) {
// Show the window again
setVisible(true);
goto again;
}
}
else {
// check if the user specified in "fn" a item of "fileview"
const FileItemList& children = m_fileList->getFileList();
const FileItemList& children = m_fileList->fileList();
std::string fn2 = fn;
#ifdef _WIN32
@ -536,7 +544,6 @@ again:
for (IFileItem* child : children) {
std::string child_name = child->displayName();
#ifdef _WIN32
child_name = base::string_to_lower(child_name);
#endif
@ -604,7 +611,7 @@ again:
// does it not have extension? ...we should add the extension
// selected in the filetype combo-box
if (base::get_file_extension(buf).empty()) {
if (!buf.empty() && base::get_file_extension(buf).empty()) {
buf += '.';
buf += getSelectedExtension();
}
@ -628,12 +635,17 @@ again:
}
// Cancel
else if (ret != 1) {
return "";
return false;
}
}
// duplicate the buffer to return a new string
result = buf;
// Put in output the selected filenames
if (!buf.empty())
output.push_back(buf);
else if (m_type == FileSelectorType::OpenMultiple) {
for (IFileItem* fi : m_fileList->selectedFileItems())
output.push_back(fi->fileName());
}
// save the path in the configuration file
std::string lastpath = folder->keyName();
@ -650,19 +662,19 @@ again:
}
}
return result;
return (!output.empty());
}
// Updates the content of the combo-box that shows the current
// location in the file-system.
void FileSelector::updateLocation()
{
IFileItem* currentFolder = m_fileList->getCurrentFolder();
IFileItem* currentFolder = m_fileList->currentFolder();
IFileItem* fileItem = currentFolder;
std::list<IFileItem*> locations;
int selected_index = -1;
while (fileItem != NULL) {
while (fileItem) {
locations.push_front(fileItem);
fileItem = fileItem->parent();
}
@ -672,8 +684,7 @@ void FileSelector::updateLocation()
// Add item by item (from root to the specific current folder)
int level = 0;
for (std::list<IFileItem*>::iterator it=locations.begin(), end=locations.end();
it != end; ++it) {
for (auto it=locations.begin(), end=locations.end(); it!=end; ++it) {
fileItem = *it;
// Indentation
@ -729,7 +740,7 @@ void FileSelector::updateNavigationButtons()
// Update the state of the go up button: if the current-folder isn't
// the root-item.
IFileItem* currentFolder = m_fileList->getCurrentFolder();
IFileItem* currentFolder = m_fileList->currentFolder();
goUpButton()->setEnabled(currentFolder != FileSystemModule::instance()->getRootFileItem());
}
@ -797,7 +808,7 @@ void FileSelector::onNewFolder()
window.openWindowInForeground();
if (window.closer() == window.ok()) {
IFileItem* currentFolder = m_fileList->getCurrentFolder();
IFileItem* currentFolder = m_fileList->currentFolder();
if (currentFolder) {
std::string dirname = window.name()->text();
@ -858,7 +869,8 @@ void FileSelector::onFileTypeChange()
m_fileList->setExtensions(exts.c_str());
m_navigationLocked = false;
if (m_type == FileSelectorType::Open) {
if (m_type == FileSelectorType::Open ||
m_type == FileSelectorType::OpenMultiple) {
std::string origShowExtensions = fileType()->getItem(0)->getValue();
preferred_open_extensions[origShowExtensions] = fileType()->getValue();
}
@ -876,12 +888,16 @@ void FileSelector::onFileTypeChange()
void FileSelector::onFileListFileSelected()
{
IFileItem* fileitem = m_fileList->getSelectedFileItem();
IFileItem* fileitem = m_fileList->selectedFileItem();
if (!fileitem->isFolder()) {
std::string filename = base::get_file_name(fileitem->fileName());
if (m_type != FileSelectorType::OpenMultiple ||
m_fileList->selectedFileItems().size() == 1)
m_fileName->setValue(filename.c_str());
else
m_fileName->setValue(std::string());
}
}
@ -893,7 +909,7 @@ void FileSelector::onFileListFileAccepted()
void FileSelector::onFileListCurrentFolderChanged()
{
if (!m_navigationLocked)
addInNavigationHistory(m_fileList->getCurrentFolder());
addInNavigationHistory(m_fileList->currentFolder());
updateLocation();
updateNavigationButtons();

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -38,9 +38,10 @@ namespace app {
void goInsideFolder();
// Shows the dialog to select a file in the program.
std::string show(const std::string& title,
bool show(const std::string& title,
const std::string& initialPath,
const std::string& showExtensions);
const std::string& showExtensions,
FileSelectorFiles& output);
private:
void updateLocation();

View File

@ -1,4 +1,4 @@
Copyright (c) 2012-2016 David Capello
Copyright (c) 2012-2017 David Capello
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@ -1,5 +1,5 @@
// SHE library
// Copyright (C) 2015 David Capello
// Copyright (C) 2015-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -9,6 +9,7 @@
#pragma once
#include <string>
#include <vector>
namespace she {
class Display;
@ -21,8 +22,10 @@ namespace she {
virtual void toSaveFile() = 0; // Configure the dialog to save a file
virtual void setTitle(const std::string& title) = 0;
virtual void setDefaultExtension(const std::string& extension) = 0;
virtual void setMultipleSelection(bool multiple) = 0;
virtual void addFilter(const std::string& extension, const std::string& description) = 0;
virtual std::string fileName() = 0;
virtual void getMultipleFileNames(std::vector<std::string>& output) = 0;
virtual void setFileName(const std::string& filename) = 0;
virtual bool show(Display* parent) = 0;
};

View File

@ -1,5 +1,5 @@
// SHE library
// Copyright (C) 2012-2016 David Capello
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -82,6 +82,7 @@ class FileDialogOSX : public FileDialog {
public:
FileDialogOSX()
: m_save(false)
, m_multipleSelection(false)
{
}
@ -105,6 +106,10 @@ public:
m_defExtension = extension;
}
void setMultipleSelection(bool multiple) override {
m_multipleSelection = multiple;
}
void addFilter(const std::string& extension, const std::string& description) override {
if (m_defExtension.empty())
m_defExtension = extension;
@ -116,6 +121,10 @@ public:
return m_filename;
}
void getMultipleFileNames(std::vector<std::string>& output) override {
output = m_filenames;
}
void setFileName(const std::string& filename) override {
m_filename = filename;
}
@ -128,7 +137,7 @@ public:
}
else {
panel = [NSOpenPanel openPanel];
[(NSOpenPanel*)panel setAllowsMultipleSelection:NO];
[(NSOpenPanel*)panel setAllowsMultipleSelection:(m_multipleSelection ? YES: NO)];
[(NSOpenPanel*)panel setCanChooseDirectories:NO];
}
@ -157,12 +166,22 @@ public:
bool retValue;
if ([helper result] == NSFileHandlingPanelOKButton) {
if (m_multipleSelection) {
for (NSURL* url in [(NSOpenPanel*)panel URLs]) {
m_filename = [[url path] UTF8String];
m_filenames.push_back(m_filename);
}
}
else {
NSURL* url = [panel URL];
m_filename = [[url path] UTF8String];
m_filenames.push_back(m_filename);
}
retValue = true;
}
else
else {
retValue = false;
}
#if !__has_feature(objc_arc)
[helper release];
@ -176,8 +195,10 @@ private:
std::vector<std::pair<std::string, std::string>> m_filters;
std::string m_defExtension;
std::string m_filename;
std::vector<std::string> m_filenames;
std::string m_title;
bool m_save;
bool m_multipleSelection;
};
NativeDialogsOSX::NativeDialogsOSX()

View File

@ -1,5 +1,5 @@
// SHE library
// Copyright (C) 2015-2016 David Capello
// Copyright (C) 2015-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -29,7 +29,8 @@ class FileDialogWin32 : public FileDialog {
public:
FileDialogWin32()
: m_filename(FILENAME_BUFSIZE)
, m_save(false) {
, m_save(false)
, m_multipleSelection(false) {
}
void dispose() override {
@ -52,6 +53,10 @@ public:
m_defExtension = base::from_utf8(extension);
}
void setMultipleSelection(bool multiple) override {
m_multipleSelection = multiple;
}
void addFilter(const std::string& extension, const std::string& description) override {
if (m_defExtension.empty()) {
m_defExtension = base::from_utf8(extension);
@ -64,6 +69,10 @@ public:
return base::to_utf8(&m_filename[0]);
}
void getMultipleFileNames(std::vector<std::string>& output) override {
output = m_filenames;
}
void setFileName(const std::string& filename) override {
wcscpy(&m_filename[0], base::from_utf8(base::get_file_name(filename)).c_str());
m_initialDir = base::from_utf8(base::get_file_path(filename));
@ -92,16 +101,41 @@ public:
OFN_NOCHANGEDIR |
OFN_PATHMUSTEXIST;
if (!m_save)
if (!m_save) {
ofn.Flags |= OFN_FILEMUSTEXIST;
if (m_multipleSelection)
ofn.Flags |= OFN_ALLOWMULTISELECT;
}
else
ofn.Flags |= OFN_OVERWRITEPROMPT;
BOOL res;
if (m_save)
res = GetSaveFileName(&ofn);
else
else {
res = GetOpenFileName(&ofn);
if (res && m_multipleSelection) {
WCHAR* p = &m_filename[0];
std::string path = base::to_utf8(p);
for (p+=std::wcslen(p)+1; ; ++p) {
if (*p) {
WCHAR* q = p;
for (++p; *p; ++p)
;
m_filenames.push_back(
base::join_path(path, base::to_utf8(q)));
}
else // Two null chars in a row
break;
}
// Just one filename was selected
if (m_filenames.empty())
m_filenames.push_back(path);
}
}
if (!res) {
DWORD err = CommDlgExtendedError();
@ -112,7 +146,7 @@ public:
}
}
return res != FALSE;
return (res != FALSE);
}
private:
@ -158,9 +192,11 @@ private:
std::wstring m_defExtension;
int m_defFilter;
std::vector<WCHAR> m_filename;
std::vector<std::string> m_filenames;
std::wstring m_initialDir;
std::wstring m_title;
bool m_save;
bool m_multipleSelection;
};
NativeDialogsWin32::NativeDialogsWin32()