package Kephra::File; our $VERSION = '0.46'; use strict; use warnings; sub _dialog_l18n { Kephra::Config::Localisation::strings()->{dialog} } sub _config { Kephra::API::settings()->{file} } sub _dir { _config()->{current}{directory} } # # file events sub savepoint_left { my $doc_nr = shift; $doc_nr = Kephra::Document::Data::current_nr() if not defined $doc_nr or ref $doc_nr; Kephra::Document::Data::inc_value('modified') unless Kephra::Document::Data::get_attribute('modified', $doc_nr); Kephra::Document::Data::set_attribute('modified', 1, $doc_nr); Kephra::App::TabBar::refresh_label($doc_nr) if Kephra::App::TabBar::_config()->{info_symbol}; Kephra::EventTable::trigger('document.savepoint'); } sub savepoint_reached { my $doc_nr = shift; $doc_nr = Kephra::Document::Data::current_nr() if not defined $doc_nr or ref $doc_nr; Kephra::Document::Data::dec_value('modified') if Kephra::Document::Data::get_attribute('modified', $doc_nr); Kephra::Document::Data::set_attribute('modified', 0, $doc_nr); Kephra::App::TabBar::refresh_label($doc_nr); Kephra::EventTable::trigger('document.savepoint'); } sub can_save { Kephra::Document::Data::attr('modified') } sub can_save_all { Kephra::Document::Data::get_value('modified') } sub changed_notify_check { my $current_doc = Kephra::Document::Data::current_nr(); for my $file_nr ( @{ Kephra::Document::Data::all_nr() } ) { my $file = Kephra::Document::Data::get_file_path($file_nr); my $last_check = Kephra::Document::Data::get_attribute ('did_notify', $file_nr); next unless $file; if (not -e $file) { next if defined $last_check and $last_check eq 'ignore'; Kephra::Document::Change::to_number( $file_nr ); Kephra::Dialog::notify_file_deleted( $file_nr ); next; } my $last_change = Kephra::Document::Data::get_attribute('file_changed', $file_nr); my $current_age = Kephra::File::IO::get_age($file); if ( $last_change != $current_age) { next if defined $last_check and ( $last_check eq 'ignore' or $last_check >= $current_age); Kephra::Document::Change::to_number( $file_nr ); Kephra::Document::Data::set_attribute ('did_notify', _remember_save_moment($file_nr), $file_nr); Kephra::Dialog::notify_file_changed( $file_nr, $current_age ); } } Kephra::Document::Change::to_number($current_doc) unless $current_doc == Kephra::Document::Data::current_nr(); } sub _remember_save_moment { my ($doc_nr) = shift || Kephra::Document::Data::current_nr(); my $path = shift || Kephra::Document::Data::get_file_path($doc_nr); return unless defined $path and -e $path; my $age = Kephra::File::IO::get_age($path); Kephra::Document::Data::set_attribute('file_changed', $age, $doc_nr); return $age; } sub check_b4_overwite { my $file = shift; $file = Kephra::Document::Data::get_file_path() unless $file; my $allow = _config()->{save}{overwrite}; if ( -e $file ) { my $frame = Kephra::App::Window::_ref(); my $label = Kephra::Config::Localisation::strings()->{dialog}; if ( $allow eq 'ask' ) { my $answer = Kephra::Dialog::get_confirm_2 ( "$label->{general}{overwrite} $file ?", $label->{file}{overwrite}, -1, -1 ); return 1 if $answer == &Wx::wxYES; return 0 if $answer == &Wx::wxNO; } else { Kephra::Dialog::info_box( $label->{general}{dont_allow}, $label->{file}{overwrite} ) unless $allow; return $allow; } } else { return -1 } } # # drag n drop sub add_dropped { # add all currently dnd-held files my ($ep, $event) = @_; -d $_ ? add_dir($_) : Kephra::Document::add($_) for $event->GetFiles; } sub add_dir{ # add all files of an dnd-held dir my $dir = shift; return until -d $dir; opendir (my $DH, $dir); my @dir_items = readdir($DH); closedir($DH); my $path; my $recursive = _config()->{open}{dir_recursive}; foreach (@dir_items) { $path = "$dir/$_"; if (-d $path) { next if not $recursive or $_ eq '.' or $_ eq '..'; add_dir($path); } else { Kephra::Document::add($path) } } } # # file menu calls sub new { Kephra::Document::new() } sub open { # buttons dont freeze while computing Kephra::App::_ref()->Yield(); # file selector dialog my $files = Kephra::Dialog::get_files_open( _dialog_l18n()->{file}{open}, _dir(), $Kephra::temp{file}{filterstring}{all} ); # opening selected files if (ref $files eq 'ARRAY') { Kephra::Document::add($_) for @$files } } sub open_all_of_dir { my $dir = Kephra::Dialog::get_dir( _dialog_l18n()->{file}{open_dir}, _dir() ); add_dir( $dir ); } sub reload { reload_current(@_) } # alias sub reload_current { my $file_path = Kephra::Document::Data::get_file_path(); my $doc_nr = Kephra::Document::Data::current_nr(); if ($file_path and -e $file_path){ my $ep = Kephra::App::EditPanel::_ref(); Kephra::Document::Data::update_attributes($doc_nr); $ep->BeginUndoAction; $ep->SetText(""); Kephra::File::IO::open_buffer( $doc_nr ); $ep->EndUndoAction; $ep->SetSavePoint; _remember_save_moment(); Kephra::Document::Data::evaluate_attributes(); Kephra::App::EditPanel::Margin::autosize_line_number() if (Kephra::App::EditPanel::Margin::_config()->{linenumber}{autosize} and Kephra::App::EditPanel::Margin::_config()->{linenumber}{width} ); Kephra::Document::Data::evaluate_attributes($doc_nr); } else { } } sub reload_all { Kephra::Document::do_with_all( sub { reload_current() } ) } sub insert { my $file = Kephra::Dialog::get_file_open ( _dialog_l18n()->{file}{insert}, _dir(), $Kephra::temp{file}{filterstring}{all} ); Kephra::File::IO::open_buffer( Kephra::Document::Data::current_nr(), $file); } # sub _save_nr { my $nr = shift; $nr = Kephra::Document::Data::current_nr() unless defined $nr; my $ep = Kephra::Document::Data::_ep( $nr ); my $file = Kephra::Document::Data::get_file_path($nr); return until defined $nr and $ep and -e $file; my $save_config = _config()->{save}; return unless $ep->GetModify == 1 or $save_config->{unchanged}; rename $file, $file . '~' if $save_config->{tilde_backup} == 1; Kephra::File::IO::write_buffer( $nr ); $ep->SetSavePoint; _remember_save_moment($nr); } sub save { save_current(@_) } sub save_current { my ($ctrl, $event) = @_; my $ep = Kephra::App::EditPanel::_ref(); my $file = Kephra::Document::Data::get_file_path(); my $save_config = _config()->{save}; if ( $ep->GetModify == 1 or $save_config->{unchanged} ) { if ( $file and -e $file ) { if (not -w $file ) { my $err_msg = _dialog_l18n()->{error}; Kephra::Dialog::warning_box( $err_msg->{write_protected}."\n".$err_msg->{write_protected2}, $err_msg->{file} ); save_as(); } else { _save_nr(); Kephra::Config::Global::eval_config_file($file) if $save_config->{reload_config} == 1 and Kephra::Document::Data::get_attribute('config_file'); } } else { save_as() } } } sub save_as { my $file = Kephra::Dialog::get_file_save( _dialog_l18n()->{file}{save_as}, _dir(), $Kephra::temp{file}{filterstring}{all} ); if ( $file and check_b4_overwite($file) ) { my $ep = Kephra::App::EditPanel::_ref(); my $oldname = Kephra::Document::Data::get_file_path(); Kephra::Document::Data::inc_value('loaded') unless $oldname; Kephra::Document::Data::update_attributes(); Kephra::Document::Data::set_file_path($file); Kephra::File::IO::write_buffer(); $ep->SetSavePoint(); Kephra::Document::SyntaxMode::set('auto'); Kephra::App::Window::refresh_title(); Kephra::App::TabBar::refresh_current_label(); Kephra::App::StatusBar::refresh_all_cells(); _config()->{current}{directory} = Kephra::Document::Data::get_attribute('directory'); _remember_save_moment( ); Kephra::EventTable::trigger('document.list'); } } sub save_copy_as { my $file = Kephra::Dialog::get_file_save( _dialog_l18n()->{file}{save_copy_as}, _dir(), $Kephra::temp{file}{filterstring}{all} ); print "---",$file,"\n"; Kephra::File::IO::write_buffer(Kephra::Document::Data::current_nr(), $file) if $file and check_b4_overwite($file); } sub rename { my $new_path_name = Kephra::Dialog::get_file_save( _dialog_l18n()->{file}{rename}, _dir(), $Kephra::temp{file}{filterstring}{all} ); if ($new_path_name){ my $old_path_name = Kephra::Document::Data::get_file_path(); rename $old_path_name, $new_path_name if $old_path_name; Kephra::Document::Data::set_file_path($new_path_name); Kephra::Document::SyntaxMode::set('auto'); Kephra::App::Window::refresh_title(); Kephra::App::TabBar::refresh_current_label(); _config()->{current}{directory} = Kephra::Document::Data::get_attribute('directory'); Kephra::EventTable::trigger('document.list'); _remember_save_moment(); } } sub save_all { my $unsaved = can_save_all(); return unless $unsaved; # save surrent if its the only if ($unsaved == 1 and can_save() ) { save_current(); } # else { Kephra::Document::do_with_all( sub { save_current() if shift->{modified}; } ); } } sub save_all_named { my $unsaved = can_save_all(); return unless $unsaved; my $need_save_other; my $cdoc_nr = Kephra::Document::Data::current_nr(); for my $doc_nr ( @{ Kephra::Document::Data::all_nr()} ) { my ($name, $mod) = @{Kephra::Document::Data::attributes(['file_name', 'modified'], $doc_nr) }; $need_save_other = 1 if $doc_nr != $cdoc_nr and $name and $mod; } if ($need_save_other) { Kephra::Document::do_with_all( sub { my $file = shift; save_current() if $file->{modified} and $file->{file_name}; } ); } elsif (can_save() and Kephra::Document::Data::get_file_path()) { save_current(); } } sub print { require Wx::Print; my ( $frame, $event ) = @_; my $ep = Kephra::App::EditPanel::_ref(); my $printer = Wx::Printer->new; my $printout = Wx::Printout->new( "$Kephra::NAME $Kephra::VERSION : " . Kephra::Document::Data::file_name() ); #$ep->FormatRange(doDraw,startPos,endPos,draw,target,renderRect,pageRect); #$printer->Print( $frame, $printout, 1 ); $printout->Destroy; } sub close { close_current() } sub close_current { close_nr( Kephra::Document::Data::current_nr() ) } sub close_nr { my $doc_nr = shift; my $ep = Kephra::Document::Data::_ep($doc_nr); my $config = _config()->{save}; my $save_answer= &Wx::wxNO; # save text if options demand it if ($ep->GetModify == 1 or $config->{unchanged} eq 1) { if ($ep->GetTextLength > 0 or $config->{empty} eq 1) { if ($config->{b4_close} eq 'ask' or $config->{b4_close} eq '2'){ my $l10n = _dialog_l18n()->{file}; $save_answer = Kephra::Dialog::get_confirm_3 ($l10n->{save_current}, $l10n->{close_unsaved} ); } return if $save_answer == &Wx::wxCANCEL; if ($save_answer == &Wx::wxYES or $config->{b4_close} eq '1') { _save_nr($doc_nr) } else{ savepoint_reached($doc_nr) if $ep->GetModify } } } # proceed close_nr_unsaved($doc_nr); } sub close_other { my $doc_nr = Kephra::Document::Data::current_nr(); Kephra::Document::Change::to_number(0); $_ != $doc_nr ? close_current() : Kephra::Document::Change::to_number(1) for @{ Kephra::Document::Data::all_nr() }; } sub close_all { close_current($_) for @{ Kephra::Document::Data::all_nr() } } sub close_unsaved { close_current_unsaved() } sub close_current_unsaved { close_nr_unsaved( Kephra::Document::Data::current_nr()) } sub close_nr_unsaved { my $doc_nr = shift; my $current = Kephra::Document::Data::current_nr(); my $ep = Kephra::Document::Data::_ep( $doc_nr ); my $file = Kephra::Document::Data::get_file_path( $doc_nr ); my $buffer = Kephra::Document::Data::get_value( 'buffer' ); if ($file){ Kephra::App::EditPanel::Fold::store( $doc_nr ); Kephra::Edit::Marker::store( $doc_nr ); } Kephra::EventTable::trigger('document.close'); # empty last document if ( $buffer == 1 ) { Kephra::Document::Data::set_value('loaded', 0); Kephra::Document::reset(0); } # close document elsif ( $buffer > 1 ) { # select to which file nr to jump my $close_last = $doc_nr == Kephra::Document::Data::last_nr(); my $switch = $doc_nr == $current; if ($switch){ $close_last ? Kephra::Document::Change::to_number( $doc_nr - 1 ) : Kephra::Document::Change::to_number( $doc_nr + 1 ); } Kephra::Document::Data::dec_value('buffer'); Kephra::Document::Data::dec_value('loaded') if Kephra::Document::Data::get_file_path( $doc_nr ); Kephra::App::TabBar::delete_tab_by_doc_nr( $doc_nr ); Kephra::Document::Data::delete_slot( $doc_nr ); Kephra::Document::Data::set_current_nr( $doc_nr ) unless $close_last and $switch; } Kephra::App::Window::refresh_title(); Kephra::App::EditPanel::gets_focus(); Kephra::EventTable::trigger('document.list'); } sub close_all_unsaved { close_current_unsaved() for @{ Kephra::Document::Data::all_nr() } } sub close_other_unsaved { my $doc_nr = Kephra::Document::Data::current_nr(); Kephra::Document::Change::to_number(0); $_ != $doc_nr ? close_unsaved() : Kephra::Document::Change::to_number(1) for @{ Kephra::Document::Data::all_nr() }; } 1; =head1 NAME Kephra::File - basic file menu functions =head1 DESCRIPTION file menu calls drag n drop files file save events =cut