File Coverage

lib/Kephra/File.pm
Criterion Covered Total %
statement 6 237 2.5
branch 0 118 0.0
condition 0 90 0.0
subroutine 2 43 4.6
pod 0 33 0.0
total 8 521 1.5


line stmt bran cond sub pod time code
1             package Kephra::File;
2             our $VERSION = '0.46';
3            
4 1     1   1119 use strict;
  1         9  
  1         37  
5 1     1   5 use warnings;
  1         2  
  1         3825  
6            
7 0     0     sub _dialog_l18n { Kephra::Config::Localisation::strings()->{dialog} }
8 0     0     sub _config { Kephra::API::settings()->{file} }
9 0     0     sub _dir { _config()->{current}{directory} }
10             #
11             # file events
12             sub savepoint_left {
13 0     0 0   my $doc_nr = shift;
14 0 0 0       $doc_nr = Kephra::Document::Data::current_nr() if not defined $doc_nr or ref $doc_nr;
15 0 0         Kephra::Document::Data::inc_value('modified')
16             unless Kephra::Document::Data::get_attribute('modified', $doc_nr);
17 0           Kephra::Document::Data::set_attribute('modified', 1, $doc_nr);
18 0 0         Kephra::App::TabBar::refresh_label($doc_nr)
19             if Kephra::App::TabBar::_config()->{info_symbol};
20 0           Kephra::EventTable::trigger('document.savepoint');
21             }
22             sub savepoint_reached {
23 0     0 0   my $doc_nr = shift;
24 0 0 0       $doc_nr = Kephra::Document::Data::current_nr() if not defined $doc_nr or ref $doc_nr;
25 0 0         Kephra::Document::Data::dec_value('modified')
26             if Kephra::Document::Data::get_attribute('modified', $doc_nr);
27 0           Kephra::Document::Data::set_attribute('modified', 0, $doc_nr);
28 0           Kephra::App::TabBar::refresh_label($doc_nr);
29 0           Kephra::EventTable::trigger('document.savepoint');
30             }
31            
32 0     0 0   sub can_save { Kephra::Document::Data::attr('modified') }
33 0     0 0   sub can_save_all { Kephra::Document::Data::get_value('modified') }
34            
35             sub changed_notify_check {
36 0     0 0   my $current_doc = Kephra::Document::Data::current_nr();
37 0           for my $file_nr ( @{ Kephra::Document::Data::all_nr() } ) {
  0            
38 0           my $file = Kephra::Document::Data::get_file_path($file_nr);
39 0           my $last_check = Kephra::Document::Data::get_attribute
40             ('did_notify', $file_nr);
41 0 0         next unless $file;
42 0 0         if (not -e $file) {
43 0 0 0       next if defined $last_check and $last_check eq 'ignore';
44 0           Kephra::Document::Change::to_number( $file_nr );
45 0           Kephra::Dialog::notify_file_deleted( $file_nr );
46 0           next;
47             }
48 0           my $last_change = Kephra::Document::Data::get_attribute('file_changed', $file_nr);
49 0           my $current_age = Kephra::File::IO::get_age($file);
50 0 0         if ( $last_change != $current_age) {
51 0 0 0       next if defined $last_check
      0        
52             and ( $last_check eq 'ignore' or $last_check >= $current_age);
53 0           Kephra::Document::Change::to_number( $file_nr );
54 0           Kephra::Document::Data::set_attribute
55             ('did_notify', _remember_save_moment($file_nr), $file_nr);
56 0           Kephra::Dialog::notify_file_changed( $file_nr, $current_age );
57             }
58             }
59 0 0         Kephra::Document::Change::to_number($current_doc)
60             unless $current_doc == Kephra::Document::Data::current_nr();
61             }
62            
63             sub _remember_save_moment {
64 0   0 0     my ($doc_nr) = shift || Kephra::Document::Data::current_nr();
65 0   0       my $path = shift || Kephra::Document::Data::get_file_path($doc_nr);
66 0 0 0       return unless defined $path and -e $path;
67 0           my $age = Kephra::File::IO::get_age($path);
68 0           Kephra::Document::Data::set_attribute('file_changed', $age, $doc_nr);
69 0           return $age;
70             }
71            
72             sub check_b4_overwite {
73 0     0 0   my $file = shift;
74 0 0         $file = Kephra::Document::Data::get_file_path() unless $file;
75 0           my $allow = _config()->{save}{overwrite};
76 0 0         if ( -e $file ) {
77 0           my $frame = Kephra::App::Window::_ref();
78 0           my $label = Kephra::Config::Localisation::strings()->{dialog};
79 0 0         if ( $allow eq 'ask' ) {
80 0           my $answer = Kephra::Dialog::get_confirm_2 (
81             "$label->{general}{overwrite} $file ?",
82             $label->{file}{overwrite},
83             -1, -1
84             );
85 0 0         return 1 if $answer == &Wx::wxYES;
86 0 0         return 0 if $answer == &Wx::wxNO;
87             } else {
88 0 0         Kephra::Dialog::info_box(
89             $label->{general}{dont_allow},
90             $label->{file}{overwrite}
91             ) unless $allow;
92 0           return $allow;
93             }
94 0           } else { return -1 }
95             }
96             #
97             # drag n drop
98             sub add_dropped { # add all currently dnd-held files
99 0     0 0   my ($ep, $event) = @_;
100 0 0         -d $_ ? add_dir($_) : Kephra::Document::add($_) for $event->GetFiles;
101             }
102            
103             sub add_dir{ # add all files of an dnd-held dir
104 0     0 0   my $dir = shift;
105 0           return until -d $dir;
106 0           opendir (my $DH, $dir);
107 0           my @dir_items = readdir($DH);
108 0           closedir($DH);
109 0           my $path;
110 0           my $recursive = _config()->{open}{dir_recursive};
111            
112 0           foreach (@dir_items) {
113 0           $path = "$dir/$_";
114 0 0         if (-d $path) {
115 0 0 0       next if not $recursive or $_ eq '.' or $_ eq '..';
      0        
116 0           add_dir($path);
117 0           } else { Kephra::Document::add($path) }
118             }
119             }
120            
121             #
122             # file menu calls
123 0     0 0   sub new { Kephra::Document::new() }
124             sub open {
125             # buttons dont freeze while computing
126 0     0 0   Kephra::App::_ref()->Yield();
127            
128             # file selector dialog
129 0           my $files = Kephra::Dialog::get_files_open(
130             _dialog_l18n()->{file}{open}, _dir(),
131             $Kephra::temp{file}{filterstring}{all}
132             );
133             # opening selected files
134 0 0         if (ref $files eq 'ARRAY') { Kephra::Document::add($_) for @$files }
  0            
135             }
136            
137             sub open_all_of_dir {
138 0     0 0   my $dir = Kephra::Dialog::get_dir( _dialog_l18n()->{file}{open_dir}, _dir() );
139 0           add_dir( $dir );
140             }
141            
142 0     0 0   sub reload { reload_current(@_) } # alias
143             sub reload_current {
144 0     0 0   my $file_path = Kephra::Document::Data::get_file_path();
145 0           my $doc_nr = Kephra::Document::Data::current_nr();
146 0 0 0       if ($file_path and -e $file_path){
147 0           my $ep = Kephra::App::EditPanel::_ref();
148 0           Kephra::Document::Data::update_attributes($doc_nr);
149 0           $ep->BeginUndoAction;
150 0           $ep->SetText("");
151 0           Kephra::File::IO::open_buffer( $doc_nr );
152 0           $ep->EndUndoAction;
153 0           $ep->SetSavePoint;
154 0           _remember_save_moment();
155 0           Kephra::Document::Data::evaluate_attributes();
156 0 0 0       Kephra::App::EditPanel::Margin::autosize_line_number()
157             if (Kephra::App::EditPanel::Margin::_config()->{linenumber}{autosize}
158             and Kephra::App::EditPanel::Margin::_config()->{linenumber}{width} );
159 0           Kephra::Document::Data::evaluate_attributes($doc_nr);
160             } else {
161             }
162             }
163 0     0 0   sub reload_all { Kephra::Document::do_with_all( sub { reload_current() } ) }
  0     0      
