vutils.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. #ifndef VUTILS_H
  2. #define VUTILS_H
  3. #include <QString>
  4. #include <QColor>
  5. #include <QVector>
  6. #include <QPair>
  7. #include <QMessageBox>
  8. #include <QUrl>
  9. #include <QDir>
  10. #include "vconfigmanager.h"
  11. #include "vconstants.h"
  12. class QKeyEvent;
  13. class VFile;
  14. class VOrphanFile;
  15. class VNotebook;
  16. class QWidget;
  17. class QComboBox;
  18. class QWebEngineView;
  19. #if !defined(V_ASSERT)
  20. #define V_ASSERT(cond) ((!(cond)) ? qt_assert(#cond, __FILE__, __LINE__) : qt_noop())
  21. #endif
  22. // Thanks to CGAL/cgal.
  23. #ifndef __has_attribute
  24. #define __has_attribute(x) 0 // Compatibility with non-clang compilers.
  25. #endif
  26. #ifndef __has_cpp_attribute
  27. #define __has_cpp_attribute(x) 0 // Compatibility with non-supporting compilers.
  28. #endif
  29. // The fallthrough attribute.
  30. // See for clang:
  31. // http://clang.llvm.org/docs/AttributeReference.html#statement-attributes
  32. // See for gcc:
  33. // https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
  34. #if __has_cpp_attribute(fallthrough)
  35. # define V_FALLTHROUGH [[fallthrough]]
  36. #elif __has_cpp_attribute(gnu::fallthrough)
  37. # define V_FALLTHROUGH [[gnu::fallthrough]]
  38. #elif __has_cpp_attribute(clang::fallthrough)
  39. # define V_FALLTHROUGH [[clang::fallthrough]]
  40. #elif __has_attribute(fallthrough) && ! __clang__
  41. # define V_FALLTHROUGH __attribute__ ((fallthrough))
  42. #else
  43. # define V_FALLTHROUGH while(false){}
  44. #endif
  45. enum class MessageBoxType
  46. {
  47. Normal = 0,
  48. Danger = 1
  49. };
  50. struct ImageLink
  51. {
  52. enum ImageLinkType
  53. {
  54. LocalRelativeInternal = 0x1,
  55. LocalRelativeExternal = 0x2,
  56. LocalAbsolute = 0x4,
  57. Resource = 0x8,
  58. Remote = 0x10,
  59. All = 0xffff
  60. };
  61. QString m_path;
  62. // The url text in the link.
  63. QString m_url;
  64. ImageLinkType m_type;
  65. };
  66. class VUtils
  67. {
  68. public:
  69. static QString readFileFromDisk(const QString &filePath);
  70. static bool writeFileToDisk(const QString &filePath, const QString &text);
  71. static bool writeJsonToDisk(const QString &p_filePath, const QJsonObject &p_json);
  72. static QJsonObject readJsonFromDisk(const QString &p_filePath);
  73. static QString generateImageFileName(const QString &path, const QString &title,
  74. const QString &format = "png");
  75. // Given the file name @p_fileName and directory path @p_dirPath, generate
  76. // a file name based on @p_fileName which does not exist in @p_dirPath.
  77. // @p_completeBaseName: use complete base name or complete suffix. For example,
  78. // "abc.tar.gz", if @p_completeBaseName is true, the base name is "abc.tar",
  79. // otherwise, it is "abc".
  80. static QString generateCopiedFileName(const QString &p_dirPath,
  81. const QString &p_fileName,
  82. bool p_completeBaseName = true);
  83. // Given the directory name @p_dirName and directory path @p_parentDirPath,
  84. // generate a directory name based on @p_dirName which does not exist in
  85. // @p_parentDirPath.
  86. static QString generateCopiedDirName(const QString &p_parentDirPath,
  87. const QString &p_dirName);
  88. // Return the last directory name of @p_path.
  89. static QString directoryNameFromPath(const QString& p_path);
  90. // Return the file name of @p_path.
  91. // /home/tamlok/abc, /home/tamlok/abc/ will both return abc.
  92. static QString fileNameFromPath(const QString &p_path);
  93. // Return the base path of @p_path.
  94. // /home/tamlok/abc, /home/tamlok/abc/ will both return /home/tamlok.
  95. static QString basePathFromPath(const QString &p_path);
  96. // Fetch all the image links in markdown file p_file.
  97. // @p_type to filter the links returned.
  98. // Need to open p_file and will close it if it is originally closed.
  99. static QVector<ImageLink> fetchImagesFromMarkdownFile(VFile *p_file,
  100. ImageLink::ImageLinkType p_type = ImageLink::All);
  101. // Return the absolute path of @p_url according to @p_basePath.
  102. static QString imageLinkUrlToPath(const QString &p_basePath, const QString &p_url);
  103. // Create directories along the @p_path.
  104. // @p_path could be /home/tamlok/abc, /home/tamlok/abc/.
  105. static bool makePath(const QString &p_path);
  106. // Return QJsonObject if there is valid Json string in clipboard.
  107. // Return empty object if there is no valid Json string.
  108. static QJsonObject clipboardToJson();
  109. // Get the operation type in system's clipboard.
  110. static ClipboardOpType operationInClipboard();
  111. static ClipboardOpType opTypeInClipboard() { return ClipboardOpType::Invalid; }
  112. // Copy file @p_srcFilePath to @p_destFilePath.
  113. // Will make necessary parent directory along the destination path.
  114. static bool copyFile(const QString &p_srcFilePath, const QString &p_destFilePath, bool p_isCut);
  115. // Copy @p_srcDirPath to be @p_destDirPath.
  116. // @p_destDirPath should not exist.
  117. // Will make necessary parent directory along the destination path.
  118. static bool copyDirectory(const QString &p_srcDirPath, const QString &p_destDirPath, bool p_isCut);
  119. static int showMessage(QMessageBox::Icon p_icon, const QString &p_title, const QString &p_text,
  120. const QString &p_infoText, QMessageBox::StandardButtons p_buttons,
  121. QMessageBox::StandardButton p_defaultBtn, QWidget *p_parent,
  122. MessageBoxType p_type = MessageBoxType::Normal);
  123. static const QVector<QPair<QString, QString> > &getAvailableLanguages();
  124. static bool isValidLanguage(const QString &p_lang);
  125. static bool isImageURL(const QUrl &p_url);
  126. static bool isImageURLText(const QString &p_url);
  127. static qreal calculateScaleFactor();
  128. static bool realEqual(qreal p_a, qreal p_b);
  129. static QChar keyToChar(int p_key);
  130. static QString getLocale();
  131. static void sleepWait(int p_milliseconds);
  132. // Return the DocType according to suffix.
  133. static DocType docTypeFromName(const QString &p_name);
  134. // Generate HTML template.
  135. static QString generateHtmlTemplate(MarkdownConverterType p_conType);
  136. // @p_renderBg is the background name.
  137. static QString generateHtmlTemplate(MarkdownConverterType p_conType,
  138. const QString &p_renderBg,
  139. const QString &p_renderStyle,
  140. const QString &p_renderCodeBlockStyle,
  141. bool p_isPDF);
  142. static QString generateSimpleHtmlTemplate(const QString &p_body);
  143. // Get an available file name in @p_directory with base @p_baseFileName.
  144. // If there already exists a file named @p_baseFileName, try to add sequence
  145. // suffix to the name, such as _001.
  146. // @p_completeBaseName: use complete base name or complete suffix. For example,
  147. // "abc.tar.gz", if @p_completeBaseName is true, the base name is "abc.tar",
  148. // otherwise, it is "abc".
  149. static QString getFileNameWithSequence(const QString &p_directory,
  150. const QString &p_baseFileName,
  151. bool p_completeBaseName = true);
  152. // Get an available directory name in @p_directory with base @p_baseDirName.
  153. // If there already exists a file named @p_baseFileName, try to add sequence
  154. // suffix to the name, such as _001.
  155. static QString getDirNameWithSequence(const QString &p_directory,
  156. const QString &p_baseDirName);
  157. // Get an available random file name in @p_directory.
  158. static QString getRandomFileName(const QString &p_directory);
  159. // Try to check if @p_path is legal.
  160. static bool checkPathLegal(const QString &p_path);
  161. // Check if file/folder name is legal.
  162. static bool checkFileNameLegal(const QString &p_name);
  163. // Returns true if @p_patha and @p_pathb points to the same file/directory.
  164. static bool equalPath(const QString &p_patha, const QString &p_pathb);
  165. // Try to split @p_path into multiple parts based on @p_base.
  166. // Returns false if @p_path is not under @p_base directory.
  167. // @p_parts will be empty if @p_path is right @p_base.
  168. // Example: "/home/tamlok/study", "/home/tamlok/study/a/b/c/vnote.md"
  169. // returns true and @p_parts is {a, b, c, vnote.md}.
  170. static bool splitPathInBasePath(const QString &p_base,
  171. const QString &p_path,
  172. QStringList &p_parts);
  173. // Decode URL by simply replacing meta-characters.
  174. static void decodeUrl(QString &p_url);
  175. // Returns the shortcut text.
  176. static QString getShortcutText(const QString &p_keySeq);
  177. // Delete directory recursively specified by @p_path.
  178. // Will just move the directory to the recycle bin of @p_notebook if
  179. // @p_skipRecycleBin is false.
  180. static bool deleteDirectory(const VNotebook *p_notebook,
  181. const QString &p_path,
  182. bool p_skipRecycleBin = false);
  183. static bool deleteDirectory(const QString &p_path);
  184. // Empty all files in directory recursively specified by @p_path.
  185. // Will just move files to the recycle bin of @p_notebook if
  186. // @p_skipRecycleBin is false.
  187. static bool emptyDirectory(const VNotebook *p_notebook,
  188. const QString &p_path,
  189. bool p_skipRecycleBin = false);
  190. // Delete file specified by @p_path.
  191. // Will just move the file to the recycle bin of @p_notebook if
  192. // @p_skipRecycleBin is false.
  193. static bool deleteFile(const VNotebook *p_notebook,
  194. const QString &p_path,
  195. bool p_skipRecycleBin = false);
  196. // Delete file specified by @p_path.
  197. // Will just move the file to the recycle bin of VOrphanFile if
  198. // @p_skipRecycleBin is false.
  199. static bool deleteFile(const VOrphanFile *p_file,
  200. const QString &p_path,
  201. bool p_skipRecycleBin = false);
  202. // Delete file specified by @p_path.
  203. static bool deleteFile(const QString &p_path);
  204. static QString displayDateTime(const QDateTime &p_dateTime);
  205. // Check if file @p_name exists in @p_dir.
  206. // @p_forceCaseInsensitive: if true, will check the name ignoring the case.
  207. static bool fileExists(const QDir &p_dir, const QString &p_name, bool p_forceCaseInsensitive = false);
  208. // Assign @p_str to @p_msg if it is not NULL.
  209. static void addErrMsg(QString *p_msg, const QString &p_str);
  210. // Check each file of @p_files and return valid ones for VNote to open.
  211. static QStringList filterFilePathsToOpen(const QStringList &p_files);
  212. // Return the normalized file path of @p_file if it is valid to open.
  213. // Return empty if it is not valid.
  214. static QString validFilePathToOpen(const QString &p_file);
  215. // See if @p_modifiers is Control which is different on macOs and Windows.
  216. static bool isControlModifierForVim(int p_modifiers);
  217. // If @p_file does not exists, create an empty file.
  218. static void touchFile(const QString &p_file);
  219. // Ctrl, Meta, Shift, Alt.
  220. static bool isMetaKey(int p_key);
  221. // Create and return a QComboBox.
  222. static QComboBox *getComboBox(QWidget *p_parent = nullptr);
  223. static QWebEngineView *getWebEngineView(QWidget *p_parent = nullptr);
  224. static void setDynamicProperty(QWidget *p_widget, const char *p_prop, bool p_val = true);
  225. // Return a file name with locale @p_locale.
  226. // If @p_locale is empty, use system's locale instead.
  227. static QString getFileNameWithLocale(const QString &p_name,
  228. const QString &p_locale = QString());
  229. // Return a doc file path.
  230. static QString getDocFile(const QString &p_name);
  231. static QString getCaptainShortcutSequenceText(const QString &p_operation);
  232. static QString getAvailableFontFamily(const QStringList &p_families);
  233. // Regular expression for image link.
  234. // ![image title]( http://github.com/tamlok/vnote.jpg "alt \" text" )
  235. // Captured texts (need to be trimmed):
  236. // 1. Image Alt Text (Title);
  237. // 2. Image URL;
  238. // 3. Image Optional Title with double quotes;
  239. // 4. Unused;
  240. static const QString c_imageLinkRegExp;
  241. // Regular expression for image title.
  242. static const QString c_imageTitleRegExp;
  243. // Regular expression for file/directory name.
  244. // Forbidden char: \/:*?"<>|
  245. static const QString c_fileNameRegExp;
  246. // Regular expression for fenced code block.
  247. static const QString c_fencedCodeBlockStartRegExp;
  248. static const QString c_fencedCodeBlockEndRegExp;
  249. // Regular expression for preview image block.
  250. static const QString c_previewImageBlockRegExp;
  251. // Regular expression for header block.
  252. // Captured texts:
  253. // 1. Header marker (##);
  254. // 2. Header Title (need to be trimmed);
  255. // 3. Header Sequence (1.1., 1.2., optional);
  256. // 4. Unused;
  257. static const QString c_headerRegExp;
  258. // Regular expression for header block.
  259. // Captured texts:
  260. // 1. prefix till the real header title content;
  261. static const QString c_headerPrefixRegExp;
  262. private:
  263. VUtils() {}
  264. static void initAvailableLanguage();
  265. // Use HGMarkdownParser to parse @p_content to get all image link regions.
  266. static QVector<VElementRegion> fetchImageRegionsUsingParser(const QString &p_content);
  267. // Delete file/directory specified by @p_path by moving it to the recycle bin
  268. // folder @p_recycleBinFolderPath.
  269. static bool deleteFile(const QString &p_recycleBinFolderPath,
  270. const QString &p_path);
  271. static QString generateHtmlTemplate(const QString &p_template,
  272. MarkdownConverterType p_conType);
  273. // <value, name>
  274. static QVector<QPair<QString, QString>> s_availableLanguages;
  275. };
  276. inline QString VUtils::directoryNameFromPath(const QString &p_path)
  277. {
  278. return fileNameFromPath(p_path);
  279. }
  280. #endif // VUTILS_H