1/* 2* Copyright (c) 2018 (https://github.com/phase1geo/Minder) 3* 4* This program is free software; you can redistribute it and/or 5* modify it under the terms of the GNU General Public 6* License as published by the Free Software Foundation; either 7* version 2 of the License, or (at your option) any later version. 8* 9* This program is distributed in the hope that it will be useful, 10* but WITHOUT ANY WARRANTY; without even the implied warranty of 11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12* General Public License for more details. 13* 14* You should have received a copy of the GNU General Public 15* License along with this program; if not, write to the 16* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17* Boston, MA 02110-1301 USA 18* 19* Authored by: Trevor Williams <phase1geo@gmail.com> 20*/ 21 22using Gtk; 23 24public class ExportMarkdown : Export { 25 26 /* Constructor */ 27 public ExportMarkdown() { 28 base( "markdown", _( "Markdown" ), { ".md", ".markdown" }, true, false ); 29 } 30 31 private bool handle_directory( string fname, out string mdfile, out string imgdir ) { 32 mdfile = fname; 33 imgdir = fname; 34 if( get_bool( "include-image-links" ) ) { 35 var filename = fname; 36 var dirname = fname; 37 if( fname.has_suffix( ".md" ) ) { 38 var parts = fname.split( "." ); 39 dirname = string.joinv( ".", parts[0:parts.length-1] ); 40 } 41 if( DirUtils.create_with_parents( dirname, 0775 ) == 0 ) { 42 imgdir = GLib.Path.build_filename( dirname, "images" ); 43 if( DirUtils.create_with_parents( imgdir, 0775 ) == 0 ) { 44 mdfile = GLib.Path.build_filename( dirname, GLib.Path.get_basename( fname ) ); 45 return( true ); 46 } 47 } 48 return( false ); 49 } 50 return( true ); 51 } 52 53 /* Exports the given drawing area to the file of the given name */ 54 public override bool export( string fname, DrawArea da ) { 55 string filename, imgdir; 56 if( !handle_directory( fname, out filename, out imgdir ) ) return( false ); 57 var file = File.new_for_path( filename ); 58 bool retval = true; 59 try { 60 var os = file.replace( null, false, FileCreateFlags.NONE ); 61 export_top_nodes( os, da, imgdir ); 62 } catch( Error e ) { 63 retval = false; 64 } 65 return( retval ); 66 } 67 68 /* Draws each of the top-level nodes */ 69 private void export_top_nodes( FileOutputStream os, DrawArea da, string imgdir ) { 70 71 try { 72 73 var nodes = da.get_nodes(); 74 for( int i=0; i<nodes.length; i++ ) { 75 string title = "# " + nodes.index( i ).name.text.text + "\n\n"; 76 os.write( title.data ); 77 if( nodes.index( i ).note != "" ) { 78 string note = " > " + nodes.index( i ).note.replace( "\n", "\n > " ); 79 os.write( note.data ); 80 } 81 var children = nodes.index( i ).children(); 82 for( int j=0; j<children.length; j++ ) { 83 export_node( os, da.image_manager, children.index( j ), imgdir ); 84 } 85 } 86 87 } catch( Error e ) { 88 // Handle the error 89 } 90 91 } 92 93 /* Copies the given image file to the image directory */ 94 private bool copy_file( string imgdir, string filename ) { 95 var basename = GLib.Path.get_basename( filename ); 96 var lname = GLib.Path.build_filename( imgdir, basename ); 97 var rfile = File.new_for_path( filename ); 98 var lfile = File.new_for_path( lname ); 99 stdout.printf( "basename: %s, lname: %s, filename: %s\n", basename, lname, filename ); 100 try { 101 rfile.copy( lfile, FileCopyFlags.OVERWRITE ); 102 } catch( Error e ) { 103 stdout.printf( "message: %s\n", e.message ); 104 return( false ); 105 } 106 return( true ); 107 } 108 109 /* Draws the given node and its children to the output stream */ 110 private void export_node( FileOutputStream os, ImageManager im, Node node, string imgdir, string prefix = " " ) { 111 112 try { 113 114 var title = prefix + "- "; 115 116 if( node.is_task() ) { 117 if( node.is_task_done() ) { 118 title += "[x] "; 119 } else { 120 title += "[ ] "; 121 } 122 } 123 124 if( (node.image != null) && get_bool( "include-image-links" ) ) { 125 var file = im.get_file( node.image.id ); 126 if( copy_file( imgdir, file ) ) { 127 var basename = GLib.Path.get_basename( file ); 128 title += "<img src=\"images/" + basename + 129 "\" alt=\"image\" width=\"" + node.image.width.to_string() + 130 "\" height=\"" + node.image.height.to_string() + "\"/>\n" + prefix + " "; 131 } 132 } 133 134 title += node.name.text.text.replace( "\n", prefix + " " ) + "\n"; 135 136 os.write( title.data ); 137 138 if( node.note != "" ) { 139 string note = prefix + " > " + node.note.replace( "\n", "\n" + prefix + " > " ) + "\n"; 140 os.write( note.data ); 141 } 142 143 os.write( "\n".data ); 144 145 var children = node.children(); 146 for( int i=0; i<children.length; i++ ) { 147 export_node( os, im, children.index( i ), imgdir, prefix + " " ); 148 } 149 150 } catch( Error e ) { 151 // Handle error 152 } 153 154 } 155 156 /* Add the PNG settings */ 157 public override void add_settings( Grid grid ) { 158 159 add_setting_bool( "include-image-links", grid, _( "Include image links" ), 160 _( "Creates a directory containing the Markdown and embedded images" ), false ); 161 162 } 163 164 /* Save the settings */ 165 public override void save_settings( Xml.Node* node ) { 166 167 node->set_prop( "include-image-links", get_bool( "include-image-links" ).to_string() ); 168 169 } 170 171 /* Load the settings */ 172 public override void load_settings( Xml.Node* node ) { 173 174 var i = node->get_prop( "include-image-links" ); 175 if( i != null ) { 176 set_bool( "include-image-links", bool.parse( i ) ); 177 } 178 179 } 180 181} 182