164            
165             sub insert {
166 0     0 0   my $file = Kephra::Dialog::get_file_open (
167             _dialog_l18n()->{file}{insert},
168             _dir(),
169             $Kephra::temp{file}{filterstring}{all}
170             );
171 0           Kephra::File::IO::open_buffer( Kephra::Document::Data::current_nr(), $file);
172             }
173             #
174             sub _save_nr {
175 0     0     my $nr = shift;
176 0 0         $nr = Kephra::Document::Data::current_nr() unless defined $nr;
177 0           my $ep = Kephra::Document::Data::_ep( $nr );
178 0           my $file = Kephra::Document::Data::get_file_path($nr);
179 0   0       return until defined $nr and $ep and -e $file;
      0        
180 0           my $save_config = _config()->{save};
181 0 0 0       return unless $ep->GetModify == 1 or $save_config->{unchanged};
182 0 0         rename $file, $file . '~' if $save_config->{tilde_backup} == 1;
183 0           Kephra::File::IO::write_buffer( $nr );
184 0           $ep->SetSavePoint;
185 0           _remember_save_moment($nr);
186             }
187 0     0 0   sub save { save_current(@_) }
188             sub save_current {
189 0     0 0   my ($ctrl, $event) = @_;
190 0           my $ep = Kephra::App::EditPanel::_ref();
191 0           my $file = Kephra::Document::Data::get_file_path();
192 0           my $save_config = _config()->{save};
193 0 0 0       if ( $ep->GetModify == 1 or $save_config->{unchanged} ) {
194 0 0 0       if ( $file and -e $file ) {
195 0 0         if (not -w $file ) {
196 0           my $err_msg = _dialog_l18n()->{error};
197 0           Kephra::Dialog::warning_box(
198             $err_msg->{write_protected}."\n".$err_msg->{write_protected2},
199             $err_msg->{file} );
200 0           save_as();
201             } else {
202 0           _save_nr();
203 0 0 0       Kephra::Config::Global::eval_config_file($file)
204             if $save_config->{reload_config} == 1
205             and Kephra::Document::Data::get_attribute('config_file');
206             }
207 0           } else { save_as() }
208             }
209             }
210            
211             sub save_as {
212 0     0 0   my $file = Kephra::Dialog::get_file_save(
213             _dialog_l18n()->{file}{save_as},
214             _dir(),
215             $Kephra::temp{file}{filterstring}{all}
216             );
217 0 0 0       if ( $file and check_b4_overwite($file) ) {
218 0           my $ep = Kephra::App::EditPanel::_ref();
219 0           my $oldname = Kephra::Document::Data::get_file_path();
220 0 0         Kephra::Document::Data::inc_value('loaded') unless $oldname;
221 0           Kephra::Document::Data::update_attributes();
222 0           Kephra::Document::Data::set_file_path($file);
223 0           Kephra::File::IO::write_buffer();
224 0           $ep->SetSavePoint();
225 0           Kephra::Document::SyntaxMode::set('auto');
226 0           Kephra::App::Window::refresh_title();
227 0           Kephra::App::TabBar::refresh_current_label();
228 0           Kephra::App::StatusBar::refresh_all_cells();
229 0           _config()->{current}{directory} =
230             Kephra::Document::Data::get_attribute('directory');
231 0           _remember_save_moment( );
232 0           Kephra::EventTable::trigger('document.list');
233             }
234             }
235            
236            
237             sub save_copy_as {
238 0     0 0   my $file = Kephra::Dialog::get_file_save(
239             _dialog_l18n()->{file}{save_copy_as},
240             _dir(),
241             $Kephra::temp{file}{filterstring}{all}
242             );
243 0           print "---",$file,"\n";
244 0 0 0       Kephra::File::IO::write_buffer(Kephra::Document::Data::current_nr(), $file)
245             if $file and check_b4_overwite($file);
246             }
247            
248            
249             sub rename {
250 0     0 0   my $new_path_name = Kephra::Dialog::get_file_save(
251             _dialog_l18n()->{file}{rename},
252             _dir(),
253             $Kephra::temp{file}{filterstring}{all} );
254 0 0         if ($new_path_name){
255 0           my $old_path_name = Kephra::Document::Data::get_file_path();
256 0 0         rename $old_path_name, $new_path_name if $old_path_name;
257 0           Kephra::Document::Data::set_file_path($new_path_name);
258 0           Kephra::Document::SyntaxMode::set('auto');
259 0           Kephra::App::Window::refresh_title();
260 0           Kephra::App::TabBar::refresh_current_label();
261 0           _config()->{current}{directory} =
262             Kephra::Document::Data::get_attribute('directory');
263 0           Kephra::EventTable::trigger('document.list');
264 0           _remember_save_moment();
265             }
266             }
267            
268            
269             sub save_all {
270 0     0 0   my $unsaved = can_save_all();
271 0 0         return unless $unsaved;
272             # save surrent if its the only
273 0 0 0       if ($unsaved == 1 and can_save() ) {
274 0           save_current();
275             }
276             #
277             else {
278             Kephra::Document::do_with_all( sub {
279 0 0   0     save_current() if shift->{modified};
280 0           } );
281             }
282             }
283            
284             sub save_all_named {
285 0     0 0   my $unsaved = can_save_all();
286 0 0         return unless $unsaved;
287 0           my $need_save_other;
288 0           my $cdoc_nr = Kephra::Document::Data::current_nr();
289 0           for my $doc_nr ( @{ Kephra::Document::Data::all_nr()} ) {
  0            
290 0           my ($name, $mod) = @{Kephra::Document::Data::attributes(['file_name', 'modified'], $doc_nr) };
  0            
291 0 0 0       $need_save_other = 1 if $doc_nr != $cdoc_nr and $name and $mod;
      0        
292             }
293 0 0 0       if ($need_save_other) {
    0          
294             Kephra::Document::do_with_all( sub {
295 0     0     my $file = shift;
296 0 0 0       save_current() if $file->{modified} and $file->{file_name};
297 0           } );
298             } elsif (can_save() and Kephra::Document::Data::get_file_path()) {
299 0           save_current();
300             }
301             }
302            
303             sub print {
304 0     0 0   require Wx::Print;
305 0           my ( $frame, $event ) = @_;
306 0           my $ep = Kephra::App::EditPanel::_ref();
307 0           my $printer = Wx::Printer->new;
308 0           my $printout = Wx::Printout->new(
309             "$Kephra::NAME $Kephra::VERSION : " . Kephra::Document::Data::file_name()
310             );
311             #$ep->FormatRange(doDraw,startPos,endPos,draw,target,renderRect,pageRect);
312             #$printer->Print( $frame, $printout, 1 );
313            
314 0           $printout->Destroy;
315             }
316            
317 0     0 0   sub close { close_current() }
318 0     0 0   sub close_current { close_nr( Kephra::Document::Data::current_nr() ) }
319             sub close_nr {
320 0     0 0   my $doc_nr = shift;
321 0           my $ep = Kephra::Document::Data::_ep($doc_nr);
322 0           my $config = _config()->{save};
323 0           my $save_answer= &Wx::wxNO;
324            
325             # save text if options demand it
326 0 0 0       if ($ep->GetModify == 1 or $config->{unchanged} eq 1) {
327 0 0 0       if ($ep->GetTextLength > 0 or $config->{empty} eq 1) {
328 0 0 0       if ($config->{b4_close} eq 'ask' or $config->{b4_close} eq '2'){
329 0           my $l10n = _dialog_l18n()->{file};
330 0           $save_answer = Kephra::Dialog::get_confirm_3
331             ($l10n->{save_current}, $l10n->{close_unsaved} );
332             }
333 0 0         return if $save_answer == &Wx::wxCANCEL;
334 0 0 0       if ($save_answer == &Wx::wxYES or $config->{b4_close} eq '1')
335 0           { _save_nr($doc_nr) }
336 0 0         else{ savepoint_reached($doc_nr) if $ep->GetModify }
337             }
338             }
339            
340             # proceed
341 0           close_nr_unsaved($doc_nr);
342             }
343            
344             sub close_other {
345 0     0 0   my $doc_nr = Kephra::Document::Data::current_nr();
346 0           Kephra::Document::Change::to_number(0);
347 0           $_ != $doc_nr ? close_current() : Kephra::Document::Change::to_number(1)
348 0 0         for @{ Kephra::Document::Data::all_nr() };
349             }
350            
351 0     0 0   sub close_all { close_current($_) for @{ Kephra::Document::Data::all_nr() } }
  0            
352 0     0 0   sub close_unsaved { close_current_unsaved() }
353 0     0 0   sub close_current_unsaved { close_nr_unsaved( Kephra::Document::Data::current_nr()) }
354             sub close_nr_unsaved {
355 0     0 0   my $doc_nr = shift;
356 0           my $current = Kephra::Document::Data::current_nr();
357 0           my $ep = Kephra::Document::Data::_ep( $doc_nr );
358 0           my $file = Kephra::Document::Data::get_file_path( $doc_nr );
359 0           my $buffer = Kephra::Document::Data::get_value( 'buffer' );
360 0 0         if ($file){
361 0           Kephra::App::EditPanel::Fold::store( $doc_nr );
362 0           Kephra::Edit::Marker::store( $doc_nr );
363             }
364 0           Kephra::EventTable::trigger('document.close');
365            
366             # empty last document
367 0 0         if ( $buffer == 1 ) {
    0          
368 0           Kephra::Document::Data::set_value('loaded', 0);
369 0           Kephra::Document::reset(0);
370             }
371             # close document
372             elsif ( $buffer > 1 ) {
373             # select to which file nr to jump
374 0           my $close_last = $doc_nr == Kephra::Document::Data::last_nr();
375 0           my $switch = $doc_nr == $current;
376 0 0         if ($switch){
377 0 0         $close_last
378             ? Kephra::Document::Change::to_number( $doc_nr - 1 )
379             : Kephra::Document::Change::to_number( $doc_nr + 1 );
380             }
381 0           Kephra::Document::Data::dec_value('buffer');
382 0 0         Kephra::Document::Data::dec_value('loaded')
383             if Kephra::Document::Data::get_file_path( $doc_nr );
384 0           Kephra::App::TabBar::delete_tab_by_doc_nr( $doc_nr );
385 0           Kephra::Document::Data::delete_slot( $doc_nr );
386 0 0 0       Kephra::Document::Data::set_current_nr( $doc_nr ) unless $close_last and $switch;
387             }
388 0           Kephra::App::Window::refresh_title();
389 0           Kephra::App::EditPanel::gets_focus();
390            
391 0           Kephra::EventTable::trigger('document.list');
392             }
393            
394 0     0 0   sub close_all_unsaved { close_current_unsaved() for @{ Kephra::Document::Data::all_nr() } }
  0            
395             sub close_other_unsaved {
396 0     0 0   my $doc_nr = Kephra::Document::Data::current_nr();
397 0           Kephra::Document::Change::to_number(0);
398 0           $_ != $doc_nr ? close_unsaved() : Kephra::Document::Change::to_number(1)
399 0 0         for @{ Kephra::Document::Data::all_nr() };
400             }
401            
402             1;
403            
404             =head1 NAME
405            
406             Kephra::File - basic file menu functions
407            
408             =head1 DESCRIPTION
409            
410             file menu calls
411            
412             drag n drop files
413            
414             file save events
415            
416             =cut