use std::filesystem::path instead of std::string

This commit is contained in:
Jinhao 2019-03-07 01:10:02 +08:00
parent 051525fc6f
commit 0a3fb34e09
7 changed files with 111 additions and 121 deletions

View File

@ -428,7 +428,7 @@ namespace nana { namespace experimental { namespace filesystem
file_status status(const path& p, std::error_code&); file_status status(const path& p, std::error_code&);
std::uintmax_t file_size(const path& p); std::uintmax_t file_size(const path& p);
//uintmax_t file_size(const path& p, error_code& ec) noexcept; std::uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
inline bool is_directory(file_status s) noexcept inline bool is_directory(file_status s) noexcept
{ return s.type() == file_type::directory ;} { return s.type() == file_type::directory ;}

View File

@ -1,7 +1,7 @@
/* /*
* A text editor implementation * A text editor implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -66,6 +66,7 @@ namespace nana{ namespace widgets
using char_type = wchar_t; using char_type = wchar_t;
using size_type = textbase<char_type>::size_type; using size_type = textbase<char_type>::size_type;
using string_type = textbase<char_type>::string_type; using string_type = textbase<char_type>::string_type;
using path_type = std::filesystem::path;
using event_interface = text_editor_event_interface; using event_interface = text_editor_event_interface;
@ -105,7 +106,7 @@ namespace nana{ namespace widgets
void indent(bool, std::function<std::string()> generator); void indent(bool, std::function<std::string()> generator);
void set_event(event_interface*); void set_event(event_interface*);
bool load(const char*); bool load(const path_type& file);
void text_align(::nana::align alignment); void text_align(::nana::align alignment);

View File

@ -1,7 +1,7 @@
/* /*
* A textbase class implementation * A textbase class implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -18,10 +18,11 @@
#include <nana/charset.hpp> #include <nana/charset.hpp>
#include <nana/basic_types.hpp> #include <nana/basic_types.hpp>
#include <nana/traits.hpp> #include <nana/traits.hpp>
#include <nana/filesystem/filesystem.hpp>
#include "textbase_export_interface.hpp" #include "textbase_export_interface.hpp"
#include <deque> #include <deque>
#include <memory>
#include <fstream> #include <fstream>
#include <stdexcept> #include <stdexcept>
@ -36,15 +37,16 @@ namespace skeletons
: public ::nana::noncopyable : public ::nana::noncopyable
{ {
public: public:
typedef CharT char_type; using char_type = CharT;
typedef std::basic_string<CharT> string_type; using string_type = std::basic_string<CharT>;
typedef typename string_type::size_type size_type; using size_type = typename string_type::size_type;
using path_type = std::filesystem::path;
textbase() textbase()
{ {
attr_max_.reset(); attr_max_.reset();
//Insert an empty string for the first line of empty text. //Insert an empty string for the first line of empty text.
text_cont_.emplace_back(new string_type); text_cont_.emplace_back();
} }
void set_event_agent(textbase_event_agent_interface * evt) void set_event_agent(textbase_event_agent_interface * evt)
@ -55,21 +57,19 @@ namespace skeletons
bool empty() const bool empty() const
{ {
return (text_cont_.empty() || return (text_cont_.empty() ||
((text_cont_.size() == 1) && (text_cont_.front()->empty()))); ((text_cont_.size() == 1) && text_cont_.front().empty()));
} }
bool load(const char* file_utf8) bool load(const path_type& file)
{ {
if (!file_utf8) std::ifstream ifs{ file.string() };
return false;
std::ifstream ifs(to_osmbstr(file_utf8));
if (!ifs) if (!ifs)
return false; return false;
ifs.seekg(0, std::ios::end); std::error_code err;
std::size_t bytes = static_cast<std::size_t>(ifs.tellg()); auto const bytes = file_size(file, err);
ifs.seekg(0, std::ios::beg); if (err)
return false;
if(bytes >= 2) if(bytes >= 2)
{ {
@ -81,7 +81,7 @@ namespace skeletons
if(0xBB == ch && 0xBF == ifs.get()) if(0xBB == ch && 0xBF == ifs.get())
{ {
ifs.close(); ifs.close();
return load(file_utf8, nana::unicode::utf8); return load(file, nana::unicode::utf8);
} }
} }
else if(0xFF == ch) else if(0xFF == ch)
@ -89,16 +89,13 @@ namespace skeletons
if(0xFE == ifs.get()) if(0xFE == ifs.get())
{ {
//UTF16,UTF32 //UTF16,UTF32
if(bytes >= 4) if((bytes >= 4) && (ifs.get() == 0 && ifs.get() == 0))
{ {
if(ifs.get() == 0 && ifs.get() == 0) ifs.close();
{ return load(file, nana::unicode::utf32);
ifs.close();
return load(file_utf8, nana::unicode::utf32);
}
} }
ifs.close(); ifs.close();
return load(file_utf8, nana::unicode::utf16); return load(file, nana::unicode::utf16);
} }
} }
else if(0xFE == ch) else if(0xFE == ch)
@ -107,7 +104,7 @@ namespace skeletons
{ {
//UTF16(big-endian) //UTF16(big-endian)
ifs.close(); ifs.close();
return load(file_utf8, nana::unicode::utf16); return load(file, nana::unicode::utf16);
} }
} }
else if(0 == ch) else if(0 == ch)
@ -119,7 +116,7 @@ namespace skeletons
{ {
//UTF32(big_endian) //UTF32(big_endian)
ifs.close(); ifs.close();
return load(file_utf8, nana::unicode::utf32); return load(file, nana::unicode::utf32);
} }
} }
} }
@ -135,15 +132,15 @@ namespace skeletons
while(ifs.good()) while(ifs.good())
{ {
std::getline(ifs, str_mbs); std::getline(ifs, str_mbs);
text_cont_.emplace_back(new string_type(static_cast<string_type&&>(nana::charset{ str_mbs }))); text_cont_.emplace_back(static_cast<string_type&&>(nana::charset{ str_mbs }));
if(text_cont_.back()->size() > attr_max_.size) if (text_cont_.back().size() > attr_max_.size)
{ {
attr_max_.size = text_cont_.back()->size(); attr_max_.size = text_cont_.back().size();
attr_max_.line = text_cont_.size() - 1; attr_max_.line = text_cont_.size() - 1;
} }
} }
_m_saved(file_utf8); _m_saved(file);
return true; return true;
} }
@ -175,12 +172,9 @@ namespace skeletons
} }
} }
bool load(const char* file_utf8, nana::unicode encoding) bool load(const path_type& file, nana::unicode encoding)
{ {
if (!file_utf8) std::ifstream ifs{ file.string() };
return false;
std::ifstream ifs(to_osmbstr(file_utf8));
if (!ifs) if (!ifs)
return false; return false;
@ -218,9 +212,8 @@ namespace skeletons
byte_order_translate_4bytes(str); byte_order_translate_4bytes(str);
} }
text_cont_.emplace_back(new string_type(static_cast<string_type&&>(nana::charset{ str, encoding }))); text_cont_.emplace_back(static_cast<string_type&&>(nana::charset{ str, encoding }));
attr_max_.size = text_cont_.back().size();
attr_max_.size = text_cont_.back()->size();
attr_max_.line = 0; attr_max_.line = 0;
} }
@ -236,21 +229,21 @@ namespace skeletons
byte_order_translate_4bytes(str); byte_order_translate_4bytes(str);
} }
text_cont_.emplace_back(new string_type(static_cast<string_type&&>(nana::charset{ str, encoding }))); text_cont_.emplace_back(static_cast<string_type&&>(nana::charset{ str, encoding }));
if(text_cont_.back()->size() > attr_max_.size) if (text_cont_.back().size() > attr_max_.size)
{ {
attr_max_.size = text_cont_.back()->size(); attr_max_.size = text_cont_.back().size();
attr_max_.line = text_cont_.size() - 1; attr_max_.line = text_cont_.size() - 1;
} }
} }
_m_saved(file_utf8); _m_saved(file);
return true; return true;
} }
void store(std::string fs, bool is_unicode, ::nana::unicode encoding) const void store(const path_type& filename, bool is_unicode, ::nana::unicode encoding) const
{ {
std::ofstream ofs(to_osmbstr(fs), std::ios::binary); std::ofstream ofs(filename.string(), std::ios::binary);
if(ofs && text_cont_.size()) if(ofs && text_cont_.size())
{ {
auto i = text_cont_.cbegin(); auto i = text_cont_.cbegin();
@ -277,27 +270,26 @@ namespace skeletons
for (std::size_t pos = 0; pos < count; ++pos) for (std::size_t pos = 0; pos < count; ++pos)
{ {
auto mbs = nana::charset(**(i++)).to_bytes(encoding); auto mbs = nana::charset(*(i++)).to_bytes(encoding);
ofs.write(mbs.c_str(), static_cast<std::streamsize>(mbs.size())); ofs.write(mbs.c_str(), static_cast<std::streamsize>(mbs.size()));
ofs.write("\r\n", 2); ofs.write("\r\n", 2);
} }
last_mbs = nana::charset(*text_cont_.back()).to_bytes(encoding); last_mbs = nana::charset(text_cont_.back()).to_bytes(encoding);
} }
else else
{ {
for (std::size_t pos = 0; pos < count; ++pos) for (std::size_t pos = 0; pos < count; ++pos)
{ {
std::string mbs = nana::charset(**(i++)); std::string mbs = nana::charset(*(i++));
ofs.write(mbs.c_str(), mbs.size()); ofs.write(mbs.c_str(), mbs.size());
ofs.write("\r\n", 2); ofs.write("\r\n", 2);
} }
last_mbs = nana::charset(text_cont_.back());
last_mbs = nana::charset(*text_cont_.back());
} }
ofs.write(last_mbs.c_str(), static_cast<std::streamsize>(last_mbs.size())); ofs.write(last_mbs.c_str(), static_cast<std::streamsize>(last_mbs.size()));
_m_saved(std::move(fs)); _m_saved(filename);
} }
} }
@ -311,7 +303,7 @@ namespace skeletons
{ {
if (!changed_) if (!changed_)
{ {
_m_first_change(); _m_emit_first_change();
changed_ = true; changed_ = true;
} }
@ -332,8 +324,7 @@ namespace skeletons
const string_type& getline(size_type pos) const const string_type& getline(size_type pos) const
{ {
if (pos < text_cont_.size()) if (pos < text_cont_.size())
return *text_cont_[pos]; return text_cont_[pos];
return nullstr_; return nullstr_;
} }
@ -346,7 +337,7 @@ namespace skeletons
{ {
if (text_cont_.size() <= pos) if (text_cont_.size() <= pos)
{ {
text_cont_.emplace_back(new string_type(std::move(text))); text_cont_.emplace_back(std::move(text));
pos = text_cont_.size() - 1; pos = text_cont_.size() - 1;
} }
else else
@ -369,7 +360,7 @@ namespace skeletons
} }
else else
{ {
text_cont_.emplace_back(new string_type(std::move(str))); text_cont_.emplace_back(std::move(str));
pos.y = static_cast<unsigned>(text_cont_.size() - 1); pos.y = static_cast<unsigned>(text_cont_.size() - 1);
} }
@ -380,9 +371,9 @@ namespace skeletons
void insertln(size_type pos, string_type&& str) void insertln(size_type pos, string_type&& str)
{ {
if (pos < text_cont_.size()) if (pos < text_cont_.size())
text_cont_.emplace(_m_iat(pos), new string_type(std::move(str))); text_cont_.emplace(_m_iat(pos), std::move(str));
else else
text_cont_.emplace_back(new string_type(std::move(str))); text_cont_.emplace_back(std::move(str));
_m_make_max(pos); _m_make_max(pos);
edited_ = true; edited_ = true;
@ -429,9 +420,9 @@ namespace skeletons
{ {
text_cont_.clear(); text_cont_.clear();
attr_max_.reset(); attr_max_.reset();
text_cont_.emplace_back(new string_type); //text_cont_ must not be empty text_cont_.emplace_back(); //text_cont_ must not be empty
_m_saved(std::string()); _m_saved({});
} }
void merge(size_type pos) void merge(size_type pos)
@ -439,7 +430,8 @@ namespace skeletons
if(pos + 1 < text_cont_.size()) if(pos + 1 < text_cont_.size())
{ {
auto i = _m_iat(pos + 1); auto i = _m_iat(pos + 1);
_m_at(pos) += **i; _m_at(pos) += *i;
text_cont_.erase(i); text_cont_.erase(i);
_m_make_max(pos); _m_make_max(pos);
@ -453,7 +445,7 @@ namespace skeletons
} }
} }
const std::string& filename() const const path_type& filename() const
{ {
return filename_; return filename_;
} }
@ -463,33 +455,25 @@ namespace skeletons
return changed_; return changed_;
} }
void edited_reset() void reset_status(bool remain_saved_filename)
{ {
changed_ = false; if(!remain_saved_filename)
} filename_.clear();
void reset()
{
filename_.clear();
changed_ = false; changed_ = false;
} }
bool saved() const bool saved() const
{ {
return ! not_saved(); return !(changed_ || filename_.empty());
}
bool not_saved() const
{
return edited() || filename_.empty();
} }
private: private:
string_type& _m_at(size_type pos) string_type& _m_at(size_type pos)
{ {
return **_m_iat(pos); return *_m_iat(pos);
} }
typename std::deque<std::unique_ptr<string_type>>::iterator _m_iat(size_type pos) typename std::deque<string_type>::iterator _m_iat(size_type pos)
{ {
return text_cont_.begin() + pos; return text_cont_.begin() + pos;
} }
@ -506,50 +490,40 @@ namespace skeletons
void _m_scan_for_max() void _m_scan_for_max()
{ {
attr_max_.size = 0; attr_max_.reset();
std::size_t n = 0; for (std::size_t i = 0; i < text_cont_.size(); ++i)
for(auto & p : text_cont_) _m_make_max(i);
{
if(p->size() > attr_max_.size)
{
attr_max_.size = p->size();
attr_max_.line = n;
}
++n;
}
} }
void _m_first_change() const void _m_emit_first_change() const
{ {
if (evt_agent_) if (evt_agent_)
evt_agent_->first_change(); evt_agent_->first_change();
} }
void _m_saved(std::string && filename) const void _m_saved(const path_type& filename) const
{ {
if(filename_ != filename) if((filename_ != filename) || changed_)
{ {
filename_ = std::move(filename); filename_ = filename;
_m_first_change(); _m_emit_first_change();
} }
else if(changed_)
_m_first_change();
changed_ = false; changed_ = false;
} }
private: private:
std::deque<std::unique_ptr<string_type>> text_cont_; std::deque<string_type> text_cont_;
textbase_event_agent_interface* evt_agent_{ nullptr }; textbase_event_agent_interface* evt_agent_{ nullptr };
mutable bool changed_{ false }; mutable bool changed_{ false };
mutable bool edited_{ false }; mutable bool edited_{ false };
mutable std::string filename_; //A string for the saved filename. mutable path_type filename_; ///< The saved filename
const string_type nullstr_; const string_type nullstr_;
struct attr_max struct attr_max
{ {
std::size_t line; std::size_t line; ///< The line number of max line
std::size_t size; std::size_t size; ///< The number of characters in max line
void reset() void reset()
{ {

View File

@ -1,7 +1,7 @@
/** /**
* A Textbox Implementation * A Textbox Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -109,6 +109,8 @@ namespace nana
using text_focus_behavior = widgets::skeletons::text_focus_behavior; using text_focus_behavior = widgets::skeletons::text_focus_behavior;
using text_positions = std::vector<upoint>; using text_positions = std::vector<upoint>;
using path_type = std::filesystem::path;
/// The default constructor without creating the widget. /// The default constructor without creating the widget.
textbox(); textbox();
@ -136,9 +138,9 @@ namespace nana
textbox(window, const rectangle& = rectangle(), bool visible = true); textbox(window, const rectangle& = rectangle(), bool visible = true);
/// \brief Loads a text file. When attempt to load a unicode encoded text file, be sure the file have a BOM header. /// \brief Loads a text file. When attempt to load a unicode encoded text file, be sure the file have a BOM header.
void load(std::string file); void load(const path_type& file);
void store(std::string file); void store(const path_type& file);
void store(std::string file, nana::unicode encoding); void store(const path_type& file, nana::unicode encoding);
colored_area_access_interface* colored_area_access(); colored_area_access_interface* colored_area_access();
@ -158,7 +160,7 @@ namespace nana
textbox& reset(const std::string& text = std::string(), bool end_caret = true); ///< discard the old text and set a new text textbox& reset(const std::string& text = std::string(), bool end_caret = true); ///< discard the old text and set a new text
/// The file of last store operation. /// The file of last store operation.
std::string filename() const; path_type filename() const;
/// Determine whether the text was edited. /// Determine whether the text was edited.
bool edited() const; bool edited() const;

View File

@ -936,7 +936,7 @@ namespace nana { namespace experimental { namespace filesystem
auto stat = status(p, err); auto stat = status(p, err);
if (err != std::error_code()) if (err != std::error_code())
throw filesystem_error("nana::experimental::filesystem::status", p, err); throw filesystem_error("nana::filesystem::status", p, err);
return stat; return stat;
} }
@ -1002,6 +1002,16 @@ namespace nana { namespace experimental { namespace filesystem
std::uintmax_t file_size(const path& p) std::uintmax_t file_size(const path& p)
{ {
std::error_code err;
auto bytes = file_size(p, err);
if (err)
throw filesystem_error("nana::filesystem::status", p, err);
return bytes;
}
std::uintmax_t file_size(const path& p, std::error_code& ec)
{
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
//Some compilation environment may fail to link to GetFileSizeEx //Some compilation environment may fail to link to GetFileSizeEx
typedef BOOL(__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER); typedef BOOL(__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER);
@ -1019,23 +1029,25 @@ namespace nana { namespace experimental { namespace filesystem
return li.QuadPart; return li.QuadPart;
} }
} }
return 0; ec.assign(static_cast<int>(::GetLastError()), std::generic_category());
#elif defined(NANA_POSIX) #elif defined(NANA_POSIX)
FILE * stream = ::fopen(p.c_str(), "rb"); FILE * stream = ::fopen(p.c_str(), "rb");
long long size = 0;
if (stream) if (stream)
{ {
long long bytes = 0;
# if defined(NANA_LINUX) # if defined(NANA_LINUX)
fseeko64(stream, 0, SEEK_END); fseeko64(stream, 0, SEEK_END);
size = ftello64(stream); bytes = ftello64(stream);
# elif defined(NANA_POSIX) # elif defined(NANA_POSIX)
fseeko(stream, 0, SEEK_END); fseeko(stream, 0, SEEK_END);
size = ftello(stream); bytes = ftello(stream);
# endif # endif
::fclose(stream); ::fclose(stream);
return bytes;
} }
return size; ec.assign(static_cast<int>(::errno), std::generic_category());
#endif #endif
return static_cast<std::uintmax_t>(-1);
} }

View File

@ -1275,7 +1275,7 @@ namespace nana {
event_handler_ = ptr; event_handler_ = ptr;
} }
bool text_editor::load(const char* fs) bool text_editor::load(const path_type& fs)
{ {
if (!impl_->textbase.load(fs)) if (!impl_->textbase.load(fs))
return false; return false;

View File

@ -1,7 +1,7 @@
/* /*
* A Textbox Implementation * A Textbox Implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -233,31 +233,31 @@ namespace drawerbase {
create(wd, r, visible); create(wd, r, visible);
} }
void textbox::load(std::string file) void textbox::load(const std::filesystem::path& file)
{ {
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
if (editor && editor->load(file.data())) if (editor && editor->load(file))
{ {
if (editor->try_refresh()) if (editor->try_refresh())
API::update_window(handle()); API::update_window(handle());
} }
} }
void textbox::store(std::string file) void textbox::store(const std::filesystem::path& file)
{ {
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
if (editor) if (editor)
editor->textbase().store(std::move(file), false, nana::unicode::utf8); //3rd parameter is just for syntax, it will be ignored editor->textbase().store(file, false, nana::unicode::utf8); //3rd parameter is just for syntax, it will be ignored
} }
void textbox::store(std::string file, nana::unicode encoding) void textbox::store(const std::filesystem::path& file, nana::unicode encoding)
{ {
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
if (editor) if (editor)
editor->textbase().store(std::move(file), true, encoding); editor->textbase().store(file, true, encoding);
} }
textbox::colored_area_access_interface* textbox::colored_area_access() textbox::colored_area_access_interface* textbox::colored_area_access()
@ -300,7 +300,8 @@ namespace drawerbase {
if (end_caret) if (end_caret)
editor->move_caret_end(true); editor->move_caret_end(true);
editor->textbase().reset(); //Reset the edited status and the saved filename
editor->textbase().reset_status(false);
if (editor->try_refresh()) if (editor->try_refresh())
API::update_window(this->handle()); API::update_window(this->handle());
@ -308,7 +309,7 @@ namespace drawerbase {
return *this; return *this;
} }
std::string textbox::filename() const textbox::path_type textbox::filename() const
{ {
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
@ -330,7 +331,7 @@ namespace drawerbase {
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
if (editor) if (editor)
editor->textbase().edited_reset(); editor->textbase().reset_status(true);
return *this; return *this;
} }