|
|
|
|
@ -119,111 +119,6 @@ Directories::Directories() : Gtk::ListViewText(1) {
|
|
|
|
|
|
|
|
|
|
tree_store->set_sort_column(column_record.name, Gtk::SortType::SORT_ASCENDING); |
|
|
|
|
tree_store->set_sort_func(column_record.name, [this](const Gtk::TreeModel::iterator &it1, const Gtk::TreeModel::iterator &it2) { |
|
|
|
|
/// Natural comparison supporting UTF-8 and locale
|
|
|
|
|
struct Natural { |
|
|
|
|
static bool is_digit(char chr) { |
|
|
|
|
return chr >= '0' && chr <= '9'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int compare_characters(size_t &i1, size_t &i2, const std::string &s1, const std::string &s2) { |
|
|
|
|
ScopeGuard scope_guard{[&i1, &i2] { |
|
|
|
|
++i1; |
|
|
|
|
++i2; |
|
|
|
|
}}; |
|
|
|
|
auto c1 = static_cast<unsigned char>(s1[i1]); |
|
|
|
|
auto c2 = static_cast<unsigned char>(s2[i2]); |
|
|
|
|
if(c1 < 0b10000000 && c2 < 0b10000000) { // Both characters are ascii
|
|
|
|
|
auto at = std::tolower(s1[i1]); |
|
|
|
|
auto bt = std::tolower(s2[i2]); |
|
|
|
|
if(at < bt) |
|
|
|
|
return -1; |
|
|
|
|
else if(at == bt) |
|
|
|
|
return 0; |
|
|
|
|
else |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Glib::ustring u1; |
|
|
|
|
if(c1 >= 0b11110000) |
|
|
|
|
u1 = s1.substr(i1, 4); |
|
|
|
|
else if(c1 >= 0b11100000) |
|
|
|
|
u1 = s1.substr(i1, 3); |
|
|
|
|
else if(c1 >= 0b11000000) |
|
|
|
|
u1 = s1.substr(i1, 2); |
|
|
|
|
else |
|
|
|
|
u1 = s1[i1]; |
|
|
|
|
|
|
|
|
|
Glib::ustring u2; |
|
|
|
|
if(c2 >= 0b11110000) |
|
|
|
|
u2 = s2.substr(i2, 4); |
|
|
|
|
else if(c2 >= 0b11100000) |
|
|
|
|
u2 = s2.substr(i2, 3); |
|
|
|
|
else if(c2 >= 0b11000000) |
|
|
|
|
u2 = s2.substr(i2, 2); |
|
|
|
|
else |
|
|
|
|
u2 = s2[i2]; |
|
|
|
|
|
|
|
|
|
i1 += u1.bytes() - 1; |
|
|
|
|
i2 += u2.bytes() - 1; |
|
|
|
|
|
|
|
|
|
u1 = u1.lowercase(); |
|
|
|
|
u2 = u2.lowercase(); |
|
|
|
|
|
|
|
|
|
if(u1 < u2) |
|
|
|
|
return -1; |
|
|
|
|
else if(u1 == u2) |
|
|
|
|
return 0; |
|
|
|
|
else |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int compare_numbers(size_t &i1, size_t &i2, const std::string &s1, const std::string &s2) { |
|
|
|
|
int result = 0; |
|
|
|
|
while(true) { |
|
|
|
|
if(i1 >= s1.size() || !is_digit(s1[i1])) { |
|
|
|
|
if(i2 >= s2.size() || !is_digit(s2[i2])) // a and b has equal number of digits
|
|
|
|
|
return result; |
|
|
|
|
return -1; // a has fewer digits
|
|
|
|
|
} |
|
|
|
|
if(i2 >= s2.size() || !is_digit(s2[i2])) |
|
|
|
|
return 1; // b has fewer digits
|
|
|
|
|
|
|
|
|
|
if(result == 0) { |
|
|
|
|
if(s1[i1] < s2[i2]) |
|
|
|
|
result = -1; |
|
|
|
|
if(s1[i1] > s2[i2]) |
|
|
|
|
result = 1; |
|
|
|
|
} |
|
|
|
|
++i1; |
|
|
|
|
++i2; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int compare(const std::string &s1, const std::string &s2) { |
|
|
|
|
size_t i1 = 0; |
|
|
|
|
size_t i2 = 0; |
|
|
|
|
while(i1 < s1.size() && i2 < s2.size()) { |
|
|
|
|
if(is_digit(s1[i1]) && !is_digit(s2[i2])) |
|
|
|
|
return -1; |
|
|
|
|
if(!is_digit(s1[i1]) && is_digit(s2[i2])) |
|
|
|
|
return 1; |
|
|
|
|
if(!is_digit(s1[i1]) && !is_digit(s2[i2])) { |
|
|
|
|
auto result = compare_characters(i1, i2, s1, s2); |
|
|
|
|
if(result != 0) |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
auto result = compare_numbers(i1, i2, s1, s2); |
|
|
|
|
if(result != 0) |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(i1 >= s1.size()) |
|
|
|
|
return -1; |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
auto name1 = it1->get_value(column_record.name); |
|
|
|
|
auto name2 = it2->get_value(column_record.name); |
|
|
|
|
if(name1.empty()) |
|
|
|
|
@ -240,7 +135,7 @@ Directories::Directories() : Gtk::ListViewText(1) {
|
|
|
|
|
return Natural::compare(prefix1 + name1, prefix2 + name2); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
set_enable_search(true); //TODO: why does this not work in OS X?
|
|
|
|
|
set_enable_search(true); // TODO: why does this not work in OS X?
|
|
|
|
|
set_search_column(column_record.name); |
|
|
|
|
|
|
|
|
|
signal_row_activated().connect([this](const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column) { |
|
|
|
|
@ -522,7 +417,7 @@ void Directories::open(const boost::filesystem::path &dir_path) {
|
|
|
|
|
|
|
|
|
|
path = filesystem::get_normal_path(dir_path); |
|
|
|
|
|
|
|
|
|
//TODO: report that set_title does not handle '_' correctly?
|
|
|
|
|
// TODO: report that set_title does not handle '_' correctly?
|
|
|
|
|
auto title = path.filename().string(); |
|
|
|
|
size_t pos = 0; |
|
|
|
|
while((pos = title.find('_', pos)) != std::string::npos) { |
|
|
|
|
@ -582,7 +477,7 @@ void Directories::select(const boost::filesystem::path &select_path) {
|
|
|
|
|
if(!filesystem::file_in_path(select_path, path)) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
//return if the select_path is already selected
|
|
|
|
|
// return if the select_path is already selected
|
|
|
|
|
auto iter = get_selection()->get_selected(); |
|
|
|
|
if(iter) { |
|
|
|
|
if(iter->get_value(column_record.path) == select_path) |
|
|
|
|
@ -597,9 +492,9 @@ void Directories::select(const boost::filesystem::path &select_path) {
|
|
|
|
|
else |
|
|
|
|
parent_path = select_path.parent_path(); |
|
|
|
|
|
|
|
|
|
//check if select_path is already expanded
|
|
|
|
|
// check if select_path is already expanded
|
|
|
|
|
if(directories.find(parent_path.string()) != directories.end()) { |
|
|
|
|
//set cursor at select_path and return
|
|
|
|
|
// set cursor at select_path and return
|
|
|
|
|
tree_store->foreach_iter([this, &select_path](const Gtk::TreeModel::iterator &iter) { |
|
|
|
|
if(iter->get_value(column_record.path) == select_path) { |
|
|
|
|
auto tree_path = Gtk::TreePath(iter); |
|
|
|
|
@ -618,7 +513,7 @@ void Directories::select(const boost::filesystem::path &select_path) {
|
|
|
|
|
paths.emplace_front(parent_path); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//expand to select_path
|
|
|
|
|
// expand to select_path
|
|
|
|
|
for(auto &a_path : paths) { |
|
|
|
|
tree_store->foreach_iter([this, &a_path](const Gtk::TreeModel::iterator &iter) { |
|
|
|
|
if(iter->get_value(column_record.path) == a_path) { |
|
|
|
|
@ -629,7 +524,7 @@ void Directories::select(const boost::filesystem::path &select_path) {
|
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//set cursor at select_path
|
|
|
|
|
// set cursor at select_path
|
|
|
|
|
tree_store->foreach_iter([this, &select_path](const Gtk::TreeModel::iterator &iter) { |
|
|
|
|
if(iter->get_value(column_record.path) == select_path) { |
|
|
|
|
auto tree_path = Gtk::TreePath(iter); |
|
|
|
|
|