From 7117cc03b0276c5dd110ec390aa8fedb989f1ede Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 20 May 2015 12:42:53 +0200 Subject: [PATCH 01/17] adapting nana filesystem to std --- build/vc2013/nana.vcxproj | 3 + build/vc2013/nana.vcxproj.filters | 5 + include/nana/filesystem/filesystem.hpp | 272 +++++++++++++++++++++++++ 3 files changed, 280 insertions(+) create mode 100644 include/nana/filesystem/filesystem.hpp diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index 7e216758..5f16d613 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -247,6 +247,9 @@ + + + diff --git a/build/vc2013/nana.vcxproj.filters b/build/vc2013/nana.vcxproj.filters index f0f82981..1b098164 100644 --- a/build/vc2013/nana.vcxproj.filters +++ b/build/vc2013/nana.vcxproj.filters @@ -301,4 +301,9 @@ Source Files\nana\gui\widgets + + + Header Files + + \ No newline at end of file diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp new file mode 100644 index 00000000..bfdd1a71 --- /dev/null +++ b/include/nana/filesystem/filesystem.hpp @@ -0,0 +1,272 @@ +/* + * A filesystem Implementation + * Copyright(C) 2003 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: stdex/filesystem/filesystem.hpp + * @description: + * file_iterator is a toolkit for applying each file and directory in a + * specified path. + */ + +// http://en.cppreference.com/w/cpp/experimental/fs +// http://cpprocks.com/introduction-to-tr2-filesystem-library-in-vs2012/ --- TR2 filesystem in VS2012 +// https://msdn.microsoft.com/en-us/library/hh874694%28v=vs.140%29.aspx --- C++ 14, the header VS2015 +// https://msdn.microsoft.com/en-us/library/hh874694%28v=vs.120%29.aspx --- header VS2013 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf --- last pdf of std draft N4100 2014-07-04 +// http://cplusplus.github.io/filesystem-ts/working-draft.html --- in html format +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4099.html --- in html format +// http://article.gmane.org/gmane.comp.lib.boost.devel/256220 --- The filesystem TS unanimously approved by ISO. +// http://theboostcpplibraries.com/boost.filesystem --- Boost docs +// http://www.boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm --- +// http://www.boost.org/doc/libs/1_34_0/libs/filesystem/doc/index.htm +// http://www.boost.org/doc/libs/1_58_0/boost/filesystem.hpp + + +#ifndef NANA_FILESYSTEM_HPP +#define NANA_FILESYSTEM_HPP +#include +#include + +#include + +#ifdef NANA_WINDOWS + #include + typedef HANDLE find_handle_t; +#elif defined(NANA_LINUX) + #include + #include + #include + typedef DIR* find_handle_t; +#endif + + // namespace std { namespace experimental { namespace filesystem { inline namespace v1 { + +namespace nana +{ +namespace filesystem +{ + struct fileinfo + { + fileinfo(); +#ifdef NANA_WINDOWS + fileinfo(const WIN32_FIND_DATA& wfd); +#elif NANA_LINUX + fileinfo(const nana::string& filename, const struct stat &); +#endif + nana::string name; + + unsigned long size; + bool directory; + }; + + + /// an iterator for a sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator + //template + class directory_iterator :public std::iterator + { + public: + typedef fileinfo value_type; + + directory_iterator():end_(true), handle_(nullptr){} + + directory_iterator(const nana::string& file_path) + :end_(false), handle_(nullptr) + { + _m_prepare(file_path); + } + + const value_type& + operator*() const { return value_; } + + const value_type* + operator->() const { return &(operator*()); } + + directory_iterator& operator++() + { _m_read(); return *this; } + + directory_iterator operator++(int) + { + directory_iterator tmp = *this; + _m_read(); + return tmp; + } + + bool equal(const directory_iterator& x) const + { + if(end_ && (end_ == x.end_)) return true; + return (value_.name == x.value_.name); + } + private: + template + static bool _m_ignore(const Char * p) + { + while(*p == '.') + ++p; + return (*p == 0); + } + + void _m_prepare(const nana::string& file_path) + { + #if defined(NANA_WINDOWS) + path_ = file_path; + auto pat = file_path; + DWORD attr = ::GetFileAttributes(pat.data()); + if((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY)) + pat += STR("\\*"); + + ::HANDLE handle = ::FindFirstFile(pat.data(), &wfd_); + + if(handle == INVALID_HANDLE_VALUE) + { + end_ = true; + return; + } + + while(_m_ignore(wfd_.cFileName)) + { + if(::FindNextFile(handle, &wfd_) == 0) + { + end_ = true; + ::FindClose(handle); + return; + } + } + value_ = value_type(wfd_); + #elif defined(NANA_LINUX) + path_ = nana::charset(file_path); + if(path_.size() && (path_[path_.size() - 1] != '/')) + path_ += '/'; + find_handle_t handle = opendir(path_.c_str()); + end_ = true; + if(handle) + { + struct dirent * dnt = readdir(handle); + if(dnt) + { + while(_m_ignore(dnt->d_name)) + { + dnt = readdir(handle); + if(dnt == 0) + { + closedir(handle); + return; + } + } + + struct stat fst; + if(stat((path_ + dnt->d_name).c_str(), &fst) == 0) + { + value_ = value_type(nana::charset(dnt->d_name), fst); + } + else + { + value_.name = nana::charset(dnt->d_name); + value_.size = 0; + value_.directory = false; + } + end_ = false; + } + } + #endif + if(false == end_) + { + find_ptr_ = std::shared_ptr(new find_handle_t(handle), inner_handle_deleter()); + handle_ = handle; + } + } + + void _m_read() + { + if(handle_) + { + #if defined(NANA_WINDOWS) + if(::FindNextFile(handle_, &wfd_) != 0) + { + while(_m_ignore(wfd_.cFileName)) + { + if(::FindNextFile(handle_, &wfd_) == 0) + { + end_ = true; + return; + } + } + value_ = value_type(wfd_); + } + else + end_ = true; + #elif defined(NANA_LINUX) + struct dirent * dnt = readdir(handle_); + if(dnt) + { + while(_m_ignore(dnt->d_name)) + { + dnt = readdir(handle_); + if(dnt == 0) + { + end_ = true; + return; + } + } + struct stat fst; + if(stat((path_ + "/" + dnt->d_name).c_str(), &fst) == 0) + value_ = value_type(nana::charset(dnt->d_name), fst); + else + value_.name = nana::charset(dnt->d_name); + } + else + end_ = true; + #endif + } + } + private: + struct inner_handle_deleter + { + void operator()(find_handle_t * handle) + { + if(handle && *handle) + { + #if defined(NANA_WINDOWS) + ::FindClose(*handle); + #elif defined(NANA_LINUX) + ::closedir(*handle); + #endif + } + delete handle; + } + }; + private: + bool end_; + +#if defined(NANA_WINDOWS) + WIN32_FIND_DATA wfd_; + nana::string path_; +#elif defined(NANA_LINUX) + std::string path_; +#endif + std::shared_ptr find_ptr_; + + find_handle_t handle_; + value_type value_; + }; + + //template + inline bool operator==(const directory_iterator/**/ & x, const directory_iterator/**/ & y) + { + return x.equal(y); + } + + //template + inline bool operator!=(const directory_iterator/**/ & x, const directory_iterator/**/ & y) + { + return !x.equal(y); + } + + //using directory_iterator = directory_iterator ; +}//end namespace filesystem +}//end namespace nana + +#endif From 0b63ca51f7153270b2df657aea9013f9074656c8 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 21 May 2015 15:43:14 +0200 Subject: [PATCH 02/17] mimic std directory_iterator and directory_entry --- include/nana/filesystem/filesystem.hpp | 44 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index bfdd1a71..f71504b7 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -24,7 +24,7 @@ // http://www.boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm --- // http://www.boost.org/doc/libs/1_34_0/libs/filesystem/doc/index.htm // http://www.boost.org/doc/libs/1_58_0/boost/filesystem.hpp - +// https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.200x --- Table 1.4. g++ C++ Technical Specifications Implementation Status #ifndef NANA_FILESYSTEM_HPP #define NANA_FILESYSTEM_HPP @@ -49,16 +49,18 @@ namespace nana { namespace filesystem { - struct fileinfo - { - fileinfo(); -#ifdef NANA_WINDOWS - fileinfo(const WIN32_FIND_DATA& wfd); -#elif NANA_LINUX - fileinfo(const nana::string& filename, const struct stat &); -#endif - nana::string name; + using path = nana::string; + struct directory_entry + { + directory_entry(); + directory_entry(const nana::string& filename, bool is_directory, unsigned long size) + :name{filename}, size{size}, directory{is_directory} + {} + const path& path() const noexcept{return name;} + //operator const path&() const noexcept; + + nana::string name; unsigned long size; bool directory; }; @@ -66,10 +68,10 @@ namespace filesystem /// an iterator for a sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator //template - class directory_iterator :public std::iterator + class directory_iterator :public std::iterator { public: - typedef fileinfo value_type; + using value_type = directory_entry ; directory_iterator():end_(true), handle_(nullptr){} @@ -135,7 +137,11 @@ namespace filesystem return; } } - value_ = value_type(wfd_); + + value_ = value_type(wfd_.cFileName, + (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY, + wfd_.nFileSizeLow); + #elif defined(NANA_LINUX) path_ = nana::charset(file_path); if(path_.size() && (path_[path_.size() - 1] != '/')) @@ -160,7 +166,7 @@ namespace filesystem struct stat fst; if(stat((path_ + dnt->d_name).c_str(), &fst) == 0) { - value_ = value_type(nana::charset(dnt->d_name), fst); + value_ = value_type(nana::charset(dnt->d_name), 0 != S_ISDIR(fst.st_mode), fst.st_size); } else { @@ -194,7 +200,9 @@ namespace filesystem return; } } - value_ = value_type(wfd_); + value_ = value_type(wfd_.cFileName, + (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY, + wfd_.nFileSizeLow); } else end_ = true; @@ -213,7 +221,9 @@ namespace filesystem } struct stat fst; if(stat((path_ + "/" + dnt->d_name).c_str(), &fst) == 0) - value_ = value_type(nana::charset(dnt->d_name), fst); + value_ = value_type(wfd_.cFileName, + (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY, + wfd_.nFileSizeLow); else value_.name = nana::charset(dnt->d_name); } @@ -265,7 +275,7 @@ namespace filesystem return !x.equal(y); } - //using directory_iterator = directory_iterator ; + //using directory_iterator = directory_iterator ; }//end namespace filesystem }//end namespace nana From 02961f16737594f8620dcd4f869288c3fabb115f Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 21 May 2015 22:06:14 +0200 Subject: [PATCH 03/17] add file_type (from type), bring all from fs_utility and mimic path, and directory_entry --- build/vc2013/nana.vcxproj | 1 + build/vc2013/nana.vcxproj.filters | 3 + include/nana/filesystem/filesystem.hpp | 81 ++++- source/filesystem/filesystem.cpp | 442 +++++++++++++++++++++++++ 4 files changed, 517 insertions(+), 10 deletions(-) create mode 100644 source/filesystem/filesystem.cpp diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index 5f16d613..9547b689 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -177,6 +177,7 @@ + diff --git a/build/vc2013/nana.vcxproj.filters b/build/vc2013/nana.vcxproj.filters index 1b098164..cb51dab8 100644 --- a/build/vc2013/nana.vcxproj.filters +++ b/build/vc2013/nana.vcxproj.filters @@ -300,6 +300,9 @@ Source Files\nana\gui\widgets + + Source Files\nana\filesystem + diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index f71504b7..1f387006 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -49,20 +49,81 @@ namespace nana { namespace filesystem { - using path = nana::string; + enum class file_type + { + none = 0, ///< has not been determined or an error occurred while trying to determine + not_found = -1, ///< Pseudo-type: file was not found. Is not considered an error + regular = 1, + directory = 2 , + symlink =3, ///< Symbolic link file + block =4, ///< Block special file + character= 5 , ///< Character special file + fifo = 6 , ///< FIFO or pipe file + socket =7, + unknown= 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other + }; + + enum class error { none = 0 }; + + struct attribute + { + long long bytes; + bool is_directory; + tm modified; + }; + + bool file_attrib(const nana::string& file, attribute&); + long long filesize(const nana::string& file); + + bool mkdir(const nana::string& dir, bool & if_exist); + bool modified_file_time(const nana::string& file, struct tm&); + + nana::string path_user(); + nana::string path_current(); + + bool rmfile(const nana::char_t* file); + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty); + nana::string root(const nana::string& path); + + /// concerned only with lexical and syntactic aspects and does not necessarily exist in + /// external storage, and the pathname is not necessarily valid for the current operating system + /// or for a particular file system + /// A sequence of elements that identify the location of a file within a filesystem. + /// The elements are the: + /// rootname (opt), root-directory (opt), and an optional sequence of filenames. + /// The maximum number of elements in the sequence is operating system dependent. + class path + { + public: + path(); + path(const nana::string&); + + bool empty() const; + path root() const; + file_type what() const; + + nana::string name() const; + private: +#if defined(NANA_WINDOWS) + nana::string text_; +#else + std::string text_; +#endif + }; struct directory_entry { - directory_entry(); - directory_entry(const nana::string& filename, bool is_directory, unsigned long size) - :name{filename}, size{size}, directory{is_directory} - {} - const path& path() const noexcept{return name;} - //operator const path&() const noexcept; - - nana::string name; + path m_path; unsigned long size; bool directory; + + directory_entry(); + directory_entry(const nana::string& filename, bool is_directory, unsigned long size) + :m_path{filename}, size{size}, directory{is_directory} + {} + operator const path&() const noexcept; + const path& path() const noexcept{return m_path;} + }; @@ -100,7 +161,7 @@ namespace filesystem bool equal(const directory_iterator& x) const { if(end_ && (end_ == x.end_)) return true; - return (value_.name == x.value_.name); + return (value_.path().name() == x.value_.path().name()); } private: template diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp new file mode 100644 index 00000000..e79f786a --- /dev/null +++ b/source/filesystem/filesystem.cpp @@ -0,0 +1,442 @@ +/* + * A FileSystem Utility Implementation + * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/filesystem/filesystem.cpp + * @description: + * provide some interface for file managment + */ + +#include +#include +#if defined(NANA_WINDOWS) + #include + + #if defined(NANA_MINGW) + #ifndef _WIN32_IE + #define _WIN32_IE 0x0500 + #endif + #endif + + #include + #include +#elif defined(NANA_LINUX) + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +namespace nana +{ +namespace filesystem +{ +//Because of No wide character version of POSIX +#if defined(NANA_LINUX) + typedef std::string string_t; + const char* splstr = "/\\"; +#else + typedef nana::string string_t; + const nana::char_t* splstr = STR("/\\"); +#endif + //class path + path::path(){} + + path::path(const nana::string& text) +#if defined(NANA_WINDOWS) + :text_(text) + { +#else + :text_(nana::charset(text)) + { +#endif + auto pos = text_.find_last_of(splstr); + for(; (pos != string_t::npos) && (pos + 1 == text_.size()); pos = text_.find_last_of(splstr)) + text_.erase(pos); + } + + bool path::empty() const + { +#if defined(NANA_WINDOWS) + return (::GetFileAttributes(text_.c_str()) == INVALID_FILE_ATTRIBUTES); +#elif defined(NANA_LINUX) + struct stat sta; + return (::stat(text_.c_str(), &sta) == -1); +#endif + } + + path path::root() const + { + #if defined(NANA_WINDOWS) + return path(filesystem::root(text_)); + #elif defined(NANA_LINUX) + return path(filesystem::root(nana::charset(text_))); + #endif + } + + file_type path::what() const + { +#if defined(NANA_WINDOWS) + unsigned long attr = ::GetFileAttributes(text_.c_str()); + if(INVALID_FILE_ATTRIBUTES == attr) + return file_type:: not_found ; //?? + + if(FILE_ATTRIBUTE_DIRECTORY & attr) + return file_type::directory; + + return file_type::regular; +#elif defined(NANA_LINUX) + struct stat sta; + if(-1 == ::stat(text_.c_str(), &sta)) + return file_type:: not_found ; //?? + + if((S_IFDIR & sta.st_mode) == S_IFDIR) + return file_type::directory; + + if((S_IFREG & sta.st_mode) == S_IFREG) + return file_type::regular; + + return file_type::none; +#endif + } + + nana::string path::name() const + { + string_t::size_type pos = text_.find_last_of(splstr); +#if defined(NANA_WINDOWS) + return text_.substr(pos + 1); +#else + return nana::charset(text_.substr(pos + 1)); +#endif + } + //end class path + + namespace detail + { + //rm_dir_recursive + //@brief: remove a directory, if it is not empty, recursively remove it's subfiles and sub directories + bool rm_dir_recursive(nana::string&& dir) + { + std::vector files; + nana::string path = dir; + path += '\\'; + + std::copy(directory_iterator(dir), directory_iterator(), std::back_inserter(files)); + + for(auto & f : files) + { + if(f.directory) + rm_dir_recursive(path + f.path().name()); + else + rmfile((path + f.path().name()).c_str()); + } + + return rmdir(dir.c_str(), true); + } + + bool mkdir_helper(const nana::string& dir, bool & if_exist) + { +#if defined(NANA_WINDOWS) + if(::CreateDirectory(dir.c_str(), 0)) + { + if_exist = false; + return true; + } + + if_exist = (::GetLastError() == ERROR_ALREADY_EXISTS); +#elif defined(NANA_LINUX) + if(0 == ::mkdir(static_cast(nana::charset(dir)).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) + { + if_exist = false; + return true; + } + + if_exist = (errno == EEXIST); +#endif + return false; + } + +#if defined(NANA_WINDOWS) + void filetime_to_c_tm(FILETIME& ft, struct tm& t) + { + FILETIME local_file_time; + if(::FileTimeToLocalFileTime(&ft, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + } + } +#endif + }//end namespace detail + + bool file_attrib(const nana::string& file, attribute& attr) + { +#if defined(NANA_WINDOWS) + WIN32_FILE_ATTRIBUTE_DATA fad; + if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &fad)) + { + LARGE_INTEGER li; + li.u.LowPart = fad.nFileSizeLow; + li.u.HighPart = fad.nFileSizeHigh; + attr.bytes = li.QuadPart; + attr.is_directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); + detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified); + return true; + } +#elif defined(NANA_LINUX) + struct stat fst; + if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &fst)) + { + attr.bytes = fst.st_size; + attr.is_directory = (0 != (040000 & fst.st_mode)); + attr.modified = *(::localtime(&fst.st_ctime)); + return true; + } +#endif + return false; + } + + long long filesize(const nana::string& file) + { +#if defined(NANA_WINDOWS) + //Some compilation environment may fail to link to GetFileSizeEx + typedef BOOL (__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER); + GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx")); + if(get_file_size_ex) + { + HANDLE handle = ::CreateFile(file.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if(INVALID_HANDLE_VALUE != handle) + { + LARGE_INTEGER li; + if(!get_file_size_ex(handle, &li)) + li.QuadPart = 0; + + ::CloseHandle(handle); + return li.QuadPart; + } + } + return 0; +#elif defined(NANA_LINUX) + FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb"); + long long size = 0; + if(stream) + { + fseeko64(stream, 0, SEEK_END); + size = ftello64(stream); + fclose(stream); + } + return size; +#endif + } + + bool modified_file_time(const nana::string& file, struct tm& t) + { +#if defined(NANA_WINDOWS) + WIN32_FILE_ATTRIBUTE_DATA attr; + if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &attr)) + { + FILETIME local_file_time; + if(::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + return true; + } + } +#elif defined(NANA_LINUX) + struct stat attr; + if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &attr)) + { + t = *(::localtime(&attr.st_ctime)); + return true; + } +#endif + return false; + } + + bool mkdir(const nana::string& path, bool & if_exist) + { + if_exist = false; + if(path.size() == 0) return false; + + nana::string root; +#if defined(NANA_WINDOWS) + if(path.size() > 3 && path[1] == STR(':')) + root = path.substr(0, 3); +#elif defined(NANA_LINUX) + if(path[0] == STR('/')) + root = '/'; +#endif + bool mkstat = false; + std::size_t beg = root.size(); + + while(true) + { + beg = path.find_first_not_of(STR("/\\"), beg); + if(beg == path.npos) + break; + + std::size_t pos = path.find_first_of(STR("/\\"), beg + 1); + if(pos != path.npos) + { + root += path.substr(beg, pos - beg); + + mkstat = detail::mkdir_helper(root, if_exist); + if(mkstat == false && if_exist == false) + return false; + +#if defined(NANA_WINDOWS) + root += STR('\\'); +#elif defined(NANA_LINUX) + root += STR('/'); +#endif + } + else + { + if(beg + 1 < path.size()) + { + root += path.substr(beg); + mkstat = detail::mkdir_helper(root, if_exist); + } + break; + } + beg = pos + 1; + } + return mkstat; + } + + bool rmfile(const nana::char_t* file) + { +#if defined(NANA_WINDOWS) + bool ret = false; + if(file) + { + ret = (::DeleteFile(file) == TRUE); + if(!ret) + ret = (ERROR_FILE_NOT_FOUND == ::GetLastError()); + } + + return ret; +#elif defined(NANA_LINUX) + if(std::remove(static_cast(nana::charset(file)).c_str())) + return (errno == ENOENT); + return true; +#endif + } + + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty) + { + bool ret = false; + if(dir) + { +#if defined(NANA_WINDOWS) + ret = (::RemoveDirectory(dir) == TRUE); + if(!fails_if_not_empty && (::GetLastError() == ERROR_DIR_NOT_EMPTY)) + ret = detail::rm_dir_recursive(dir); +#elif defined(NANA_LINUX) + std::string mbstr = nana::charset(dir); + if(::rmdir(mbstr.c_str())) + { + if(!fails_if_not_empty && (errno == EEXIST || errno == ENOTEMPTY)) + ret = detail::rm_dir_recursive(dir); + } + else + ret = true; +#endif + } + return ret; + } + + nana::string root(const nana::string& path) + { + std::size_t index = path.size(); + + if(index) + { + const nana::char_t * str = path.c_str(); + + for(--index; index > 0; --index) + { + nana::char_t c = str[index]; + if(c != '\\' && c != '/') + break; + } + + for(--index; index > 0; --index) + { + nana::char_t c = str[index]; + if(c == '\\' || c == '/') + break; + } + } + + return index?path.substr(0, index + 1):nana::string(); + } + + nana::string path_user() + { +#if defined(NANA_WINDOWS) + nana::char_t path[MAX_PATH]; + if(SUCCEEDED(SHGetFolderPath(0, CSIDL_PROFILE, 0, SHGFP_TYPE_CURRENT, path))) + return path; +#elif defined(NANA_LINUX) + const char * s = ::getenv("HOME"); + if(s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } + + nana::string path_current() + { +#if defined(NANA_WINDOWS) + nana::char_t buf[MAX_PATH]; + DWORD len = ::GetCurrentDirectory(MAX_PATH, buf); + if(len) + { + if(len > MAX_PATH) + { + nana::char_t * p = new nana::char_t[len + 1]; + ::GetCurrentDirectory(len + 1, p); + nana::string s = p; + delete [] p; + return s; + } + return buf; + } +#elif defined(NANA_LINUX) + const char * s = ::getenv("PWD"); + if(s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } +}//end namespace filesystem +}//end namespace nana From 59f0ace35397c49bd47d7b8f1912cf96d505e129 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 22 May 2015 00:19:13 +0200 Subject: [PATCH 04/17] mimic enum class perms , more adaption --- include/nana/filesystem/filesystem.hpp | 165 +++++++++++++++++++++---- source/filesystem/filesystem.cpp | 12 +- 2 files changed, 144 insertions(+), 33 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 1f387006..3b8f3dd7 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -30,6 +30,7 @@ #define NANA_FILESYSTEM_HPP #include #include +#include #include @@ -63,27 +64,62 @@ namespace filesystem unknown= 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other }; + enum class perms + { + none =0, ///< There are no permissions set for the file. + unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions + }; + //enum class copy_options; + //enum class directory_options; + + // class filesystem_error; enum class error { none = 0 }; - struct attribute + struct attribute // deprecate ?? { - long long bytes; - bool is_directory; - tm modified; + uintmax_t size {}; + bool directory{}; + tm modified {}; + + attribute() {} ; + attribute( uintmax_t size, bool is_directory) :size{size}, directory{is_directory} {} }; - bool file_attrib(const nana::string& file, attribute&); - long long filesize(const nana::string& file); + struct space_info + { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; + }; + using file_time_type = std::chrono::time_point< std::chrono::system_clock>;// trivial-clock> ; - bool mkdir(const nana::string& dir, bool & if_exist); - bool modified_file_time(const nana::string& file, struct tm&); + class file_status + { + file_type m_ft = file_type::none; + perms m_prms = perms::unknown; - nana::string path_user(); - nana::string path_current(); + public: + explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown) noexcept + :m_ft{ft}, m_prms{prms} + {} - bool rmfile(const nana::char_t* file); - bool rmdir(const nana::char_t* dir, bool fails_if_not_empty); - nana::string root(const nana::string& path); + file_status(const file_status& fs) noexcept: m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; + file_status(file_status&& fs) noexcept: m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; + + ~file_status(){}; + file_status& operator=(const file_status&) noexcept = default; + file_status& operator=(file_status&&fs) noexcept // = default; + { + m_ft=fs.m_ft; m_prms = fs.m_prms; + return *this; + } + // observers + file_type type() const noexcept{ return m_ft;} + perms permissions() const noexcept{ return m_prms;} + // modifiers + void type (file_type ft) noexcept { m_ft=ft ;} + void permissions(perms prms) noexcept { m_prms = prms; } + }; /// concerned only with lexical and syntactic aspects and does not necessarily exist in /// external storage, and the pathname is not necessarily valid for the current operating system @@ -114,33 +150,40 @@ namespace filesystem struct directory_entry { path m_path; - unsigned long size; - bool directory; + + attribute attr{}; + //file_status m_status; directory_entry(); - directory_entry(const nana::string& filename, bool is_directory, unsigned long size) - :m_path{filename}, size{size}, directory{is_directory} + directory_entry(const nana::string& filename, bool is_directory, uintmax_t size) + :m_path{filename}, attr{size, is_directory} {} - operator const path&() const noexcept; + + void assign (const path& p){ m_path=p;} + void replace_filename(const path& p){ m_path=p;} + + //file_status status() const; + + operator const path&() const noexcept{return m_path;}; const path& path() const noexcept{return m_path;} }; - /// an iterator for a sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator //template class directory_iterator :public std::iterator { public: using value_type = directory_entry ; + typedef ptrdiff_t difference_type; + typedef const directory_entry* pointer; + typedef const directory_entry& reference; + typedef std::input_iterator_tag iterator_category; directory_iterator():end_(true), handle_(nullptr){} - directory_iterator(const nana::string& file_path) - :end_(false), handle_(nullptr) - { - _m_prepare(file_path); - } + directory_iterator(const nana::string& file_path) { _m_prepare(file_path); } + directory_iterator(const path& file_path) { _m_prepare(file_path.name()); } const value_type& operator*() const { return value_; } @@ -310,7 +353,7 @@ namespace filesystem } }; private: - bool end_; + bool end_{false}; #if defined(NANA_WINDOWS) WIN32_FIND_DATA wfd_; @@ -320,10 +363,19 @@ namespace filesystem #endif std::shared_ptr find_ptr_; - find_handle_t handle_; + find_handle_t handle_{nullptr}; value_type value_; }; + // enable directory_iterator range-based for statements + directory_iterator begin(directory_iterator iter) noexcept { return iter; } + directory_iterator end(const directory_iterator&) noexcept { return {}; } + + //class recursive_directory_iterator; + //// enable recursive_directory_iterator range-based for statements + //recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; + //recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; + //template inline bool operator==(const directory_iterator/**/ & x, const directory_iterator/**/ & y) { @@ -336,7 +388,66 @@ namespace filesystem return !x.equal(y); } - //using directory_iterator = directory_iterator ; + + // file_status status(const path& p); + bool file_attrib(const nana::string& file, attribute&); + + bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} + bool is_directory(const path& p){return directory_iterator(p.name())->attr.directory; } + //bool is_directory(const path& p, error_code& ec) noexcept; + + //bool is_regular_file(file_status s) noexcept; + + bool is_empty(const path& p) + { + directory_iterator d(p) ; + return d->attr.directory ? d == directory_iterator() + : d->attr.size == 0; + } + //bool is_empty(const path& p, error_code& ec) noexcept; + + uintmax_t file_size(const nana::string& file); // deprecate? + uintmax_t file_size(const path& p){return file_size(p.name());} + //uintmax_t file_size(const path& p, error_code& ec) noexcept; + //long long filesize(const nana::string& file); + + + bool create_directories(const path& p); + //bool create_directories(const path& p, error_code& ec) noexcept; + bool create_directory(const path& p); + //bool create_directory(const path& p, error_code& ec) noexcept; + bool create_directory(const path& p, const path& attributes); + //bool create_directory(const path& p, const path& attributes, error_code& ec) noexcept; + bool create_directory(const nana::string& dir, bool & if_exist); + bool create_directory(const path& p, bool & if_exist) + { + return create_directory(p.name(), if_exist); + }; + + + bool modified_file_time(const nana::string& file, struct tm&); + + + nana::string path_user(); + + + path current_path(); + //path current_path(error_code& ec); + void current_path(const path& p); + //void current_path(const path& p, error_code& ec) noexcept; + //nana::string path_current(); + + + //bool remove(const path& p); + //bool remove(const path& p, error_code& ec) noexcept; + bool rmfile(const nana::char_t* file); + + //uintmax_t remove_all(const path& p); + //uintmax_t remove_all(const path& p, error_code& ec) noexcept; + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty); + nana::string root(const nana::string& path); + + }//end namespace filesystem }//end namespace nana diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index e79f786a..f578afeb 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -134,7 +134,7 @@ namespace filesystem for(auto & f : files) { - if(f.directory) + if(f.attr.directory) rm_dir_recursive(path + f.path().name()); else rmfile((path + f.path().name()).c_str()); @@ -196,8 +196,8 @@ namespace filesystem LARGE_INTEGER li; li.u.LowPart = fad.nFileSizeLow; li.u.HighPart = fad.nFileSizeHigh; - attr.bytes = li.QuadPart; - attr.is_directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); + attr.size = li.QuadPart; + attr.directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified); return true; } @@ -214,7 +214,7 @@ namespace filesystem return false; } - long long filesize(const nana::string& file) + uintmax_t file_size(const nana::string& file) { #if defined(NANA_WINDOWS) //Some compilation environment may fail to link to GetFileSizeEx @@ -281,7 +281,7 @@ namespace filesystem return false; } - bool mkdir(const nana::string& path, bool & if_exist) + bool create_directory(const nana::string& path, bool & if_exist) { if_exist = false; if(path.size() == 0) return false; @@ -414,7 +414,7 @@ namespace filesystem return nana::string(); } - nana::string path_current() + path current_path() { #if defined(NANA_WINDOWS) nana::char_t buf[MAX_PATH]; From f55c54f7b4ae04336f6154d67f2ec0f2156e4e1e Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 22 May 2015 23:21:01 +0200 Subject: [PATCH 05/17] filesystem to experimental to avoid conflicts with fs_utillity --- include/nana/filesystem/filesystem.hpp | 5 +- source/filesystem/filesystem.cpp | 724 +++++++++++++------------ 2 files changed, 366 insertions(+), 363 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 3b8f3dd7..c117a797 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -46,7 +46,7 @@ // namespace std { namespace experimental { namespace filesystem { inline namespace v1 { -namespace nana +namespace nana { namespace experimental { namespace filesystem { @@ -73,7 +73,7 @@ namespace filesystem //enum class directory_options; // class filesystem_error; - enum class error { none = 0 }; + enum class error { none = 0 }; // deprecate ?? struct attribute // deprecate ?? { @@ -449,6 +449,7 @@ namespace filesystem }//end namespace filesystem +} //end namespace experimental }//end namespace nana #endif diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index f578afeb..07d297f3 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -36,407 +36,409 @@ #include #endif -namespace nana -{ -namespace filesystem -{ -//Because of No wide character version of POSIX +namespace nana { + namespace experimental + { + namespace filesystem + { + //Because of No wide character version of POSIX #if defined(NANA_LINUX) - typedef std::string string_t; - const char* splstr = "/\\"; + typedef std::string string_t; + const char* splstr = "/\\"; #else - typedef nana::string string_t; - const nana::char_t* splstr = STR("/\\"); + typedef nana::string string_t; + const nana::char_t* splstr = STR("/\\"); #endif - //class path - path::path(){} + //class path + path::path() {} - path::path(const nana::string& text) + path::path(const nana::string& text) #if defined(NANA_WINDOWS) - :text_(text) - { + : text_(text) + { #else - :text_(nana::charset(text)) - { + :text_(nana::charset(text)) + { #endif - auto pos = text_.find_last_of(splstr); - for(; (pos != string_t::npos) && (pos + 1 == text_.size()); pos = text_.find_last_of(splstr)) - text_.erase(pos); - } + auto pos = text_.find_last_of(splstr); + for (; (pos != string_t::npos) && (pos + 1 == text_.size()); pos = text_.find_last_of(splstr)) + text_.erase(pos); + } - bool path::empty() const - { + bool path::empty() const + { #if defined(NANA_WINDOWS) - return (::GetFileAttributes(text_.c_str()) == INVALID_FILE_ATTRIBUTES); + return (::GetFileAttributes(text_.c_str()) == INVALID_FILE_ATTRIBUTES); #elif defined(NANA_LINUX) - struct stat sta; - return (::stat(text_.c_str(), &sta) == -1); + struct stat sta; + return (::stat(text_.c_str(), &sta) == -1); #endif - } + } - path path::root() const - { - #if defined(NANA_WINDOWS) - return path(filesystem::root(text_)); - #elif defined(NANA_LINUX) - return path(filesystem::root(nana::charset(text_))); - #endif - } - - file_type path::what() const - { + path path::root() const + { #if defined(NANA_WINDOWS) - unsigned long attr = ::GetFileAttributes(text_.c_str()); - if(INVALID_FILE_ATTRIBUTES == attr) - return file_type:: not_found ; //?? - - if(FILE_ATTRIBUTE_DIRECTORY & attr) - return file_type::directory; - - return file_type::regular; + return path(filesystem::root(text_)); #elif defined(NANA_LINUX) - struct stat sta; - if(-1 == ::stat(text_.c_str(), &sta)) - return file_type:: not_found ; //?? + return path(filesystem::root(nana::charset(text_))); +#endif + } - if((S_IFDIR & sta.st_mode) == S_IFDIR) - return file_type::directory; + file_type path::what() const + { +#if defined(NANA_WINDOWS) + unsigned long attr = ::GetFileAttributes(text_.c_str()); + if (INVALID_FILE_ATTRIBUTES == attr) + return file_type::not_found; //?? + + if (FILE_ATTRIBUTE_DIRECTORY & attr) + return file_type::directory; - if((S_IFREG & sta.st_mode) == S_IFREG) return file_type::regular; +#elif defined(NANA_LINUX) + struct stat sta; + if (-1 == ::stat(text_.c_str(), &sta)) + return file_type::not_found; //?? - return file_type::none; + if ((S_IFDIR & sta.st_mode) == S_IFDIR) + return file_type::directory; + + if ((S_IFREG & sta.st_mode) == S_IFREG) + return file_type::regular; + + return file_type::none; #endif - } + } - nana::string path::name() const - { - string_t::size_type pos = text_.find_last_of(splstr); + nana::string path::name() const + { + string_t::size_type pos = text_.find_last_of(splstr); #if defined(NANA_WINDOWS) - return text_.substr(pos + 1); + return text_.substr(pos + 1); #else - return nana::charset(text_.substr(pos + 1)); -#endif - } - //end class path - - namespace detail - { - //rm_dir_recursive - //@brief: remove a directory, if it is not empty, recursively remove it's subfiles and sub directories - bool rm_dir_recursive(nana::string&& dir) - { - std::vector files; - nana::string path = dir; - path += '\\'; - - std::copy(directory_iterator(dir), directory_iterator(), std::back_inserter(files)); - - for(auto & f : files) - { - if(f.attr.directory) - rm_dir_recursive(path + f.path().name()); - else - rmfile((path + f.path().name()).c_str()); - } - - return rmdir(dir.c_str(), true); - } - - bool mkdir_helper(const nana::string& dir, bool & if_exist) - { -#if defined(NANA_WINDOWS) - if(::CreateDirectory(dir.c_str(), 0)) - { - if_exist = false; - return true; - } - - if_exist = (::GetLastError() == ERROR_ALREADY_EXISTS); -#elif defined(NANA_LINUX) - if(0 == ::mkdir(static_cast(nana::charset(dir)).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) - { - if_exist = false; - return true; - } - - if_exist = (errno == EEXIST); -#endif - return false; - } - -#if defined(NANA_WINDOWS) - void filetime_to_c_tm(FILETIME& ft, struct tm& t) - { - FILETIME local_file_time; - if(::FileTimeToLocalFileTime(&ft, &local_file_time)) - { - SYSTEMTIME st; - ::FileTimeToSystemTime(&local_file_time, &st); - t.tm_year = st.wYear - 1900; - t.tm_mon = st.wMonth - 1; - t.tm_mday = st.wDay; - t.tm_wday = st.wDayOfWeek - 1; - t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); - - t.tm_hour = st.wHour; - t.tm_min = st.wMinute; - t.tm_sec = st.wSecond; - } - } -#endif - }//end namespace detail - - bool file_attrib(const nana::string& file, attribute& attr) - { -#if defined(NANA_WINDOWS) - WIN32_FILE_ATTRIBUTE_DATA fad; - if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &fad)) - { - LARGE_INTEGER li; - li.u.LowPart = fad.nFileSizeLow; - li.u.HighPart = fad.nFileSizeHigh; - attr.size = li.QuadPart; - attr.directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); - detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified); - return true; - } -#elif defined(NANA_LINUX) - struct stat fst; - if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &fst)) - { - attr.bytes = fst.st_size; - attr.is_directory = (0 != (040000 & fst.st_mode)); - attr.modified = *(::localtime(&fst.st_ctime)); - return true; - } -#endif - return false; - } - - uintmax_t file_size(const nana::string& file) - { -#if defined(NANA_WINDOWS) - //Some compilation environment may fail to link to GetFileSizeEx - typedef BOOL (__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER); - GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx")); - if(get_file_size_ex) - { - HANDLE handle = ::CreateFile(file.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if(INVALID_HANDLE_VALUE != handle) - { - LARGE_INTEGER li; - if(!get_file_size_ex(handle, &li)) - li.QuadPart = 0; - - ::CloseHandle(handle); - return li.QuadPart; - } - } - return 0; -#elif defined(NANA_LINUX) - FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb"); - long long size = 0; - if(stream) - { - fseeko64(stream, 0, SEEK_END); - size = ftello64(stream); - fclose(stream); - } - return size; -#endif - } - - bool modified_file_time(const nana::string& file, struct tm& t) - { -#if defined(NANA_WINDOWS) - WIN32_FILE_ATTRIBUTE_DATA attr; - if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &attr)) - { - FILETIME local_file_time; - if(::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &local_file_time)) - { - SYSTEMTIME st; - ::FileTimeToSystemTime(&local_file_time, &st); - t.tm_year = st.wYear - 1900; - t.tm_mon = st.wMonth - 1; - t.tm_mday = st.wDay; - t.tm_wday = st.wDayOfWeek - 1; - t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); - - t.tm_hour = st.wHour; - t.tm_min = st.wMinute; - t.tm_sec = st.wSecond; - return true; - } - } -#elif defined(NANA_LINUX) - struct stat attr; - if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &attr)) - { - t = *(::localtime(&attr.st_ctime)); - return true; - } -#endif - return false; - } - - bool create_directory(const nana::string& path, bool & if_exist) - { - if_exist = false; - if(path.size() == 0) return false; - - nana::string root; -#if defined(NANA_WINDOWS) - if(path.size() > 3 && path[1] == STR(':')) - root = path.substr(0, 3); -#elif defined(NANA_LINUX) - if(path[0] == STR('/')) - root = '/'; -#endif - bool mkstat = false; - std::size_t beg = root.size(); - - while(true) - { - beg = path.find_first_not_of(STR("/\\"), beg); - if(beg == path.npos) - break; - - std::size_t pos = path.find_first_of(STR("/\\"), beg + 1); - if(pos != path.npos) - { - root += path.substr(beg, pos - beg); - - mkstat = detail::mkdir_helper(root, if_exist); - if(mkstat == false && if_exist == false) - return false; - -#if defined(NANA_WINDOWS) - root += STR('\\'); -#elif defined(NANA_LINUX) - root += STR('/'); + return nana::charset(text_.substr(pos + 1)); #endif } - else + //end class path + + namespace detail { - if(beg + 1 < path.size()) + //rm_dir_recursive + //@brief: remove a directory, if it is not empty, recursively remove it's subfiles and sub directories + bool rm_dir_recursive(nana::string&& dir) { - root += path.substr(beg); - mkstat = detail::mkdir_helper(root, if_exist); + std::vector files; + nana::string path = dir; + path += '\\'; + + std::copy(directory_iterator(dir), directory_iterator(), std::back_inserter(files)); + + for (auto & f : files) + { + if (f.attr.directory) + rm_dir_recursive(path + f.path().name()); + else + rmfile((path + f.path().name()).c_str()); + } + + return rmdir(dir.c_str(), true); } - break; - } - beg = pos + 1; - } - return mkstat; - } - bool rmfile(const nana::char_t* file) - { + bool mkdir_helper(const nana::string& dir, bool & if_exist) + { #if defined(NANA_WINDOWS) - bool ret = false; - if(file) - { - ret = (::DeleteFile(file) == TRUE); - if(!ret) - ret = (ERROR_FILE_NOT_FOUND == ::GetLastError()); - } + if (::CreateDirectory(dir.c_str(), 0)) + { + if_exist = false; + return true; + } - return ret; + if_exist = (::GetLastError() == ERROR_ALREADY_EXISTS); #elif defined(NANA_LINUX) - if(std::remove(static_cast(nana::charset(file)).c_str())) - return (errno == ENOENT); - return true; -#endif - } + if (0 == ::mkdir(static_cast(nana::charset(dir)).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) + { + if_exist = false; + return true; + } + + if_exist = (errno == EEXIST); +#endif + return false; + } - bool rmdir(const nana::char_t* dir, bool fails_if_not_empty) - { - bool ret = false; - if(dir) - { #if defined(NANA_WINDOWS) - ret = (::RemoveDirectory(dir) == TRUE); - if(!fails_if_not_empty && (::GetLastError() == ERROR_DIR_NOT_EMPTY)) - ret = detail::rm_dir_recursive(dir); -#elif defined(NANA_LINUX) - std::string mbstr = nana::charset(dir); - if(::rmdir(mbstr.c_str())) - { - if(!fails_if_not_empty && (errno == EEXIST || errno == ENOTEMPTY)) - ret = detail::rm_dir_recursive(dir); - } - else - ret = true; + void filetime_to_c_tm(FILETIME& ft, struct tm& t) + { + FILETIME local_file_time; + if (::FileTimeToLocalFileTime(&ft, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + } + } #endif - } - return ret; - } + }//end namespace detail - nana::string root(const nana::string& path) - { - std::size_t index = path.size(); - - if(index) - { - const nana::char_t * str = path.c_str(); - - for(--index; index > 0; --index) + bool file_attrib(const nana::string& file, attribute& attr) { - nana::char_t c = str[index]; - if(c != '\\' && c != '/') - break; - } - - for(--index; index > 0; --index) - { - nana::char_t c = str[index]; - if(c == '\\' || c == '/') - break; - } - } - - return index?path.substr(0, index + 1):nana::string(); - } - - nana::string path_user() - { #if defined(NANA_WINDOWS) - nana::char_t path[MAX_PATH]; - if(SUCCEEDED(SHGetFolderPath(0, CSIDL_PROFILE, 0, SHGFP_TYPE_CURRENT, path))) - return path; + WIN32_FILE_ATTRIBUTE_DATA fad; + if (::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &fad)) + { + LARGE_INTEGER li; + li.u.LowPart = fad.nFileSizeLow; + li.u.HighPart = fad.nFileSizeHigh; + attr.size = li.QuadPart; + attr.directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); + detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified); + return true; + } #elif defined(NANA_LINUX) - const char * s = ::getenv("HOME"); - if(s) - return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); + struct stat fst; + if (0 == ::stat(static_cast(nana::charset(file)).c_str(), &fst)) + { + attr.bytes = fst.st_size; + attr.is_directory = (0 != (040000 & fst.st_mode)); + attr.modified = *(::localtime(&fst.st_ctime)); + return true; + } #endif - return nana::string(); - } - - path current_path() - { -#if defined(NANA_WINDOWS) - nana::char_t buf[MAX_PATH]; - DWORD len = ::GetCurrentDirectory(MAX_PATH, buf); - if(len) - { - if(len > MAX_PATH) - { - nana::char_t * p = new nana::char_t[len + 1]; - ::GetCurrentDirectory(len + 1, p); - nana::string s = p; - delete [] p; - return s; + return false; } - return buf; - } + + uintmax_t file_size(const nana::string& file) + { +#if defined(NANA_WINDOWS) + //Some compilation environment may fail to link to GetFileSizeEx + typedef BOOL(__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER); + GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx")); + if (get_file_size_ex) + { + HANDLE handle = ::CreateFile(file.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (INVALID_HANDLE_VALUE != handle) + { + LARGE_INTEGER li; + if (!get_file_size_ex(handle, &li)) + li.QuadPart = 0; + + ::CloseHandle(handle); + return li.QuadPart; + } + } + return 0; #elif defined(NANA_LINUX) - const char * s = ::getenv("PWD"); - if(s) - return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); + FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb"); + long long size = 0; + if (stream) + { + fseeko64(stream, 0, SEEK_END); + size = ftello64(stream); + fclose(stream); + } + return size; #endif - return nana::string(); - } -}//end namespace filesystem + } + + bool modified_file_time(const nana::string& file, struct tm& t) + { +#if defined(NANA_WINDOWS) + WIN32_FILE_ATTRIBUTE_DATA attr; + if (::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &attr)) + { + FILETIME local_file_time; + if (::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + return true; + } + } +#elif defined(NANA_LINUX) + struct stat attr; + if (0 == ::stat(static_cast(nana::charset(file)).c_str(), &attr)) + { + t = *(::localtime(&attr.st_ctime)); + return true; + } +#endif + return false; + } + + bool create_directory(const nana::string& path, bool & if_exist) + { + if_exist = false; + if (path.size() == 0) return false; + + nana::string root; +#if defined(NANA_WINDOWS) + if (path.size() > 3 && path[1] == STR(':')) + root = path.substr(0, 3); +#elif defined(NANA_LINUX) + if (path[0] == STR('/')) + root = '/'; +#endif + bool mkstat = false; + std::size_t beg = root.size(); + + while (true) + { + beg = path.find_first_not_of(STR("/\\"), beg); + if (beg == path.npos) + break; + + std::size_t pos = path.find_first_of(STR("/\\"), beg + 1); + if (pos != path.npos) + { + root += path.substr(beg, pos - beg); + + mkstat = detail::mkdir_helper(root, if_exist); + if (mkstat == false && if_exist == false) + return false; + +#if defined(NANA_WINDOWS) + root += STR('\\'); +#elif defined(NANA_LINUX) + root += STR('/'); +#endif + } + else + { + if (beg + 1 < path.size()) + { + root += path.substr(beg); + mkstat = detail::mkdir_helper(root, if_exist); + } + break; + } + beg = pos + 1; + } + return mkstat; + } + + bool rmfile(const nana::char_t* file) + { +#if defined(NANA_WINDOWS) + bool ret = false; + if (file) + { + ret = (::DeleteFile(file) == TRUE); + if (!ret) + ret = (ERROR_FILE_NOT_FOUND == ::GetLastError()); + } + + return ret; +#elif defined(NANA_LINUX) + if (std::remove(static_cast(nana::charset(file)).c_str())) + return (errno == ENOENT); + return true; +#endif + } + + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty) + { + bool ret = false; + if (dir) + { +#if defined(NANA_WINDOWS) + ret = (::RemoveDirectory(dir) == TRUE); + if (!fails_if_not_empty && (::GetLastError() == ERROR_DIR_NOT_EMPTY)) + ret = detail::rm_dir_recursive(dir); +#elif defined(NANA_LINUX) + std::string mbstr = nana::charset(dir); + if (::rmdir(mbstr.c_str())) + { + if (!fails_if_not_empty && (errno == EEXIST || errno == ENOTEMPTY)) + ret = detail::rm_dir_recursive(dir); + } + else + ret = true; +#endif + } + return ret; + } + + nana::string root(const nana::string& path) + { + std::size_t index = path.size(); + + if (index) + { + const nana::char_t * str = path.c_str(); + + for (--index; index > 0; --index) + { + nana::char_t c = str[index]; + if (c != '\\' && c != '/') + break; + } + + for (--index; index > 0; --index) + { + nana::char_t c = str[index]; + if (c == '\\' || c == '/') + break; + } + } + + return index ? path.substr(0, index + 1) : nana::string(); + } + + nana::string path_user() + { +#if defined(NANA_WINDOWS) + nana::char_t path[MAX_PATH]; + if (SUCCEEDED(SHGetFolderPath(0, CSIDL_PROFILE, 0, SHGFP_TYPE_CURRENT, path))) + return path; +#elif defined(NANA_LINUX) + const char * s = ::getenv("HOME"); + if (s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } + + path current_path() + { +#if defined(NANA_WINDOWS) + nana::char_t buf[MAX_PATH]; + DWORD len = ::GetCurrentDirectory(MAX_PATH, buf); + if (len) + { + if (len > MAX_PATH) + { + nana::char_t * p = new nana::char_t[len + 1]; + ::GetCurrentDirectory(len + 1, p); + nana::string s = p; + delete[] p; + return s; + } + return buf; + } +#elif defined(NANA_LINUX) + const char * s = ::getenv("PWD"); + if (s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } + }//end namespace filesystem + } //end namespace experimental }//end namespace nana From 895dbcbe7db4f465b64ab9a40e3fbbd33be2aabd Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 22 May 2015 23:26:42 +0200 Subject: [PATCH 06/17] FIX: compiling with VC2015 RC --- include/nana/config.hpp | 14 +++++++++++++- source/gui/widgets/combox.cpp | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/nana/config.hpp b/include/nana/config.hpp index 77b9005c..fecf633f 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -13,6 +13,18 @@ #ifndef NANA_CONFIG_HPP #define NANA_CONFIG_HPP + +#if defined(_MSC_VER) +#if (_MSC_VER == 1900) + // google: break any code that tries to use codecvt or codecvt. + // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. + // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively. + // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. + // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. +#define STD_CODECVT_NOT_SUPPORTED +#endif // _MSC_VER == 1900 +#endif // _MSVC + //Select platform automatically #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) //Windows: @@ -35,7 +47,7 @@ #define PLATFORM_SPEC_HPP #define STD_CODECVT_NOT_SUPPORTED #else -# static_assert(false, "Only Windows and Unix are support now"); +# static_assert(false, "Only Windows and Unix are supported now"); #endif #if defined(NANA_MINGW) || defined(NANA_LINUX) diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index b1d401f5..64208c54 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -18,6 +18,8 @@ #include #include +#include + namespace nana { arg_combox::arg_combox(combox& wdg): widget(wdg) From e99783ed54d1eb2ebe76bf6497d92a25ffd6df4c Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 23 May 2015 23:55:19 +0200 Subject: [PATCH 07/17] FIX: inline functions and one default constructor. Tested OK ! --- include/nana/filesystem/filesystem.hpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index c117a797..60a0ea12 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -139,6 +139,7 @@ namespace filesystem file_type what() const; nana::string name() const; + operator nana::string() { return name(); } private: #if defined(NANA_WINDOWS) nana::string text_; @@ -154,7 +155,7 @@ namespace filesystem attribute attr{}; //file_status m_status; - directory_entry(); + directory_entry(){} directory_entry(const nana::string& filename, bool is_directory, uintmax_t size) :m_path{filename}, attr{size, is_directory} {} @@ -368,8 +369,8 @@ namespace filesystem }; // enable directory_iterator range-based for statements - directory_iterator begin(directory_iterator iter) noexcept { return iter; } - directory_iterator end(const directory_iterator&) noexcept { return {}; } + inline directory_iterator begin(directory_iterator iter) noexcept { return iter; } + inline directory_iterator end(const directory_iterator&) noexcept { return {}; } //class recursive_directory_iterator; //// enable recursive_directory_iterator range-based for statements @@ -392,13 +393,13 @@ namespace filesystem // file_status status(const path& p); bool file_attrib(const nana::string& file, attribute&); - bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} - bool is_directory(const path& p){return directory_iterator(p.name())->attr.directory; } + inline bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} + inline bool is_directory(const path& p){return directory_iterator(p.name())->attr.directory; } //bool is_directory(const path& p, error_code& ec) noexcept; //bool is_regular_file(file_status s) noexcept; - bool is_empty(const path& p) + inline bool is_empty(const path& p) { directory_iterator d(p) ; return d->attr.directory ? d == directory_iterator() @@ -407,7 +408,7 @@ namespace filesystem //bool is_empty(const path& p, error_code& ec) noexcept; uintmax_t file_size(const nana::string& file); // deprecate? - uintmax_t file_size(const path& p){return file_size(p.name());} + inline uintmax_t file_size(const path& p){return file_size(p.name());} //uintmax_t file_size(const path& p, error_code& ec) noexcept; //long long filesize(const nana::string& file); @@ -419,7 +420,7 @@ namespace filesystem bool create_directory(const path& p, const path& attributes); //bool create_directory(const path& p, const path& attributes, error_code& ec) noexcept; bool create_directory(const nana::string& dir, bool & if_exist); - bool create_directory(const path& p, bool & if_exist) + inline bool create_directory(const path& p, bool & if_exist) { return create_directory(p.name(), if_exist); }; From 888e65aa842acdf20aca08f4a666eb03913961f7 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 24 May 2015 00:46:59 +0200 Subject: [PATCH 08/17] the linker don't like my inlines --- include/nana/filesystem/filesystem.hpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 60a0ea12..35de2a94 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -9,7 +9,10 @@ * @file: stdex/filesystem/filesystem.hpp * @description: * file_iterator is a toolkit for applying each file and directory in a - * specified path. + * specified path. + * Modiffied by Ariel Vina-Rodriguez: + * Now mimic std::experimental::filesystem::v1 (boost v3) + * and need VC2015 or a C++11 compiler. With a few correction will be compiler by VC2013 */ // http://en.cppreference.com/w/cpp/experimental/fs @@ -207,6 +210,12 @@ namespace filesystem if(end_ && (end_ == x.end_)) return true; return (value_.path().name() == x.value_.path().name()); } + + + // enable directory_iterator range-based for statements + directory_iterator begin( ) noexcept { return *this; } + directory_iterator end( ) noexcept { return {}; } + private: template static bool _m_ignore(const Char * p) @@ -368,9 +377,6 @@ namespace filesystem value_type value_; }; - // enable directory_iterator range-based for statements - inline directory_iterator begin(directory_iterator iter) noexcept { return iter; } - inline directory_iterator end(const directory_iterator&) noexcept { return {}; } //class recursive_directory_iterator; //// enable recursive_directory_iterator range-based for statements @@ -407,7 +413,7 @@ namespace filesystem } //bool is_empty(const path& p, error_code& ec) noexcept; - uintmax_t file_size(const nana::string& file); // deprecate? + uintmax_t file_size(const nana::string& file); // deprecate? inline uintmax_t file_size(const path& p){return file_size(p.name());} //uintmax_t file_size(const path& p, error_code& ec) noexcept; //long long filesize(const nana::string& file); From a42931830f05d7239a39071d7aa7152e2cf60cdb Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 24 May 2015 02:00:06 +0200 Subject: [PATCH 09/17] mimic path.filename() --- include/nana/filesystem/filesystem.hpp | 22 +++++++++++----------- source/filesystem/filesystem.cpp | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 35de2a94..790968ca 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -141,8 +141,8 @@ namespace filesystem path root() const; file_type what() const; - nana::string name() const; - operator nana::string() { return name(); } + nana::string filename() const; + operator nana::string() { return filename(); } private: #if defined(NANA_WINDOWS) nana::string text_; @@ -159,8 +159,8 @@ namespace filesystem //file_status m_status; directory_entry(){} - directory_entry(const nana::string& filename, bool is_directory, uintmax_t size) - :m_path{filename}, attr{size, is_directory} + directory_entry(const nana::string& filename_, bool is_directory, uintmax_t size) + :m_path{filename_}, attr{size, is_directory} {} void assign (const path& p){ m_path=p;} @@ -187,7 +187,7 @@ namespace filesystem directory_iterator():end_(true), handle_(nullptr){} directory_iterator(const nana::string& file_path) { _m_prepare(file_path); } - directory_iterator(const path& file_path) { _m_prepare(file_path.name()); } + directory_iterator(const path& file_path) { _m_prepare(file_path.filename()); } const value_type& operator*() const { return value_; } @@ -208,7 +208,7 @@ namespace filesystem bool equal(const directory_iterator& x) const { if(end_ && (end_ == x.end_)) return true; - return (value_.path().name() == x.value_.path().name()); + return (value_.path().filename() == x.value_.path().filename()); } @@ -284,7 +284,7 @@ namespace filesystem } else { - value_.name = nana::charset(dnt->d_name); + value_.m_path = nana::charset(dnt->d_name); value_.size = 0; value_.directory = false; } @@ -339,7 +339,7 @@ namespace filesystem (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY, wfd_.nFileSizeLow); else - value_.name = nana::charset(dnt->d_name); + value_.m_path = nana::charset(dnt->d_name); } else end_ = true; @@ -400,7 +400,7 @@ namespace filesystem bool file_attrib(const nana::string& file, attribute&); inline bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} - inline bool is_directory(const path& p){return directory_iterator(p.name())->attr.directory; } + inline bool is_directory(const path& p){return directory_iterator(p.filename())->attr.directory; } //bool is_directory(const path& p, error_code& ec) noexcept; //bool is_regular_file(file_status s) noexcept; @@ -414,7 +414,7 @@ namespace filesystem //bool is_empty(const path& p, error_code& ec) noexcept; uintmax_t file_size(const nana::string& file); // deprecate? - inline uintmax_t file_size(const path& p){return file_size(p.name());} + inline uintmax_t file_size(const path& p){return file_size(p.filename());} //uintmax_t file_size(const path& p, error_code& ec) noexcept; //long long filesize(const nana::string& file); @@ -428,7 +428,7 @@ namespace filesystem bool create_directory(const nana::string& dir, bool & if_exist); inline bool create_directory(const path& p, bool & if_exist) { - return create_directory(p.name(), if_exist); + return create_directory(p.filename(), if_exist); }; diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index 07d297f3..4c6e8d22 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -110,7 +110,7 @@ namespace nana { #endif } - nana::string path::name() const + nana::string path::filename() const { string_t::size_type pos = text_.find_last_of(splstr); #if defined(NANA_WINDOWS) @@ -136,9 +136,9 @@ namespace nana { for (auto & f : files) { if (f.attr.directory) - rm_dir_recursive(path + f.path().name()); + rm_dir_recursive(path + f.path().filename()); else - rmfile((path + f.path().name()).c_str()); + rmfile((path + f.path().filename()).c_str()); } return rmdir(dir.c_str(), true); From 9fbabadd7828316b70126f68e045bc3b0835ee68 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 24 May 2015 03:12:02 +0200 Subject: [PATCH 10/17] better mimic? --- include/nana/filesystem/filesystem.hpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 790968ca..658579fd 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -142,11 +142,17 @@ namespace filesystem file_type what() const; nana::string filename() const; - operator nana::string() { return filename(); } - private: #if defined(NANA_WINDOWS) + public: + nana::string to_string() const { return text_; } + operator nana::string() const { return text_; } + private: nana::string text_; #else + public: + std::string to_string() const { return text_; } + operator std::string() const { return text_; } + private: std::string text_; #endif }; @@ -187,7 +193,7 @@ namespace filesystem directory_iterator():end_(true), handle_(nullptr){} directory_iterator(const nana::string& file_path) { _m_prepare(file_path); } - directory_iterator(const path& file_path) { _m_prepare(file_path.filename()); } + //directory_iterator(const path& file_path) { _m_prepare(file_path.filename()); } const value_type& operator*() const { return value_; } @@ -400,7 +406,8 @@ namespace filesystem bool file_attrib(const nana::string& file, attribute&); inline bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} - inline bool is_directory(const path& p){return directory_iterator(p.filename())->attr.directory; } + inline bool is_directory(const path& p) { return directory_iterator{ p }->attr.directory; }//works?? + inline bool is_directory(const directory_entry& d) { return d.attr.directory; } //bool is_directory(const path& p, error_code& ec) noexcept; //bool is_regular_file(file_status s) noexcept; From ae1d01814a2134d2e3302516204ee02f13c87586 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 22 May 2015 23:29:48 +0200 Subject: [PATCH 11/17] FIX: linker warning which eventually produce errors --- build/vc2013/nana.vcxproj | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index 7e216758..ea824f68 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -70,21 +70,29 @@ ../bin/vc2013/ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); ../bin/vc2013/ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ../bin/vc2013/ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); ../bin/vc2013/ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ @@ -102,7 +110,7 @@ true - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + $(TargetPath) @@ -119,7 +127,7 @@ true - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + $(TargetPath) @@ -141,7 +149,7 @@ true - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + $(TargetPath) @@ -162,7 +170,7 @@ true - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + $(TargetPath) From b37ecda1877583fa922b798ba3b99e1df8bb9e7d Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 23 May 2015 00:32:30 +0200 Subject: [PATCH 12/17] fix more warning --- build/vc2013/nana.vcxproj | 16 ++++++++-------- include/nana/config.hpp | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index ea824f68..03fe61cb 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -67,32 +67,32 @@ - ../bin/vc2013/ + ../bin/ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) - ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); - ../bin/vc2013/ + ../bin/ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) - ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ - ../bin/vc2013/ + ../bin/ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) - ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); - ../bin/vc2013/ + ../bin/ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) - ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ diff --git a/include/nana/config.hpp b/include/nana/config.hpp index 77b9005c..30ae2dc5 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -13,6 +13,21 @@ #ifndef NANA_CONFIG_HPP #define NANA_CONFIG_HPP + +#if defined(_MSC_VER) + #define _SCL_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_DEPRECATE + #pragma warning(disable : 4996) + #if (_MSC_VER == 1900) + // google: break any code that tries to use codecvt or codecvt. + // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. + // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively. + // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. + // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. + #define STD_CODECVT_NOT_SUPPORTED + #endif // _MSC_VER == 1900 +#endif // _MSVC + //Select platform automatically #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) //Windows: @@ -35,7 +50,7 @@ #define PLATFORM_SPEC_HPP #define STD_CODECVT_NOT_SUPPORTED #else -# static_assert(false, "Only Windows and Unix are support now"); +# static_assert(false, "Only Windows and Unix are supported now"); #endif #if defined(NANA_MINGW) || defined(NANA_LINUX) From 80aed9c94baa086fd8cea0579820325cd4c13c49 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 23 May 2015 01:49:40 +0200 Subject: [PATCH 13/17] nana filesystem need vc2015 --- build/vc2013/nana.vcxproj.filters | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/vc2013/nana.vcxproj.filters b/build/vc2013/nana.vcxproj.filters index f0f82981..1b098164 100644 --- a/build/vc2013/nana.vcxproj.filters +++ b/build/vc2013/nana.vcxproj.filters @@ -301,4 +301,9 @@ Source Files\nana\gui\widgets + + + Header Files + + \ No newline at end of file From b1db4b2e1467d7617641150a6d5dff246f409f91 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 23 May 2015 02:13:42 +0200 Subject: [PATCH 14/17] project for VS2015 --- build/vc2015/nana.sln | 28 +++ build/vc2015/nana.vcxproj | 266 +++++++++++++++++++++++++ build/vc2015/nana.vcxproj.filters | 312 ++++++++++++++++++++++++++++++ 3 files changed, 606 insertions(+) create mode 100644 build/vc2015/nana.sln create mode 100644 build/vc2015/nana.vcxproj create mode 100644 build/vc2015/nana.vcxproj.filters diff --git a/build/vc2015/nana.sln b/build/vc2015/nana.sln new file mode 100644 index 00000000..eab31ab5 --- /dev/null +++ b/build/vc2015/nana.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{25B21068-491B-4A9F-B99F-6C27BF31BAAD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x64.ActiveCfg = Debug|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x64.Build.0 = Debug|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x86.ActiveCfg = Debug|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x86.Build.0 = Debug|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.ActiveCfg = Release|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.Build.0 = Release|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x86.ActiveCfg = Release|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/vc2015/nana.vcxproj b/build/vc2015/nana.vcxproj new file mode 100644 index 00000000..94b72562 --- /dev/null +++ b/build/vc2015/nana.vcxproj @@ -0,0 +1,266 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {25B21068-491B-4A9F-B99F-6C27BF31BAAD} + Win32Proj + nana + 8.1 + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + ../bin/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + + + ../bin/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + true + false + + + Windows + true + + + $(TargetPath) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + + + $(TargetPath) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + + + Windows + true + true + true + + + $(TargetPath) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + Windows + true + true + true + + + $(TargetPath) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vc2015/nana.vcxproj.filters b/build/vc2015/nana.vcxproj.filters new file mode 100644 index 00000000..cb51dab8 --- /dev/null +++ b/build/vc2015/nana.vcxproj.filters @@ -0,0 +1,312 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {b0bd11b1-bcbb-4e05-885e-44295bc1a7bb} + + + {aab16aa3-c8d4-4495-8606-1b21ae739ee5} + + + {c395f107-7102-415b-a019-54e7cf3575af} + + + {e2569be2-9e68-477d-8b59-e248595de6c7} + + + {52ed7f8e-fa48-495e-af1f-4df013205a35} + + + {87d14798-9015-4162-b9ab-72c741cff063} + + + {4f8e7d23-9fe1-4409-bb03-2bd0809e606b} + + + {85c9c1bb-d87b-4481-bf3c-7425f680a12d} + + + {8058b530-86ec-4d72-890d-345aa30db056} + + + {87b124cb-408d-460b-a81b-8a788bbae0d9} + + + {b10db2f1-0542-421a-9e1d-4357e3be5f68} + + + {59f186c8-f5f8-4499-8e19-f278d4754220} + + + {5acf1733-47b2-4872-a105-66c7ad15cd39} + + + {a81fa10e-1274-44e0-92a0-434fa28f89ae} + + + {e95b4a72-643f-4416-af95-b0bbaf7f0c57} + + + + + Source Files\nana\audio\detail + + + Source Files\nana\audio\detail + + + Source Files\nana\audio\detail + + + Source Files\nana\audio + + + Source Files\nana\detail\win32 + + + Source Files\nana\filesystem + + + Source Files\nana\filesystem + + + Source Files\nana\gui\detail\win32 + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\widgets\skeletons + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\paint\detail + + + Source Files\nana\paint\detail + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\system + + + Source Files\nana\system + + + Source Files\nana\system + + + Source Files\nana\system + + + Source Files\nana\threads + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana + + + Source Files\nana\gui\detail + + + Source Files\nana\gui + + + Source Files\nana\gui\widgets + + + Source Files\nana\filesystem + + + + + Header Files + + + \ No newline at end of file From 42819c64c21dd164b564093237f9f519be7dc228 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 28 May 2015 16:43:14 +0200 Subject: [PATCH 15/17] eliminate noexept from our filesystem because a compiler without filesystem is not C++11 complete anyway We will go with noexeot when we will have std::filesystem... --- include/nana/config.hpp | 23 +++++++++++++-------- include/nana/filesystem/filesystem.hpp | 28 +++++++++++++------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/include/nana/config.hpp b/include/nana/config.hpp index fecf633f..58d1ffad 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -15,14 +15,21 @@ #if defined(_MSC_VER) -#if (_MSC_VER == 1900) - // google: break any code that tries to use codecvt or codecvt. - // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. - // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively. - // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. - // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. -#define STD_CODECVT_NOT_SUPPORTED -#endif // _MSC_VER == 1900 + #define _SCL_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_DEPRECATE + #pragma warning(disable : 4996) + #if (_MSC_VER < 1900) + // is this a good idea? + #define NOT_IMPLEMENTED_KEYWORD_noexcept + #endif // _MSC_VER < 1900 + #if (_MSC_VER == 1900) + // google: break any code that tries to use codecvt or codecvt. + // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. + // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively. + // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. + // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. + #define STD_CODECVT_NOT_SUPPORTED + #endif // _MSC_VER == 1900 #endif // _MSVC //Select platform automatically diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 658579fd..b00760d2 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -102,26 +102,26 @@ namespace filesystem perms m_prms = perms::unknown; public: - explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown) noexcept + explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown) :m_ft{ft}, m_prms{prms} {} - file_status(const file_status& fs) noexcept: m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; - file_status(file_status&& fs) noexcept: m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; + file_status(const file_status& fs) : m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; + file_status(file_status&& fs) : m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; ~file_status(){}; - file_status& operator=(const file_status&) noexcept = default; - file_status& operator=(file_status&&fs) noexcept // = default; + file_status& operator=(const file_status&) = default; + file_status& operator=(file_status&&fs) // = default; { m_ft=fs.m_ft; m_prms = fs.m_prms; return *this; } // observers - file_type type() const noexcept{ return m_ft;} - perms permissions() const noexcept{ return m_prms;} + file_type type() const { return m_ft;} + perms permissions() const { return m_prms;} // modifiers - void type (file_type ft) noexcept { m_ft=ft ;} - void permissions(perms prms) noexcept { m_prms = prms; } + void type (file_type ft) { m_ft=ft ;} + void permissions(perms prms) { m_prms = prms; } }; /// concerned only with lexical and syntactic aspects and does not necessarily exist in @@ -174,8 +174,8 @@ namespace filesystem //file_status status() const; - operator const path&() const noexcept{return m_path;}; - const path& path() const noexcept{return m_path;} + operator const path&() const {return m_path;}; + const path& path() const {return m_path;} }; @@ -219,8 +219,8 @@ namespace filesystem // enable directory_iterator range-based for statements - directory_iterator begin( ) noexcept { return *this; } - directory_iterator end( ) noexcept { return {}; } + directory_iterator begin( ) { return *this; } + directory_iterator end( ) { return {}; } private: template @@ -405,7 +405,7 @@ namespace filesystem // file_status status(const path& p); bool file_attrib(const nana::string& file, attribute&); - inline bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} + inline bool is_directory(file_status s) { return s.type() == file_type::directory ;} inline bool is_directory(const path& p) { return directory_iterator{ p }->attr.directory; }//works?? inline bool is_directory(const directory_entry& d) { return d.attr.directory; } //bool is_directory(const path& p, error_code& ec) noexcept; From 3157f5f0569de78d62b8a02d8624f51a9def7315 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 29 May 2015 15:37:11 +0200 Subject: [PATCH 16/17] progressbar with stop() --- include/nana/gui/widgets/progress.hpp | 5 +++++ source/gui/widgets/progress.cpp | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/nana/gui/widgets/progress.hpp b/include/nana/gui/widgets/progress.hpp index 91e58ab7..f7697d7e 100644 --- a/include/nana/gui/widgets/progress.hpp +++ b/include/nana/gui/widgets/progress.hpp @@ -30,6 +30,8 @@ namespace nana unsigned Max(unsigned); void unknown(bool); bool unknown() const; + bool stop(bool s = true); + bool stoped() const; private: void attached(widget_reference, graph_reference) override; void refresh(graph_reference) override; @@ -45,6 +47,7 @@ namespace nana nana::paint::graphics* graph_{nullptr}; unsigned draw_width_{static_cast(-1)}; bool unknown_{false}; + bool stop_{false}; unsigned max_{100}; unsigned value_{0}; }; //end class drawer @@ -67,6 +70,8 @@ namespace nana unsigned amount(unsigned value); void unknown(bool); bool unknown() const; + bool stop(bool s=true); ///< request stop or cancel and return previus stop status + bool stoped() const; }; }//end namespace nana #endif diff --git a/source/gui/widgets/progress.cpp b/source/gui/widgets/progress.cpp index 4459ddb1..e37b5814 100644 --- a/source/gui/widgets/progress.cpp +++ b/source/gui/widgets/progress.cpp @@ -89,6 +89,15 @@ namespace nana { return unknown_; } + bool trigger::stoped() const + { + return stop_; + } + bool trigger::stop(bool s) + { + std::swap(s,stop_); + return s; + } void trigger::refresh(graph_reference) { @@ -197,5 +206,13 @@ namespace nana { return get_drawer_trigger().unknown(); } + bool progress::stop(bool s) + { + return get_drawer_trigger().stop(s); + } + bool progress::stoped() const + { + return get_drawer_trigger().stoped(); + } //end class progress }//end namespace nana From e8ae11e20872363bc4c382168e18e333c5f75043 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 10 Jun 2015 06:53:58 +0800 Subject: [PATCH 17/17] fix a refreshing issue bad refreshing when a lite_widget is destroying if the lite_widget's parent is also a type of lite_widget --- include/nana/detail/win32/platform_spec.hpp | 7 +++ include/nana/gui/detail/bedrock.hpp | 2 +- include/nana/gui/detail/drawer.hpp | 2 +- include/nana/gui/detail/effects_renderer.hpp | 41 ++++++++++++-- include/nana/gui/detail/window_manager.hpp | 4 +- source/gui/detail/drawer.cpp | 12 ++-- source/gui/detail/linux_X11/bedrock.cpp | 2 +- source/gui/detail/win32/bedrock.cpp | 17 ++++-- source/gui/detail/window_manager.cpp | 58 +++++++++----------- 9 files changed, 96 insertions(+), 49 deletions(-) diff --git a/include/nana/detail/win32/platform_spec.hpp b/include/nana/detail/win32/platform_spec.hpp index 9e735f99..39f21366 100644 --- a/include/nana/detail/win32/platform_spec.hpp +++ b/include/nana/detail/win32/platform_spec.hpp @@ -55,6 +55,13 @@ namespace detail unsigned ignore; //determinate that pos or size would be ignored. }; + struct map_thread + { + rectangle update_area; + bool ignore_update_area; + bool forced; + }; + enum { tray = 0x501, diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 1ae2a41d..501a3c8c 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -42,7 +42,7 @@ namespace detail ~bedrock(); void pump_event(window, bool is_modal); - void map_thread_root_buffer(core_window_t*, bool forced); + void map_thread_root_buffer(core_window_t*, bool forced, const rectangle* update_area = nullptr); static int inc_window(unsigned tid = 0); thread_context* open_thread_context(unsigned tid = 0); thread_context* get_thread_context(unsigned tid = 0); diff --git a/include/nana/gui/detail/drawer.hpp b/include/nana/gui/detail/drawer.hpp index f6948a45..121c84b8 100644 --- a/include/nana/gui/detail/drawer.hpp +++ b/include/nana/gui/detail/drawer.hpp @@ -110,7 +110,7 @@ namespace nana void key_char(const arg_keyboard&); void key_release(const arg_keyboard&); void shortkey(const arg_keyboard&); - void map(window, bool forced); //Copy the root buffer to screen + void map(window, bool forced, const rectangle* update_area = nullptr); //Copy the root buffer to screen void refresh(); drawer_trigger* realizer() const; void attached(widget&, drawer_trigger&); diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp index 91daf849..b9b1b785 100644 --- a/include/nana/gui/detail/effects_renderer.hpp +++ b/include/nana/gui/detail/effects_renderer.hpp @@ -13,9 +13,9 @@ namespace nana{ { edge_nimbus_renderer() = default; public: - typedef CoreWindow core_window_t; - typedef window_layout window_layer; - typedef nana::paint::graphics & graph_reference; + using core_window_t = CoreWindow; + using window_layer = window_layout; + using graph_reference = ::nana::paint::graphics&; static edge_nimbus_renderer& instance() { @@ -28,7 +28,34 @@ namespace nana{ return 2; } - bool render(core_window_t * wd, bool forced) + void erase(core_window_t* wd) + { + if (effects::edge_nimbus::none == wd->effect.edge_nimbus) + return; + + core_window_t * root_wd = wd->root_widget; + auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + + for (auto i = nimbus.cbegin(); i != nimbus.cend(); ++i) + { + if (i->window == wd) + { + auto pixels = weight(); + rectangle r{wd->pos_root, wd->dimension}; + r.x -= static_cast(pixels); + r.y -= static_cast(pixels); + r.width += static_cast(pixels << 1); + r.height += static_cast(pixels << 1); + + root_wd->root_graph->paste(root_wd->root, r, r.x, r.y); + + nimbus.erase(i); + break; + } + } + } + + bool render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr) { bool rendered = false; core_window_t * root_wd = wd->root_widget; @@ -49,8 +76,12 @@ namespace nana{ { if(_m_edge_nimbus(focused, action.window) && window_layer::read_visual_rectangle(action.window, r)) { - if(action.window == wd) + if (action.window == wd) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(r), r); rendered = true; + } //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. if ((forced && (action.window == wd)) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh)) diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index 37c9c150..ba6aa451 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -150,9 +150,9 @@ namespace detail core_window_t* root(native_window_type) const; //Copy the root buffer that wnd specified into DeviceContext - void map(core_window_t*, bool forced); + void map(core_window_t*, bool forced, const rectangle* update_area = nullptr); - bool update(core_window_t*, bool redraw, bool force); + bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr); void refresh_tree(core_window_t*); bool do_lazy_refresh(core_window_t*, bool force_copy_to_screen); diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 3b9702a3..8c176b4b 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -240,7 +240,7 @@ namespace nana _m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey); } - void drawer::map(window wd, bool forced) //Copy the root buffer to screen + void drawer::map(window wd, bool forced, const rectangle* update_area) //Copy the root buffer to screen { if(wd) { @@ -262,11 +262,15 @@ namespace nana #endif } - if (false == edge_nimbus_renderer_t::instance().render(iwd, forced)) + if (false == edge_nimbus_renderer_t::instance().render(iwd, forced, update_area)) { - nana::rectangle vr; - if(bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr)) + rectangle vr; + if (bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr)) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(vr), vr); iwd->root_graph->paste(iwd->root, vr, vr.x, vr.y); + } } if(owns_caret) diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index 44ccef61..1a5a1ecc 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -167,7 +167,7 @@ namespace detail delete impl_; } - void bedrock::map_thread_root_buffer(core_window_t*, bool forced) + void bedrock::map_thread_root_buffer(core_window_t*, bool forced, const rectangle*) { //GUI in X11 is thread-independent, so no implementation. } diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 4a9d0f11..1bb25cc9 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -338,9 +338,14 @@ namespace detail return bedrock_object; } - void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced) + void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced, const rectangle* update_area) { - ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), static_cast(forced ? TRUE : FALSE)); + auto stru = reinterpret_cast(::HeapAlloc(::GetProcessHeap(), 0, sizeof(detail::messages::map_thread))); + if (stru) + { + if (FALSE == ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), reinterpret_cast(stru))) + ::HeapFree(::GetProcessHeap(), 0, stru); + } } void interior_helper_for_menu(MSG& msg, native_window_type menu_window) @@ -591,8 +596,12 @@ namespace detail } return true; case nana::detail::messages::map_thread_root_buffer: - bedrock.wd_manager.map(reinterpret_cast(wParam), (TRUE == lParam)); - ::UpdateWindow(wd); + { + auto stru = reinterpret_cast(lParam); + bedrock.wd_manager.map(reinterpret_cast(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area)); + ::UpdateWindow(wd); + ::HeapFree(::GetProcessHeap(), 0, stru); + } return true; case nana::detail::messages::remote_thread_move_window: { diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index b7719985..7f8da08b 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -372,21 +372,26 @@ namespace detail //@brief: Delete the window handle void window_manager::destroy(core_window_t* wd) { - core_window_t* parent = nullptr; + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd) == false) return; + + rectangle update_area(wd->pos_owner, wd->dimension); + + auto parent = wd->parent; + if (parent) + utl::erase(parent->children, wd); + + _m_destroy(wd); + + while (parent && (parent->other.category == ::nana::category::flags::lite_widget)) { - //Thread-Safe Required! - std::lock_guard lock(mutex_); - if (impl_->wd_register.available(wd) == false) return; - - if (wd->parent) - { - parent = wd->parent; - utl::erase(wd->parent->children, wd); - } - - _m_destroy(wd); + update_area.x += parent->pos_owner.x; + update_area.y += parent->pos_owner.y; + parent = parent->parent; } - update(parent, false, false); + + update(parent, false, false, &update_area); } //destroy_handle @@ -672,7 +677,7 @@ namespace detail } //Copy the root buffer that wnd specified into DeviceContext - void window_manager::map(core_window_t* wd, bool forced) + void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -680,12 +685,12 @@ namespace detail { //Copy the root buffer that wd specified into DeviceContext #if defined(NANA_LINUX) - wd->drawer.map(reinterpret_cast(wd), forced); + wd->drawer.map(reinterpret_cast(wd), forced, update_area); #elif defined(NANA_WINDOWS) if(nana::system::this_thread_id() == wd->thread_id) - wd->drawer.map(reinterpret_cast(wd), forced); + wd->drawer.map(reinterpret_cast(wd), forced, update_area); else - bedrock::instance().map_thread_root_buffer(wd, forced); + bedrock::instance().map_thread_root_buffer(wd, forced, update_area); #endif } } @@ -694,7 +699,7 @@ namespace detail //@brief: update is used for displaying the screen-off buffer. // Because of a good efficiency, if it is called in an event procedure and the event procedure window is the // same as update's, update would not map the screen-off buffer and just set the window for lazy refresh - bool window_manager::update(core_window_t* wd, bool redraw, bool forced) + bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -705,7 +710,7 @@ namespace detail if(forced || (false == wd->belong_to_lazy())) { wndlayout_type::paint(wd, redraw, false); - this->map(wd, forced); + this->map(wd, forced, update_area); } else { @@ -1252,18 +1257,9 @@ namespace detail if (!established) { - if (effects::edge_nimbus::none != wd->effect.edge_nimbus) - { - auto & cont = root_attr->effects_edge_nimbus; - for (auto i = cont.begin(); i != cont.end(); ++i) - { - if (i->window == wd) - { - cont.erase(i); - break; - } - } - } + //remove the window from edge nimbus effect when it is destroying + using edge_nimbus = detail::edge_nimbus_renderer; + edge_nimbus::instance().erase(wd); } else if (pa_root_attr != root_attr) {