App-orgdaemon

 view release on metacpan or  search on metacpan

bin/org-daemon  view on Meta::CPAN

				  )->pack(qw(-side left));
	    }
	    $t->bind('<Control-e>' => sub { $edit_b->invoke });
	    if ($mv_b) {
		$t->bind('<Control-m>' => sub { $mv_b->invoke });
	    }
	    if ($is_early_warning) {
		$t->{OverflowCounter} =
		    $t->repeat(1000, sub {
				   my $diff = $date->{epoch} - time;
				   if ($diff <= 0) { # may happen if the original date was deleted
				       $t->{OverflowCounter}->cancel;
				       $overflow = "";
				   } else {
				       $overflow = sprintf "-%02d:%02d", int($diff/60), $diff%60;
				   }
			       });
	    } else {
		$t->{OverflowCounter} =
		    $t->repeat(1000, sub {
				   my $diff = time - $date->{epoch};
				   $overflow = sprintf "+%02d:%02d", int($diff/60), $diff%60;
			       });
	    }

	    stay_on_top($t);

	    $window_for_date{$date_id} = $t;
	}
    }

    # Cleanup outdated windows (not existing or very old dates)
    {
	my @destroy_w;
	$mw->Walk(sub {
		      my $w = shift;
		      if ($w->isa('Tk::Toplevel')) {
			  my $date_id = $w->{DateId};
			  if ($date_id && !$active{$date_id}) {
			      push @destroy_w, $w;
			  }
		      }
		  });
	$_->destroy for @destroy_w;
    }

    # cleanup data structures
    for my $ref (\%window_for_date, \%seen_early_warning, \%seen_due_date) {
	while(my($k) = each %$ref) {
	    if (!$active{$k}) {
		delete $ref->{$k};
	    }
	}
    }
}

sub check_for_updates {
    my $changes = 0;
    for my $org_file (keys %org_files) {
	my $org_data = $org_files{$org_file};
	my($modtime) = (stat($org_file))[9];
	if (!defined $modtime) {
	    # non-existing file
	    $org_data->{modified} = $modtime;
	    $org_data->{dates} = [];
	    open_warning($org_file);
	    $changes++;
	    next;
	}
	delete $open_warning{$org_file};
	if (!$org_data->{modified} || $org_data->{modified} < $modtime) {
	    my @new_org_data_dates = find_relevant_dates_in_org_file($org_file, include_timeless => $include_timeless, time_fallback => $time_fallback, ignore_tags => \@ignore_tags);
	    my %old_org_data_dates; # id -> date
	    if ($org_data->{dates}) {
		for my $date (@{ $org_data->{dates} }) {
		    my $date_id = $date->id;
		    $old_org_data_dates{$date_id} = $date;
		}
	    }
	    $org_data->{dates} = [];
	    for my $date (@new_org_data_dates) {
		my $date_id = $date->id;
		if (exists $old_org_data_dates{$date_id}) {
		    my $old_date = $old_org_data_dates{$date_id};
		    $old_date->copy($date);
		    push @{ $org_data->{dates} }, $old_date; # re-use old date object with new values
		} else {
		    push @{ $org_data->{dates} }, $date;
		}
	    }
	    $org_data->{modified} = $modtime;
	    $changes++;
	}
    }
    $changes;
}

# Filter the output of find_dates_in_org_file: due dates which
# are currently not display (no %window_for_date entry) are
# removed from the result
sub find_relevant_dates_in_org_file {
    my(@args) = @_;
    grep {
	(
	 $_->state ne 'due' ||
	 ($window_for_date{$_->id} && Tk::Exists($window_for_date{$_->id}))
	)
    } find_dates_in_org_file(@args);
}

sub find_dates_in_org_file {
    my($file, %opts) = @_;
    my $include_timeless = delete $opts{include_timeless};
    my $time_fallback = delete $opts{time_fallback} || '00:00';
    my %ignore_tags = map {($_,1)} @{ delete $opts{ignore_tags} || [] };
    die "Unhandled options: " . join(" ", %opts) if %opts;

    my @dates;

    # This is org-stamp-time-of-day-regexp constant from org.el,
    # version 4.67d



( run in 2.035 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )