Compare commits

...

25 Commits

Author SHA1 Message Date
Markus Koch 0d4a9c9c36 ArchLinux PKGBUILD: Update Git repository URL 2021-04-20 21:30:42 +02:00
Markus Koch 65d12ae9e0 Stop decryption for all encrypted files when cancel is pressed 2021-01-03 14:19:23 +01:00
Markus Koch 21206d4e3e Fix bug not allowing more than 5 directories 2018-07-29 12:30:51 +02:00
Markus Koch 3064eae049 Correct alignment of meta block in template
That way, it is rendered as <pre> by markdown.
2018-07-21 15:13:37 +02:00
Markus Koch e4f711b310 Add button to open the workspace directory to the settings window 2018-07-14 17:41:29 +02:00
Markus Koch be80d71b09 Update to latest version of Glade 2018-07-14 17:38:19 +02:00
Markus Koch c702e7ca6e Merge remote-tracking branch 'origin/mdrework' 2018-07-09 18:59:29 +02:00
Markus Koch f6a7a22b7f Update copyright notice in README 2018-07-08 09:17:43 +02:00
Markus Koch f701119233 Update ArchLinux PKGBUILD to clone submodules 2018-07-08 09:16:29 +02:00
Markus Koch 017e6e8b9a Refactor code
Rename add_tags to autotags.
2018-07-07 11:28:51 +02:00
Markus Koch a3173fa1d8 Add encrypted tag to decrypted files 2018-07-07 11:25:02 +02:00
Markus Koch 8678f326cd Fix memory leak in scanner 2018-07-07 09:35:38 +02:00
Markus Koch 843329331d Automatically add tags for directory names 2018-07-07 09:31:13 +02:00
Markus Koch 16c3dcac15 Change Markdown renderer to statically link hoedown 2018-04-07 19:47:22 +02:00
Markus Koch 1287949669 Show an error message if the entry already exists or can not be created. 2018-03-25 18:38:54 +02:00
Markus Koch 8cee5b5188 pango_md: Remove linebreaks within a paragraph 2018-03-25 09:42:40 +02:00
Markus Koch a6a3967940 Fix md_pango renderer which broke lists 2018-03-24 16:08:23 +01:00
Markus Koch 3ba42da401 Only enable the New Entry button when in a valid workspace 2018-03-18 13:54:47 +01:00
Markus Koch 75155331ea Add ArchLinux PKGBUILD 2018-03-17 18:26:40 +01:00
Markus Koch df3fd1d5a3 Fix Desktop file 2018-03-17 18:26:11 +01:00
Markus Koch a5e5cd7667 Add Desktop file and icon 2018-03-17 18:08:35 +01:00
Markus Koch 21b3836dc0 Add install target 2018-03-17 17:42:17 +01:00
Markus Koch 30569fe1a5 Include glade file in binary 2018-03-17 17:38:32 +01:00
Markus Koch a9b9232dd5 Merge branch 'newfile' 2018-03-17 15:44:39 +01:00
Markus Koch 6555b8d8e2 Allow to click on heading to ellipsize it 2017-09-02 10:48:14 +02:00
16 changed files with 416 additions and 150 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "src/hoedown"]
path = src/hoedown
url = git@github.com:hoedown/hoedown.git

View File

@ -14,6 +14,28 @@ INCLUDE_DIRECTORIES (${GLIB2_INCLUDE_DIRS} ${GOBJECT2_INCLUDE_DIRS} ${GTK3_INCLU
LINK_DIRECTORIES (${GLIB2_LIBRARY_DIRS} ${GOBJECT2_LIBRARY_DIRS} ${GTK3_LIBRARY_DIRS} ${WEBKIT_LIBRARY_DIRS})
add_definitions(${GLIB2_CFLAGS_OTHER} ${GOBJECT2_CFLAGS_OTHER} ${GTK3_CFLAGS_OTHER} ${WEBKIT_CFLAGS_OTHER})
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/resources.c"
COMMAND glib-compile-resources "${CMAKE_CURRENT_SOURCE_DIR}/mdiary.gresource.xml" --target="${CMAKE_CURRENT_BINARY_DIR}/resources.c" --generate-source
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/glade/mainWindow.glade" "${CMAKE_CURRENT_SOURCE_DIR}/mdiary.gresource.xml"
COMMENT "Generating resources"
)
add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/hoedown/libhoedown.a"
COMMAND make libhoedown.a
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/hoedown"
COMMENT "Compiling libhoedown"
)
ADD_LIBRARY(HOEDOWN STATIC IMPORTED)
SET_TARGET_PROPERTIES(HOEDOWN PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/src/hoedown/libhoedown.a"
)
aux_source_directory(./src SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} ${GTK3_LIBRARIES} ${WEBKIT_LIBRARIES})
target_sources(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/resources.c")
target_sources(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src/hoedown/libhoedown.a")
target_link_libraries(${PROJECT_NAME} ${GTK3_LIBRARIES} ${WEBKIT_LIBRARIES} HOEDOWN)
install (TARGETS ${PROJECT_NAME} DESTINATION bin)

View File

@ -2,7 +2,7 @@
A viewer for a file based diary with entries written in markdown.
## License
Copyright (C) 2017 Markus Koch <markus@notsyncing.net>
Copyright (C) 2018 Markus Koch <markus@notsyncing.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 2 as

View File

@ -13,7 +13,7 @@ Renders everything as is. You will see the source code except for the header abo
The following constructs are supported: *italics*, **bold**, Headings 1 to 4.
## Full HTML with Images
As the external md command is invoked and a web browser used to render the content, all markdown syntax supported by the md command is supported.
Markdown is rendered using [Hoedown](https://github.com/hoedown/hoedown/) and displayed using an integrated web browser. This all Markdown syntax (including images) are supported.
# Encrypted Entries Using GPG
MDiary supports gpg encrypted entries. To use this feature, place a gpg encrypted entry as *<name>.md.gpg* in the workspace. MDiary will automatically show a decrypt button in the header bar which will invoke gpg to decrypt all encrypted entries in the workspace for this session.

45
dist/archlinux/PKGBUILD vendored Normal file
View File

@ -0,0 +1,45 @@
# $Id$
# Maintainer: Markus Koch <markus@notsyncing.net>
pkgname=mdiary-git
pkgver=20180708.137.017e6e8
pkgrel=1
pkgdesc='A viewer for a file based diary with entries written in markdown.'
arch=('i686' 'x86_64')
url='https://git.notsyncing.net:8080/markus/mdiary'
license=('GPL')
depends=('gtk3' 'glib2' 'webkit2gtk')
makedepends=('cmake')
source=("$pkgname"::"git+https://git.notsyncing.net/markus/mdiary.git")
sha1sums=('SKIP')
pkgver () {
_date=`date +"%Y%m%d"`
cd "${srcdir}/${pkgname}"
echo "$_date.$(git rev-list --count master).$(git rev-parse --short master)"
}
prepare() {
cd $pkgname
git submodule init
git submodule update
}
build() {
cd "$srcdir/$pkgname"
cmake .
make
}
package() {
cd "$srcdir/$pkgname"
make DESTDIR="${pkgdir}" install
install -D -m644 "$srcdir/$pkgname/dist/mdiary.svg" \
"$pkgdir/usr/share/icons/hicolor/scalable/apps/mdiary.svg"
install -D -m644 "$srcdir/$pkgname/dist/mdiary.desktop" \
"$pkgdir/usr/share/applications/mdiary.desktop"
}

10
dist/mdiary.desktop vendored Normal file
View File

@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=MDiary
GenericName=Markdown Diary Viewer
Comment=A viewer for a file based diary with entries written in markdown.
Icon=mdiary
StartupNotify=true
Exec=mdiary
Categories=Office

BIN
dist/mdiary.dia vendored Normal file

Binary file not shown.

31
dist/mdiary.svg vendored Normal file
View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="406pt" height="296pt" viewBox="0 0 406 296" version="1.1">
<g id="surface660378">
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -15 16 C -11.8 17.333398 -8.2 17.333398 -5 16 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -5 16 C -1.8 17.333398 1.8 17.333398 5 16 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -15 29 C -11.8 30.333398 -8.2 30.333398 -5 29 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -5 29 C -1.8 30.333398 1.8 30.333398 5 29 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -5 29 L -5 15.5 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 5 15.5 L 5 29 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -15 29 L -15 15.5 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -5 15.5 C -1.8 16.833398 1.8 16.833398 5 15.5 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -15 15.5 C -11.8 16.833398 -8.2 16.833398 -5 15.5 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14 18 C -13.407617 18.407422 -12.717188 18.649023 -12 18.7 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14 19 C -11.5 20.333398 -8.5 20.333398 -6 19 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14 20 C -12.061523 21.140039 -9.716602 21.359961 -7.6 20.6 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14 21 C -11.5 22.333398 -8.5 22.333398 -6 21 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14 22 C -11.830469 23.107422 -9.304883 23.287695 -7 22.5 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14 23 C -11.5 24.333398 -8.5 24.333398 -6 23 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14 24 C -11.5 25.333398 -8.5 25.333398 -6 24 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14 25 C -11.5 26.333398 -8.5 26.333398 -6 25 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -4 19 C -1.5 20.333398 1.5 20.333398 4 19 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -4 20 C -1.5 21.333398 1.5 21.333398 4 20 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -4 21 C -1.5 22.333398 1.5 22.333398 4 21 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -4 22 C -1.5 23.333398 1.5 23.333398 4 22 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -4 23 C -1.5 24.333398 1.5 24.333398 4 23 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -4 18 C -3.407617 18.407422 -2.717188 18.649023 -2 18.7 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -4 24 C -2.790234 24.710156 -1.401758 25.057422 -0.00000000596046 25 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14 28.5 C -13.818359 28.612695 -13.612891 28.68125 -13.4 28.7 " transform="matrix(20,0,0,20,303,-307)"/>
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 3.2 28.2 C 3.476562 28.181836 3.747461 28.114258 4 28 " transform="matrix(20,0,0,20,303,-307)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.4 -->
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkTextBuffer" id="entryTextBuffer"/>
@ -78,6 +78,93 @@
<property name="width_request">720</property>
<property name="height_request">405</property>
<property name="can_focus">False</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerBar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title">MDiary</property>
<property name="subtitle">No workspace opened.</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="popover">popoverWorkspace</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Choose Workspace</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">pan-down-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="buttonNew">
<property name="label" translatable="yes">New Entry</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="buttonDecrypt">
<property name="label" translatable="yes">Decrypt GPG</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">imageDecrypt</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPaned" id="mainPane">
<property name="visible">True</property>
@ -318,15 +405,20 @@
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<child>
<object class="GtkLabel" id="labelSummary">
<object class="GtkEventBox" id="summaryEventBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please select an entry in the list above.</property>
<property name="wrap">True</property>
<property name="wrap_mode">word-char</property>
<attributes>
<attribute name="scale" value="1.3999999999999999"/>
</attributes>
<child>
<object class="GtkLabel" id="labelSummary">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please select an entry in the list above.</property>
<property name="wrap">True</property>
<attributes>
<attribute name="scale" value="1.3999999999999999"/>
</attributes>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
@ -404,93 +496,6 @@
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerBar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title">MDiary</property>
<property name="subtitle">No workspace opened.</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="popover">popoverWorkspace</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Choose Workspace</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">pan-down-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="buttonDecrypt">
<property name="label" translatable="yes">Decrypt GPG</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">imageDecrypt</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="buttonNew">
<property name="label" translatable="yes">New Entry</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="GtkPopover" id="popoverDate">
<property name="can_focus">False</property>
@ -509,6 +514,19 @@
<property name="can_focus">False</property>
<property name="window_position">center</property>
<property name="destroy_with_parent">True</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title">Preferences</property>
<property name="has_subtitle">False</property>
<property name="show_close_button">True</property>
<property name="decoration_layout">close:</property>
<child>
<placeholder/>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
@ -622,18 +640,18 @@
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title">Preferences</property>
<property name="has_subtitle">False</property>
<property name="show_close_button">True</property>
<property name="decoration_layout">close:</property>
<child>
<placeholder/>
<object class="GtkButton" id="buttonOpenWorkspaceFolder">
<property name="label" translatable="yes">Open Workspace in File Browser</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>

6
mdiary.gresource.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/mdiary">
<file preprocess="xml-stripblanks">glade/mainWindow.glade</file>
</gresource>
</gresources>

1
src/hoedown Submodule

@ -0,0 +1 @@
Subproject commit 980b9c549b4348d50b683ecee6abee470b98acda

View File

@ -2,10 +2,10 @@
#include "mdiary.h"
const gchar *default_template[] = {"# Title\n"
"Date: ", "\0",
" Date: ", "\0",
"\n"
"Summary: \n"
"Tags: \n"
" Summary: \n"
" Tags: \n"
"\n"
"Text",
NULL};
@ -425,6 +425,11 @@ static void mainWindow_connect_signals(struct mainWindow *mainWindow)
"clicked",
(GCallback) mainWindow_decrypt_gpg_clicked,
mainWindow);
g_signal_connect(mainWindow->summaryEventBox,
"button-press-event",
(GCallback) mainWindow_toggleSummaryWrap,
mainWindow);
}
/**
@ -522,6 +527,13 @@ static void mainWindow_settings_buttonCustomNewFileDateFormat_clicked(GtkComboBo
}
}
static void mainWindow_settings_buttonOpenWorkspaceFolder_clicked(GtkComboBox *widget, gpointer user_data)
{
struct mainWindow *mainWindow = (struct mainWindow *)user_data;
mainWindow_openExternalEditor(mainWindow->currentWorkspaceUrl);
}
const gchar *newDateFormats[] = {"%d.%m.%Y %H:%M",
"%Y-%m-%d %H:%M",
NULL};
@ -600,6 +612,11 @@ static void mainWindow_configure_settings_dialog(struct mainWindow *mainWindow)
(GCallback) mainWindow_settings_buttonCustomNewFileDateFormat_clicked,
mainWindow);
g_signal_connect(mainWindow->settingsDialog.buttonOpenWorkspaceFolder,
"clicked",
(GCallback) mainWindow_settings_buttonOpenWorkspaceFolder_clicked,
mainWindow);
g_signal_connect(mainWindow->settingsDialog.settingsDialog,
"delete-event",
(GCallback) mainWindow_settings_delete_event,
@ -615,7 +632,7 @@ struct mainWindow *mainWindow_new()
GtkBuilder *builder;
struct mainWindow *mainWindow;
builder = gtk_builder_new_from_file("glade/mainWindow.glade");
builder = gtk_builder_new_from_resource("/org/gtk/mdiary/glade/mainWindow.glade");
mainWindow = malloc(sizeof(struct mainWindow));
mainWindow->mainWindow = GTK_WIDGET(gtk_builder_get_object(builder, "mainWindow"));
@ -631,6 +648,7 @@ struct mainWindow *mainWindow_new()
mainWindow->checkSearchSummary = GTK_WIDGET(gtk_builder_get_object(builder, "checkSearchSummary"));
mainWindow->checkSearchTags = GTK_WIDGET(gtk_builder_get_object(builder, "checkSearchTags"));
mainWindow->checkSearchText = GTK_WIDGET(gtk_builder_get_object(builder, "checkSearchText"));
mainWindow->summaryEventBox = GTK_WIDGET(gtk_builder_get_object(builder, "summaryEventBox"));
mainWindow->labelSummary = GTK_WIDGET(gtk_builder_get_object(builder, "labelSummary"));
mainWindow->buttonClearSearch = GTK_WIDGET(gtk_builder_get_object(builder, "buttonClearSearch"));
mainWindow->headerBar = GTK_WIDGET(gtk_builder_get_object(builder, "headerBar"));
@ -658,6 +676,7 @@ struct mainWindow *mainWindow_new()
mainWindow->settingsDialog.stackNewDateFormat = GTK_WIDGET(gtk_builder_get_object(builder, "stackNewDateFormat"));
mainWindow->settingsDialog.entryNewDateFormat = GTK_WIDGET(gtk_builder_get_object(builder, "entryNewDateFormat"));
mainWindow->settingsDialog.buttonCustomNewFileDateFormat = GTK_WIDGET(gtk_builder_get_object(builder, "buttonCustomNewFileDateFormat"));
mainWindow->settingsDialog.buttonOpenWorkspaceFolder = GTK_WIDGET(gtk_builder_get_object(builder, "buttonOpenWorkspaceFolder"));
mainWindow->filterSettings.time_start = 0;
mainWindow->filterSettings.time_end = -1;
@ -705,6 +724,8 @@ void mainWindow_set_meta_information(struct mainWindow *mainWindow,
mainWindow->time_latest = time_latest;
mainWindow->filterSettings.hide_all = hide_all;
gtk_widget_set_sensitive(mainWindow->mainPane, !hide_all);
gtk_widget_set_sensitive(mainWindow->settingsDialog.buttonOpenWorkspaceFolder,
!hide_all);
mainWindow_clearSearch(NULL, mainWindow);
}
@ -765,16 +786,18 @@ void mainWindow_calendarSelected(GtkWidget *widget, gpointer user_data)
static void mainWindow_set_text(struct mainWindow *mainWindow, gchar *text, gchar *file_url)
{
gchar *tempfile_path = "/tmp/mdiary.tmp.md";
gchar *cmd = NULL;
gchar *cmd_stdout = NULL;
gchar *cmd_stderr = NULL;
gint exit_status = 0;
gchar *base_url = NULL;
GFileOutputStream *stream = NULL;
GFile *file = NULL;
GtkTextIter iter;
GtkTextIter iter_end;
hoedown_buffer *ob;
hoedown_renderer *renderer = NULL;
void (*renderer_free)(hoedown_renderer *) = NULL;
hoedown_document *document;
gchar *base_url = NULL;
if (mainWindow->renderer == RENDERER_TEXT) {
gtk_text_buffer_set_text(mainWindow->textBuffer, text, strlen(text));
@ -796,24 +819,21 @@ static void mainWindow_set_text(struct mainWindow *mainWindow, gchar *text, gcha
} else {
if (text[0] != '\0') {
base_url = g_strdup_printf("file://%s", file_url);
file = g_file_new_for_path(tempfile_path);
stream = g_file_replace(
file, NULL, FALSE,
G_FILE_CREATE_NONE,
NULL, NULL);
g_output_stream_write(G_OUTPUT_STREAM(stream), text, strlen(text), NULL, NULL);
g_output_stream_flush(G_OUTPUT_STREAM(stream), NULL, NULL);
g_info("Rendering markdown as full HTML...");
cmd = g_strdup_printf("markdown %s", tempfile_path);
if (g_spawn_command_line_sync(cmd, &cmd_stdout, &cmd_stderr, &exit_status, NULL) &&
exit_status == 0) {
webkit_web_view_load_html(WEBKIT_WEB_VIEW(mainWindow->webkitView),
cmd_stdout, base_url);
} else {
g_warning("Could not render markdown for file. Showing plain text instead.\n");
webkit_web_view_load_html(WEBKIT_WEB_VIEW(mainWindow->webkitView),
text, base_url);
}
renderer = hoedown_html_renderer_new(0, 0);
renderer_free = hoedown_html_renderer_free;
ob = hoedown_buffer_new(64);
document = hoedown_document_new(renderer, 0, 16);
hoedown_document_render(document, ob, (const uint8_t *) text, strlen(text));
webkit_web_view_load_html(WEBKIT_WEB_VIEW(mainWindow->webkitView),
hoedown_buffer_cstr(ob), base_url);
hoedown_buffer_free(ob);
hoedown_document_free(document);
renderer_free(renderer);
g_free(base_url);
} else {
webkit_web_view_load_html(WEBKIT_WEB_VIEW(mainWindow->webkitView),
@ -1044,6 +1064,20 @@ static void mainWindow_show_error(struct mainWindow *mainWindow, gchar *text)
gtk_widget_destroy(dialog);
}
static void mainWindow_show_info(struct mainWindow *mainWindow, gchar *text)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new(GTK_WINDOW(mainWindow->mainWindow),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
"%s",
text);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
void mainWindow_switch_workspace(struct mainWindow *mainWindow, gchar *path, gboolean gpg_enabled)
{
struct mdiary_scanner *mdiary_scanner;
@ -1080,8 +1114,25 @@ void mainWindow_switch_workspace(struct mainWindow *mainWindow, gchar *path, gbo
g_free(temp);
}
} else {
gtk_header_bar_set_subtitle(GTK_HEADER_BAR(mainWindow->headerBar), "No workspace opened.");
mainWindow_show_error(mainWindow, "Could not open workspace or no entries were found in it.");
if (mdiary_scanner->error_code & MDS_ERROR_GPG) {
NULL; /* Handled in scanner */
} else if (mdiary_scanner->error_code == 0) {
mainWindow_show_info(mainWindow, "This workspace is empty. Use the New Entry button to create the first entry.");
} else {
mainWindow_show_error(mainWindow, "Could not open workspace. Please choose a different directory.");
g_free(mainWindow->currentWorkspaceUrl);
mainWindow->currentWorkspaceUrl = NULL;
}
}
if (mainWindow->currentWorkspaceUrl) {
gtk_header_bar_set_subtitle(GTK_HEADER_BAR(mainWindow->headerBar),
mainWindow->currentWorkspaceUrl);
gtk_widget_set_sensitive(mainWindow->buttonNew, 1);
} else {
gtk_header_bar_set_subtitle(GTK_HEADER_BAR(mainWindow->headerBar),
"No workspace opened.");
gtk_widget_set_sensitive(mainWindow->buttonNew, 0);
}
mdiary_scanner_free(mdiary_scanner);
}
@ -1186,6 +1237,8 @@ void mainWindow_new_entry_clicked(GtkWidget *widget, gpointer user_data)
if (fd) {
fclose(fd);
g_warning("File '%s' already exists.", path);
mainWindow_show_info(mainWindow, "This entry already exists. Opening existing file instead.");
mainWindow_openExternalEditor(path);
} else {
fd = fopen(path, "w");
if (fd) {
@ -1202,6 +1255,7 @@ void mainWindow_new_entry_clicked(GtkWidget *widget, gpointer user_data)
mainWindow_openExternalEditor(path);
} else {
g_warning("Could not open file '%s' for writing.", path);
mainWindow_show_error(mainWindow, "Could not open file for writing.");
}
}
}
@ -1228,3 +1282,25 @@ void mainWindow_decrypt_gpg_clicked(GtkWidget *widget, gpointer user_data)
g_print("ERROR: This should never happen...\n");
}
}
/**
* @brief mainWindow_toggleSummaryWrap toggles line-wrapping and ellipsize on the summary
* @param widget
* @param event
* @param user_data
* @return
*/
gboolean mainWindow_toggleSummaryWrap(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
struct mainWindow *mainWindow = (struct mainWindow *)user_data;
gboolean state;
state = gtk_label_get_line_wrap(GTK_LABEL(mainWindow->labelSummary));
gtk_label_set_ellipsize(GTK_LABEL(mainWindow->labelSummary),
!state ? PANGO_ELLIPSIZE_NONE : PANGO_ELLIPSIZE_END);
gtk_label_set_line_wrap(GTK_LABEL(mainWindow->labelSummary), !state);
return FALSE;
}

View File

@ -8,6 +8,9 @@
#include "mdiary.h"
#include "md_pango.h"
#include "hoedown/src/document.h"
#include "hoedown/src/html.h"
#define FILE_LIST_MAX_LEN 5
enum {
@ -37,6 +40,7 @@ struct mainWindow {
GtkWidget *checkSearchSummary;
GtkWidget *checkSearchTags;
GtkWidget *checkSearchText;
GtkWidget *summaryEventBox;
GtkWidget *labelSummary;
GtkWidget *buttonClearSearch;
GtkWidget *headerBar;
@ -89,6 +93,7 @@ struct mainWindow {
GtkWidget *stackNewDateFormat;
GtkWidget *comboNewDateFormat;
GtkWidget *buttonCustomNewFileDateFormat;
GtkWidget *buttonOpenWorkspaceFolder;
GtkWidget *entryNewDateFormat;
} settingsDialog;
};
@ -119,6 +124,7 @@ void mainWindow_new_entry_clicked(GtkWidget *widget, gpointer user_data);
void mainWindow_decrypt_gpg_clicked(GtkWidget *widget, gpointer user_data);
void mainWindow_renderer_set(struct mainWindow *mainWindow, enum renderer_mode state);
void mainWindow_settings_show(struct mainWindow *mainWindow);
gboolean mainWindow_toggleSummaryWrap(GtkWidget *widget, GdkEvent *event, gpointer user_data);
void mainWindow_set_new_file_date_format(struct mainWindow *mainWindow, gchar *fmt);
#endif /* MAINWINDOW_H */

View File

@ -26,13 +26,25 @@ gchar *md_pango_render(gchar *markup, gint length)
g_free(str);
str = str2;
regex = g_regex_new("\\*{2}([^\\*]*)\\*{2}", 0, 0, NULL);
regex = g_regex_new("(.+)\n", 0, 0, NULL);
str2 = g_regex_replace(regex, str, -1, 0, "\\1 ", 0, NULL);
g_regex_unref(regex);
g_free(str);
str = str2;
regex = g_regex_new("\n", 0, 0, NULL);
str2 = g_regex_replace(regex, str, -1, 0, "\n\n", 0, NULL);
g_regex_unref(regex);
g_free(str);
str = str2;
regex = g_regex_new("\\*{2}([^\\*\n]*)\\*{2}", 0, 0, NULL);
str2 = g_regex_replace(regex, str, -1, 0, "<b>\\1</b>", 0, NULL);
g_regex_unref(regex);
g_free(str);
str = str2;
regex = g_regex_new("\\*([^\\*]*)\\*", 0, 0, NULL);
regex = g_regex_new("\\*([^\\*\n]*)\\*", 0, 0, NULL);
str2 = g_regex_replace(regex, str, -1, 0, "<i>\\1</i>", 0, NULL);
g_free(str);
str = str2;

View File

@ -246,7 +246,7 @@ static gchar *mdiary_get_line_from_string(gchar **str_ptr)
* @param autoCompletion
*/
static void mdiary_add_file_to_store(struct mdiary_scanner *mdiary_scanner,
gchar *filename, gchar *content,
gchar *filename, gchar *content, GList *autotags,
GtkListStore *entryListStore, GtkListStore *autoCompletion)
{
GFile *file = NULL;
@ -263,6 +263,8 @@ static void mdiary_add_file_to_store(struct mdiary_scanner *mdiary_scanner,
GString *text = NULL;
guint header_state = 0;
GList *l;
g_message("Add file: %s\n", filename);
mdiary_scanner->entries_failed++; /* Will be decremented again when entry was successfully added. */
@ -323,7 +325,7 @@ static void mdiary_add_file_to_store(struct mdiary_scanner *mdiary_scanner,
}
if (!tagList) {
g_warning("PARSER: Could not detect tags in file!\n");
tagList = g_list_append(tagList, "untagged");
tagList = g_list_append(tagList, g_strdup("untagged"));
}
if (!text) {
g_warning("PARSER: Could not find any text in file!\n");
@ -338,6 +340,11 @@ static void mdiary_add_file_to_store(struct mdiary_scanner *mdiary_scanner,
title = g_strdup("Untitled");
}
for (l = autotags; l != NULL; l = l->next)
{
tagList = g_list_append(tagList, g_strdup(l->data));
}
mdiary_scanner->entries_failed--;
mdiary_scanner->entries_added++;
mdiary_add_entry_to_store(entryListStore,
@ -359,6 +366,8 @@ static void mdiary_add_file_to_store(struct mdiary_scanner *mdiary_scanner,
g_input_stream_close(G_INPUT_STREAM(stream), NULL, NULL);
g_object_unref(file);
}
g_list_free_full(tagList, *g_free);
g_string_free(text, 0);
g_free(summary);
g_free(title);
@ -366,7 +375,7 @@ static void mdiary_add_file_to_store(struct mdiary_scanner *mdiary_scanner,
}
static void mdiary_add_gpg_to_store(struct mdiary_scanner *mdiary_scanner,
gchar *filename,
gchar *filename, GList **autotags,
GtkListStore *entryListStore, GtkListStore *autoCompletion)
{
gchar *cmd = NULL;
@ -374,18 +383,34 @@ static void mdiary_add_gpg_to_store(struct mdiary_scanner *mdiary_scanner,
gchar *cmd_stderr = NULL;
gint exit_status = 0;
cmd = g_strdup_printf("gpg --decrypt %s", filename);
g_message("Decrypt file: %s", filename);
if (mdiary_scanner->gpg_enabled == 2) { /* GPG operation was manually cancelled */
g_warning("GPG: Skipping file.");
mdiary_scanner->entries_failed++; /* Simply count files that won't be decoded. */
return;
}
cmd = g_strdup_printf("gpg --decrypt \"%s\"", filename);
if (g_spawn_command_line_sync(cmd, &cmd_stdout, &cmd_stderr, &exit_status, NULL) && exit_status == 0) {
g_message("GPG: Decryption OK!\n");
mdiary_add_file_to_store(mdiary_scanner, filename, cmd_stdout, entryListStore, autoCompletion);
*autotags = g_list_append(*autotags, "encrypted");
mdiary_add_file_to_store(mdiary_scanner, filename, cmd_stdout, *autotags, entryListStore, autoCompletion);
*autotags = g_list_remove(*autotags, g_list_last(*autotags)->data);
} else {
mdiary_scanner->entries_failed++;
g_warning("GPG: Decryption of message failed!\n"
mdiary_scanner->error_code |= MDS_ERROR_GPG;
g_warning("GPG: Decryption of message failed with error code %d!\n"
"---------- SNIP ----------\n"
"%s"
"---------- SNIP ----------\n",
cmd_stderr ? cmd_stderr : "Unknown error.");
exit_status,
cmd_stderr ? cmd_stderr : "Unknown error.\n");
if (cmd_stderr && strstr(cmd_stderr, "Operation cancelled")) {
g_warning("GPG: Aborting import of further GPG messages.");
mdiary_scanner->gpg_enabled = 2;
}
}
g_free(cmd);
@ -395,6 +420,7 @@ static void mdiary_add_gpg_to_store(struct mdiary_scanner *mdiary_scanner,
static void mdiary_recurse_and_collect(struct mdiary_scanner *mdiary_scanner,
gchar *base_dir,
GList **autotags,
GtkListStore *entryListStore,
GtkListStore *autoCompletion,
guint max_level)
@ -407,6 +433,7 @@ static void mdiary_recurse_and_collect(struct mdiary_scanner *mdiary_scanner,
if (!dir) {
g_print("Could not open base directory.\n");
mdiary_scanner->error_code |= MDS_ERROR_BASE_DIR;
} else {
while (dirname = (gchar *)g_dir_read_name(dir)) {
fullPath = g_strdup_printf("%s/%s", base_dir, dirname);
@ -415,27 +442,28 @@ static void mdiary_recurse_and_collect(struct mdiary_scanner *mdiary_scanner,
if (g_regex_match(regex, fullPath, 0, &match_info) &&
g_match_info_matches(match_info))
mdiary_add_file_to_store(mdiary_scanner,
fullPath, NULL,
fullPath, NULL, *autotags,
entryListStore, autoCompletion);
g_regex_unref(regex);
regex = g_regex_new("\\.md.gpg$", G_REGEX_CASELESS, 0, NULL);
if (g_regex_match(regex, fullPath, 0, &match_info) &&
g_match_info_matches(match_info)) {
mdiary_scanner->entries_encrypted++;
if (mdiary_scanner->gpg_enabled)
mdiary_add_gpg_to_store(mdiary_scanner,
fullPath,
fullPath, autotags,
entryListStore, autoCompletion);
}
g_regex_unref(regex);
} else if (g_file_test(fullPath, G_FILE_TEST_IS_DIR) && max_level) {
*autotags = g_list_append(*autotags, dirname);
mdiary_recurse_and_collect(mdiary_scanner,
fullPath,
fullPath, autotags,
entryListStore, autoCompletion,
max_level--);
max_level - 1);
*autotags = g_list_remove(*autotags, g_list_last(*autotags)->data);
}
g_free(fullPath);
}
@ -455,6 +483,7 @@ struct mdiary_scanner *mdiary_scanner_new(gboolean gpg_enabled)
mdiary_scanner->gpg_enabled = gpg_enabled;
mdiary_scanner->entries_failed = 0;
mdiary_scanner->entries_encrypted = 0;
mdiary_scanner->error_code = 0;
}
return mdiary_scanner;
@ -475,8 +504,11 @@ gint mdiary_scan_to_store(struct mdiary_scanner *mdiary_scanner,
gchar *base_dir,
GtkListStore *entryListStore, GtkListStore *autoCompletion)
{
GList *autotags = NULL;
mdiary_recurse_and_collect(mdiary_scanner, base_dir, entryListStore, autoCompletion, 5);
mdiary_recurse_and_collect(mdiary_scanner, base_dir, &autotags, entryListStore, autoCompletion, 5);
g_list_free(autotags);
return mdiary_scanner->entries_added;
}

View File

@ -5,6 +5,9 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#define MDS_ERROR_BASE_DIR 1
#define MDS_ERROR_GPG 2
enum {
COL_TITLE = 0, /* Title of the entry */
COL_DATE_TEXT, /* Textual representation of the date (auto generated) */
@ -24,6 +27,7 @@ struct mdiary_scanner {
gint entries_added;
gint entries_encrypted;
gint entries_failed;
gint error_code;
};
struct mdiary_scanner *mdiary_scanner_new(gboolean gpg_enabled);