# ------------------------------------------------------------------ # NAME: Susanti # FILENAME: AXEsse.pl # PURPOSE: to create a graphical user interface for # AXE style sheet # ------------------------------------------------------------------ #!/usr/bin/perl -w use Gtk; use Gtk::Atoms; init Gtk; #----------------------------- # Global Variables #----------------------------- my $AXEsse=".AXEsse.tb"; #temporary file for manipulating #include commands my $FILENAME=""; #current opened filename my $PATH=""; #file's path name my @FILE_CONTENT=(); #the content of the file my @ALL_TAGS=(); #the processed content of file #which has prefix, infix, postfix, etc my $MAIN_WINDOW; #main window for the interface my $CLIST; #list for the element content my $CLIST_ROW = 0; #the current selected list my $TEXT; #The text box for the content of #list element # For cut, copy, paste functionalities my $FOCUSED_TEXTBOX; #textbox that is in focused # For modification information my $CHANGE= 0; my $TEXT_CHANGE= 0; my $PREFIX_CHANGE= 0; my $INFIX_CHANGE= 0; my $POSTFIX_CHANGE= 0; # Undo and redo buffers my @UNDO_BUFFER=(); my @REDO_BUFFER=(); # ------------------------------------------------------------------ # FUNCTION SPECIFICATION # ------------------------------------------------------------------ # ------------------------------------------------------------------ # FUNCTION NAME: create_panes # FUNCTIONALITY: to create the interface to the AXEsse # PRECONDITION: none # POSTCONDITION: the interface of AXEsse is created # ------------------------------------------------------------------ sub create_panes { # local variables my ($filename) = @_; my ($box,); #----------------------------- # 1 Create Paned Window #----------------------------- $MAIN_WINDOW = new Gtk::Window ("toplevel"); $MAIN_WINDOW->signal_connect_after("delete_event", \&QuitFile); $MAIN_WINDOW->set_sensitive(1); if ($filename eq "") { $MAIN_WINDOW->set_title("AXEsse - notitle"); } else { $MAIN_WINDOW->set_title("AXEsse - $filename"); } $MAIN_WINDOW->border_width(0); $MAIN_WINDOW->set_policy(0,1,0); $MAIN_WINDOW->set_border_width(0); $MAIN_WINDOW->set_usize(700,700); #minimum size of window $MAIN_WINDOW->set_uposition(100,100); $box = new Gtk::VBox(0,0); $box->border_width(0); $MAIN_WINDOW->add($box); $box->show; #----------------------------- # 2 Adding menu bar #----------------------------- CreateMenuBar($box); #----------------------------- # 3 Adding toolbar #----------------------------- $MAIN_WINDOW->realize; CreateToolBar($box); #----------------------------- # Adding statusbar #----------------------------- my $statusbarBox = new Gtk::Frame(undef); $statusbarBox->border_width(2); $statusbarBox->set_shadow_type('in'); $box->pack_end($statusbarBox, 0,0,0); $STATUS_BAR = new Gtk::Label; $statusbarBox->add($STATUS_BAR); $STATUS_BAR->set_padding(100,5); $STATUS_BAR->set_justify('left'); $STATUS_BAR->show; #----------------------------- # 4 Building paned window #----------------------------- $hpaned = new Gtk::HPaned; $box->pack_start($hpaned,1, 1, 0); $hpaned->border_width(5); $hpaned->set_handle_size(15); $hpaned->set_gutter_size(15); #----------------------------- # 5 Adding Text box & scrollbar #----------------------------- $RightBox = new Gtk::VBox(0,0); $RightBox->border_width(0); $hpaned->add2($RightBox); $RightBox->show; $scrolledWin = new Gtk::ScrolledWindow(undef, undef); $scrolledWin->set_policy ('automatic', 'automatic'); $scrolledWin->set_usize(250,300); $TEXT = new Gtk::Text(undef,undef); $TEXT->signal_connect("changed", \&changedHandling); $TEXT->signal_connect("focus_in_event", \&focusHandling); $TEXT->set_editable(1); $FOCUSED_TEXTBOX = $TEXT; show $TEXT; my $vpaned = new Gtk::VPaned; $RightBox->pack_start($vpaned,1, 1, 0); $vpaned->border_width(0); $vpaned->set_handle_size(15); $vpaned->set_gutter_size(15); $scrolledWin->add($TEXT); $vpaned->add1($scrolledWin); $scrolledWin->show; #--------------------------------------- # 6 Adding prefix, infix, postfix window #--------------------------------------- CreatePIPtextboxes($vpaned); #--------------------------------------- # 6 Adding List window #--------------------------------------- $LeftBox = new Gtk::VBox(0,0); $LeftBox->border_width(0); $hpaned->add($LeftBox); $LeftBox->show; #building List CreateList($LeftBox); #show the window show_all $MAIN_WINDOW; } # ------------------------------------------------------------------ # FUNCTION NAME: focusHandling # FUNCTIONALITY: to get which text box that is activated # PRECONDITION: call back from the text box when get focused # POSTCONDITION: update variable FOCUSED_TEXTBOX # ------------------------------------------------------------------ sub focusHandling { ($FOCUSED_TEXTBOX) = @_; } # ------------------------------------------------------------------ # FUNCTION NAME: changedHandling # FUNCTIONALITY: to check which text box has bee modified # PRECONDITION: call back from the text box when the content # get modified # POSTCONDITION: The variable concerning the change is updated # ------------------------------------------------------------------ sub changedHandling { my ($widget) = @_; if ($widget == $TEXT) { $TEXT_CHANGE = 1; } elsif ($widget == $TEXT_PREFIX) { $PREFIX_CHANGE = 1; } elsif ($widget == $TEXT_INFIX) { $INFIX_CHANGE = 1; } elsif ($widget == $TEXT_POSTFIX) { $POSTFIX_CHANGE = 1; } $STATUS_BAR->set_text('To update the modification, click on Update button.'); } # ------------------------------------------------------------------ # FUNCTION NAME: CreatePIPtextboxes # FUNCTIONALITY: to create prefix, infix and postfix text boxes # PRECONDITION: vpaned is provided # POSTCONDITION: the prefix, infix, postfix text boxes are created # ------------------------------------------------------------------ sub CreatePIPtextboxes { my ($vpaned) = @_; $box = new Gtk::VBox(0,0); $box->border_width(0); $vpaned->add2($box); $box->show; $paned1 = new Gtk::VPaned; $box->pack_start($paned1, 1, 1, 0); $paned1->border_width(0); $paned1->set_handle_size(15); $paned1->set_gutter_size(15); $paned1->show; #------------------ #textbox for Prefix #------------------ $scrolledWin = new Gtk::ScrolledWindow(undef, undef); $scrolledWin->set_policy ('automatic', 'automatic'); $scrolledWin->set_usize(200,100); $TEXT_PREFIX = new Gtk::Text(undef,undef); $TEXT_PREFIX->signal_connect("changed", \&changedHandling); $TEXT_PREFIX->signal_connect("focus_in_event", \&focusHandling); $TEXT_PREFIX->set_editable(1); show $TEXT_PREFIX; $frame = new Gtk::Frame("Prefix"); $frame->add($scrolledWin); $scrolledWin->add($TEXT_PREFIX); $paned1->add1($frame); $scrolledWin->show; #------------------ # Create box and vpaned #------------------ $box1 = new Gtk::VBox(0,0); $box1->border_width(0); $paned1->add2($box1); $box1->show; $paned2 = new Gtk::VPaned; $box1->pack_start($paned2, 1, 1, 0); $paned2->border_width(0); $paned2->set_handle_size(15); $paned2->set_gutter_size(15); $paned2->show; #------------------ #textbox for Infix #------------------ $scrolledWin = new Gtk::ScrolledWindow(undef, undef); $scrolledWin->set_policy ('automatic', 'automatic'); $scrolledWin->set_usize(200,50); $TEXT_INFIX = new Gtk::Text(undef,undef); $TEXT_INFIX->signal_connect("changed", \&changedHandling); $TEXT_INFIX->signal_connect("focus_in_event", \&focusHandling); $TEXT_INFIX->set_editable(1); show $TEXT_INFIX; $frame = new Gtk::Frame("Infix"); $frame->add($scrolledWin); $scrolledWin->add($TEXT_INFIX); $paned2->add1($frame); $scrolledWin->show; #------------------ #textbox for Postfix #------------------ $scrolledWin = new Gtk::ScrolledWindow(undef, undef); $scrolledWin->set_policy ('automatic', 'automatic'); $scrolledWin->set_usize(200,100); $TEXT_POSTFIX = new Gtk::Text(undef,undef); $TEXT_POSTFIX->signal_connect("changed", \&changedHandling); $TEXT_POSTFIX->signal_connect("focus_in_event", \&focusHandling); $TEXT_POSTFIX->set_editable(1); show $TEXT_POSTFIX; $frame = new Gtk::Frame("Postfix"); $frame->add($scrolledWin); $scrolledWin->add($TEXT_POSTFIX); $paned2->add2($frame); $scrolledWin->show; } # ---------------------------------------------------------- # Message Box # ---------------------------------------------------------- # ------------------------------------------------------------------ # FUNCTION NAME: CreateDiaBox # FUNCTIONALITY: to create dialog box for messages # PRECONDITION: text --> message # flag --> from which function that call this function # POSTCONDITION: dialog box is created # ------------------------------------------------------------------ sub CreateDiaBox { my ($text, $flag, $function, $filename) = @_; local $dialogWin = new Gtk::Dialog; my($label, $button); $dialogWin->signal_connect("destroy", \&destroy_window, \$dialogWin); $dialogWin->signal_connect("delete_event", \&destroy_window, \$dialogWin); $dialogWin->set_title("Message"); $dialogWin->set_policy(0,0,1); $dialogWin->border_width(0); $dialogWin->set_uposition(150,150); my $pict = ""; if ($function eq "-openPanes") { $pict = new_pixmap("pict/exclamation.xpm",$MAIN_WINDOW->window, $MAIN_WINDOW->style->bg('normal')); } else { $pict = new_pixmap("pict/message.xpm",$MAIN_WINDOW->window, $MAIN_WINDOW->style->bg('normal')); } $pict->show; $label = new Gtk::Label "$text"; $label->set_padding(20,20); $label->show; $box = new Gtk::HBox(0,0); $box->pack_start($pict, 1,1,0); $box->pack_start($label, 1,1,0); $box->show; $dialogWin->vbox->pack_start($box, 1, 1, 0); $MAIN_WINDOW->set_sensitive(0); if ($flag eq "-OC") {createDiaOC($function,$filename); } elsif ($flag eq "-YNC") {createDiaYNC($function,$filename); } elsif ($flag eq "-O") {createDiaO($function,$filename); } $dialogWin->show; } # ------------------------------------------------------------------ # FUNCTION NAME: createDiaO # FUNCTIONALITY: to create dialog box with OK button only # PRECONDITION: the dialog box widged is already created # POSTCONDITION: add the OK button to the dialog box # ------------------------------------------------------------------ sub createDiaO { $button = new Gtk::Button "OK"; $button->signal_connect("clicked", \&DiaOK, \$dialogWin, @_); $button->can_default(1); $dialogWin->action_area->pack_start($button, 1, 1, 0); $button->grab_default; $button->show; $MAIN_WINDOW->set_sensitive(1); } # ------------------------------------------------------------------ # FUNCTION NAME: createDiaOC # FUNCTIONALITY: to create dialog box with OK and cancel buttons # PRECONDITION: the dialog box widged is already created # POSTCONDITION: add the OK and cancel buttons to the dialog box # ------------------------------------------------------------------ sub createDiaOC { $button = new Gtk::Button "OK"; $button->signal_connect("clicked", \&DiaOK, \$dialogWin, @_); $button->can_default(1); $dialogWin->action_area->pack_start($button, 1, 1, 0); $button->grab_default; $button->show; $button = new Gtk::Button "Cancel"; $button->signal_connect("clicked", \&DiaCancel, \$dialogWin, @_); $button->can_default(1); $dialogWin->action_area->pack_start($button, 1, 1, 0); $button->show; } # ------------------------------------------------------------------ # FUNCTION NAME: createDiaYNC # FUNCTIONALITY: to create dialog box with yes, no and cancel buttons # PRECONDITION: the dialog box widged is already created # POSTCONDITION: add the yes, no and cancel buttons to the dialog box # ------------------------------------------------------------------ sub createDiaYNC { $button = new Gtk::Button "Yes"; $button->signal_connect("clicked", \&DiaYes, \$dialogWin, @_ ); $button->can_default(1); $dialogWin->action_area->pack_start($button, 1, 1, 0); $button->grab_default; $button->show; $button = new Gtk::Button "No"; $button->signal_connect("clicked", \&DiaNo, \$dialogWin, @_ ); $button->can_default(1); $dialogWin->action_area->pack_start($button, 1, 1, 0); $button->show; $button = new Gtk::Button "Cancel"; $button->signal_connect("clicked", \&DiaCancel, \$dialogWin, @_ ); $button->can_default(1); $dialogWin->action_area->pack_start($button, 1, 1, 0); $button->show; } # ------------------------------------------------------------------ # FUNCTION NAME: DiaOK # FUNCTIONALITY: To exit the dialog box # PRECONDITION: the dialog box is already pop up # POSTCONDITION: close dialog box # ------------------------------------------------------------------ sub DiaOK { my ($widget1, $widget2, $function) = @_; if (($function eq "-openPanes") || ($function eq "-writable") || ($function eq "-directory") || ($function eq "-aboutHelp")) { $$widget2->destroy; $MAIN_WINDOW->set_sensitive(1); } } # ------------------------------------------------------------------ # FUNCTION NAME: DiaCancel # FUNCTIONALITY: To cancel the job that is going to do # PRECONDITION: the dialog box is already pop up # POSTCONDITION: close the dialog box # ------------------------------------------------------------------ sub DiaCancel { my ($widget1, $widget2) = @_; $$widget2->destroy; $MAIN_WINDOW->set_sensitive(1); } # ------------------------------------------------------------------ # FUNCTION NAME: DiaYes # FUNCTIONALITY: to perform task according to its flag # PRECONDITION: the yes button of dialog box is clicked # POSTCONDITION: The task is performed # ------------------------------------------------------------------ sub DiaYes { my ($widget1, $widget2, $function, $filename) = @_; #quit if ($function eq "-quit") { #save the file and quit writeToFile($FILENAME); exitAll($FILENAME); } # open or new elsif (($function eq "-open") || ($function eq "-new")) { #save the file and then pop up the file selection window if ($FILENAME eq "") { CreateFileSelection("-saveAs"); } else { writeToFile ($FILENAME); } $$widget2->destroy; # if it is open function, open the file selection if ($function eq "-open") { CreateFileSelection("-open"); } } #overwrite elsif ($function eq "-overWrite") { #save the file my $tmpFilename = $FILENAME; writeToFile ($filename); $FILENAME = $filename; #update the .AXEsse.tb file removeIncludeFile($tmpFilename); open (FILE, ">>$AXEsse"); print FILE "$FILENAME\n"; close(FILE); $$widget2->destroy; $MAIN_WINDOW->set_sensitive(1); } } # ------------------------------------------------------------------ # FUNCTION NAME: DiaNo # FUNCTIONALITY: to cancel the required task to be perform # and do the next task # PRECONDITION: the no button in the dialog box is clicked # POSTCONDITION: the task is carried out # ------------------------------------------------------------------ sub DiaNo { my ($widget1, $widget2, $function) = @_; $$widget2->destroy; #open if ($function eq "-open") { #don't save the file and then pop up the file selection window $CHANGE = 0; CreateFileSelection("-open"); } # quit elsif ($function eq "-quit") { exitAll($FILENAME); } # new elsif ($function eq "-new") { if ($FILENAME ne "") { #need to remove it from the file .AXEsse.tb removeIncludeFile($FILENAME); } initialise(); } } # ---------------------------------------------------------- # Exit all windows # ---------------------------------------------------------- # ------------------------------------------------------------------ # FUNCTION NAME: destroy_window # FUNCTIONALITY: to close the window # PRECONDITION: the window exist # POSTCONDITION: the window is closed # ------------------------------------------------------------------ sub destroy_window { my($widget, $windowref, $w2) = @_; $$windowref = undef; $w2 = undef if defined $w2; $MAIN_WINDOW->set_sensitive(1); 0; } # ---------------------------------------------------------- # Create pixmap image # ---------------------------------------------------------- # ------------------------------------------------------------------ # FUNCTION NAME: new_pixmap # FUNCTIONALITY: to create pixmap image from file # PRECONDITION: the filename, window and the background # are provided # POSTCONDITION: the pixmap image is returned # ------------------------------------------------------------------ sub new_pixmap { my ($filename, $window, $background) = @_; my ($pixmap, $mask) = create_from_xpm Gtk::Gdk::Pixmap($window, $background, $filename); return new Gtk::Pixmap($pixmap, $mask); } # ---------------------------------------------------------- # Create Toolbar icon -- e.g. new, open, save, etc. # ---------------------------------------------------------- # ------------------------------------------------------------------ # FUNCTION NAME: CreateToolBar # FUNCTIONALITY: to create tool bar for the main window # PRECONDITION: the box attached to the window is provided # POSTCONDITION: tool bar is created # ------------------------------------------------------------------ sub CreateToolBar { my ($box) = @_; my ($window, $color, $button, $entry); $MAIN_WINDOW->realize unless $MAIN_WINDOW->realized; $window = $MAIN_WINDOW->window; $color = $MAIN_WINDOW->style->bg('normal'); # Create toolbar for both text and icons $toolbar = new Gtk::Toolbar('horizontal', 'both'); $toolbar->set_space_style('line'); $toolbar->set_button_relief("none"); #NEW -------------- $button = $toolbar->append_item( "New","New Translation File - Ctrl-N", "Toolbar/New", new_pixmap("pict/new.xpm",$window, $color)); $button->signal_connect('clicked', \&NewFile); #OPEN -------------- $button = $toolbar->append_item ( "Open", "Open Translation File - Ctrl-O", "Toolbar/Open", new_pixmap("pict/open.xpm",$window, $color)); $button->signal_connect('clicked', \&OpenFile); #SAVE -------------- $button = $toolbar->append_item ( "Save", "Save Translation File - Ctrl-S", "Toolbar/Save", new_pixmap("pict/save.xpm",$window, $color)); $button->signal_connect('clicked', \&SaveFile); $toolbar->append_space(); #UNDO -------------- $button = $toolbar->append_item ( "Undo", "Undo", "Toolbar/Undo", new_pixmap("pict/undo.xpm",$window, $color)); $button->signal_connect('clicked', \&EditUndo); #REDO -------------- $button = $toolbar->append_item ( "Redo", "Redo", "Toolbar/Redo", new_pixmap("pict/redo.xpm",$window, $color)); $button->signal_connect('clicked', \&EditRedo); $toolbar->append_space(); #CUT -------------- $button = $toolbar->append_item ( "Cut", "Cut - Ctrl-X", "Toolbar/Cut", new_pixmap("pict/cut.xpm",$window, $color)); $button->signal_connect('clicked', \&EditCut); #SAVE -------------- $button = $toolbar->append_item ( "Copy", "Copy - Ctrl-C", "Toolbar/Copy", new_pixmap("pict/copy.xpm",$window, $color)); $button->signal_connect('clicked', \&EditCopy); #SAVE -------------- $button = $toolbar->append_item ( "Paste", "Paste - Ctrl-V", "Toolbar/Paste", new_pixmap("pict/paste.xpm",$window, $color)); $button->signal_connect('clicked', \&EditPaste); $toolbar->append_space(); #UPDATE -------------- $button = $toolbar->append_item ( "Update", "Update text modification", "Toolbar/Update", new_pixmap("pict/update.xpm",$window, $color)); $button->signal_connect('clicked', \&UpdateTag); $toolbar->append_space(); $box->pack_start($toolbar, 0, 0, 0); $toolbar->show; } # ------------------------------------------------------------------------ # MENUBAR # ------------------------------------------------------------------------ my @menubar_entry = ( # FILE ["/_File", undef ,0, ""], ["/File/New Window", "undef" ,14], #New window ["/File/sep3", undef ,0, ""], #separator ["/File/_New ", "N" ,1], #New ["/File/_Open ", "O" ,2], #Open ["/File/_Save ", "S" ,3], #Save ["/File/Save _As", undef ,4], #Save As ["/File/sep1", undef ,0, ""], #separator ["/File/_Exit ", "Q" ,5], #Quit # Edit ["/_Edit", undef ,0, ""], ["/Edit/_Undo ", undef ,6], #Undo ["/Edit/_Redo ", undef ,7], #Redo ["/Edit/sep2 ", undef ,0, ""], ["/Edit/_Update ", undef ,20], #Redo ["/Edit/_Insert ", undef ,17], #Redo ["/Edit/_Append ", undef ,18], #Redo ["/Edit/_Delete ", undef ,19], #Redo ["/Edit/sep3 ", undef ,0, ""], ["/Edit/Cu_t ", "X" ,8], #Cut ["/Edit/_Copy ", "C" ,9], #Copy ["/Edit/_Paste ", "V" ,10], #Paste # PREFERENCES ["/_Preferences", undef, 0, ""], ["/_Preferences/Icon only", undef, 11, ""], ["/_Preferences/Text only", undef, 12, ""], ["/_Preferences/Icon & Text", undef, 13, ""], # HELP ["/_Help", "F1", 0, ""], ["/Help/_Content", undef, 15], ["/Help/sep3 ", undef ,0, ""], ["/Help/_About AXEsse", undef, 16] ); # ------------------------------------------------------------------ # FUNCTION NAME: CreateMenuBar # FUNCTIONALITY: to create menu bar for the main window # PRECONDITION: the box attached to the window is provided # POSTCONDITION: menu bar is created # ------------------------------------------------------------------ sub CreateMenuBar { my ($box) = @_; $accel_group = new Gtk::AccelGroup; $menu_item = new Gtk::ItemFactory('Gtk::MenuBar', "
", $accel_group); $accel_group->attach($MAIN_WINDOW); foreach (@menubar_entry) { $menu_item->create_item($_, \&CreateMBItem); } $box->pack_start($menu_item->get_widget('
'), 0, 0, 0); return $box; } # ------------------------------------------------------------------ # FUNCTION NAME: CreateMBItem # FUNCTIONALITY: action to be carried out according to what # menu item being clicked # PRECONDITION: menu item is clicked # POSTCONDITION: the action is carried out # ------------------------------------------------------------------ sub CreateMBItem #Action of Menu Bar Item { my ($widget, $action, @data) = @_; if ($action == 1) {NewFile();} elsif ($action == 2) {OpenFile();} elsif ($action == 3) {SaveFile();} elsif ($action == 4) {SaveFileAs();} elsif ($action == 5) {QuitFile();} elsif ($action == 6) {EditUndo();} elsif ($action == 7) {EditRedo();} elsif ($action == 8) {EditCut();} elsif ($action == 9) {EditCopy();} elsif ($action == 10) {EditPaste();} elsif ($action == 11) {$toolbar->set_style('icons');} elsif ($action == 12) {$toolbar->set_style('text');} elsif ($action == 13) {$toolbar->set_style('both');} elsif ($action == 14) {NewWindow();} elsif ($action == 15) {HelpContent();} elsif ($action == 16) {AboutAXEsse();} elsif ($action == 17) {InsertTag(0, $CLIST, $entry);} elsif ($action == 18) {AppendTag(0, $CLIST, $entry);} elsif ($action == 19) {DeleteTag();} elsif ($action == 20) {UpdateTag();} } # ------------------------------------------------------------------ # FUNCTION NAME: NewFile # FUNCTIONALITY: to initialise the current window # PRECONDITION: The new button or menu item is clicked # POSTCONDITION: the window is initialised # ------------------------------------------------------------------ sub NewFile { # need to check whether it has been modify or not if ($CHANGE == 1) { #save it first and then open CreateDiaBox("The document has been modified.\nWould you like to save it?\n", "-YNC", "-new", $filename); } else { if ($FILENAME ne "") { #need to remove it from the file .AXEsse.tb removeIncludeFile($FILENAME); } initialise(); } } # ------------------------------------------------------------------ # FUNCTION NAME: NewWindow # FUNCTIONALITY: to display another window # PRECONDITION: none # POSTCONDITION: the new window is displayed # ------------------------------------------------------------------ sub NewWindow { OpenPanes(""); } # ------------------------------------------------------------------ # FUNCTION NAME: HelpContent # FUNCTIONALITY: To execute netscape to provide help info # PRECONDITION: AXEsseHelp.html file exist and netscape # is running # POSTCONDITION: the help file is opened using netscape # ------------------------------------------------------------------ sub HelpContent { system "netscape AXEsseHelp.html &"; } # ------------------------------------------------------------------ # FUNCTION NAME: AboutAXEsse # FUNCTIONALITY: to display information about AXEsse # PRECONDITION: CreateDiaBox dialog box function exist # POSTCONDITION: dispaly the dialog box about AXEsse information # ------------------------------------------------------------------ sub AboutAXEsse { CreateDiaBox("AXEsse - Version 0.1\n\n". "Copyright 2000\nSusanti\n\n", "-O", "-aboutHelp"); } # ------------------------------------------------------------------ # FUNCTION NAME: OpenFile # FUNCTIONALITY: to open existing file # PRECONDITION: CreateDiaBox and CreateFileSelection functions # exist # POSTCONDITION: either pop up dialog box stating the file # has not been saved or # pop up file selection dialog box allowing # user to select the file # ------------------------------------------------------------------ sub OpenFile { # need to check whether it has been modify or not if ($CHANGE == 1) { #save it first and then open CreateDiaBox("The document has been modified.\nWould you like to save it?\n", "-YNC", "-open", $filename); } else { CreateFileSelection("-open"); } } # ------------------------------------------------------------------ # FUNCTION NAME: initialise # FUNCTIONALITY: to initialise the current application # PRECONDITION: none # POSTCONDITION: the current application was initialised # ------------------------------------------------------------------ sub initialise { $MAIN_WINDOW->set_title("AXEsse - notitle"); $FILENAME=""; @FILE_CONTENT=(); @ALL_TAGS=(); $CLIST->clear; $CLIST_ROW = 0; # clean up the text-boxes cleanUp($TEXT); cleanUp($TEXT_PREFIX); cleanUp($TEXT_INFIX); cleanUp($TEXT_POSTFIX); $CHANGE= 0; $TEXT_CHANGE= 0; $PREFIX_CHANGE= 0; $INFIX_CHANGE= 0; $POSTFIX_CHANGE= 0; $STATUS_BAR->set_text(""); $FOCUSED_TEXTBOX=$TEXT; @UNDO_BUFFER=(); @REDO_BUFFER=(); } # -------------------------------------------------------------------- # FILE SELECTION # -------------------------------------------------------------------- # ------------------------------------------------------------------ # FUNCTION NAME: CreateFileSelection # FUNCTIONALITY: to create file selection dialog box # PRECONDITION: flag indicate: save as or open functions # POSTCONDITION: the file selection dialog box is created # ------------------------------------------------------------------ sub CreateFileSelection { my ($flag) = @_; my $fs_window; my $title=""; if ($flag eq "-saveAs") { $title = "Save As"; } else { $title = "Open"; } if (not defined $fs_window) { $fs_window = new Gtk::FileSelection "$title"; $fs_window->position(-mouse); $fs_window->signal_connect("destroy", \&destroy_window, \$fs_window); $fs_window->signal_connect("delete_event", \&destroy_window, \$fs_window); $fs_window->ok_button->signal_connect("clicked", \&FileSelectOK, \$fs_window, $flag); $fs_window->cancel_button->signal_connect("clicked", sub { destroy $fs_window; $MAIN_WINDOW->set_sensitive(1); }); $fs_window->set_uposition(150,150); } $MAIN_WINDOW->set_sensitive(0); if (!visible $fs_window) { show $fs_window; } } # ------------------------------------------------------------------ # FUNCTION NAME: FileSelectOK # FUNCTIONALITY: Do the action when user clicks ok button # PRECONDITION: the ok button of file selection dialog # box is clicked # POSTCONDITION: the action is carried out # ------------------------------------------------------------------ sub FileSelectOK { my ($widget1, $widget2, $flag) = (@_); my $filename = $$widget2->get_filename; $filename =~ /(\/.*\/)*.*/; $PATH = $1; if ($flag eq "-open") { #Ready to read tags after closing File Selection Window if ((-e $filename) && (-r $filename)) { #check first if ($FILENAME ne "") { removeIncludeFile($FILENAME); } initialise(); $FILENAME = $filename; $MAIN_WINDOW->set_title("AXEsse - $FILENAME"); readTags($FILENAME); addTagList(); #update the .AXEsse.tb file open(FILE, ">>$AXEsse"); print FILE "$FILENAME\n"; close(FILE); } else { CreateDiaBox ("The file - $filename - does not exist or ". "is not readable.\n" . "Please make sure that the file is exist and readable.", "-O", "-openPanes"); } } elsif ($flag eq "-saveAs") { # if the file exist, ask user whether want to replace or not if (-e $filename) { CreateDiaBox ("The file is exist.\n" . "Do you want to overwrite it?\n", "-YNC", "-overWrite", $filename); } elsif (-d $filename) { CreateDiaBox ("The file selected is a directory name.\n" . "Please select the correct filename.\n", "-O", "-directory"); } else { #save the file $tmpFilename = $FILENAME; writeToFile($filename); $FILENAME = $filename; #update the .AXEsse.tb file removeIncludeFile($tmpFilename); open (FILE, ">>$AXEsse"); print FILE "$FILENAME\n"; close(FILE); } } $$widget2->destroy; $MAIN_WINDOW->set_sensitive(1); } # ------------------------------------------------------------------ # FUNCTION NAME: SaveFile # FUNCTIONALITY: to save the current content to the file # PRECONDITION: filename is provided # POSTCONDITION: the content is saved by calling writeToFile # function # ------------------------------------------------------------------ sub SaveFile { #getfilename $filename = $FILENAME; #if it's a new file, and haven't been save. Ask for filename if ($filename eq "") { CreateFileSelection("-saveAs"); } else { writeToFile($filename); } } # ------------------------------------------------------------------ # FUNCTION NAME: writeToFile # FUNCTIONALITY: write the content to the filename # PRECONDITION: the filename is provided # POSTCONDITION: the content is saved # ------------------------------------------------------------------ sub writeToFile { my ($filename) = @_; if (open (INPUT, ">$filename")) { foreach $tag (@ALL_TAGS) { print INPUT "$$tag{content}"; } close INPUT; $CHANGE = 0; } else { CreateDiaBox ("The file is not writable.\nPlease close the file if it is opened.\n". "Or select other filename\n", "-O", "-writable"); return; } $MAIN_WINDOW->set_title("AXEsse - $filename"); } # ------------------------------------------------------------------ # FUNCTION NAME: SaveFileAs # FUNCTIONALITY: to display a file selection dialog box # PRECONDITION: CreateFileSelection function exist # POSTCONDITION: the file seleciton dialog box is displayed # ------------------------------------------------------------------ sub SaveFileAs { #save to file that is given CreateFileSelection("-saveAs"); } # ------------------------------------------------------------------ # FUNCTION NAME: QuitFile # FUNCTIONALITY: to quit the application # PRECONDITION: CreateDiaBox function exist # POSTCONDITION: quit the application # ------------------------------------------------------------------ sub QuitFile { if ($CHANGE == 0) { exitAll($FILENAME); } else { CreateDiaBox("The document has been modified.\nWould you like to save it?\n", "-YNC", "-quit"); } #to avoid the window to be deleted/destroyed print ""; } # ------------------------------------------------------------------ # FUNCTION NAME: exitAll # FUNCTIONALITY: to make sure temporary file AXEsse.tb # is deleted for the last application # PRECONDITION: filename is provided # POSTCONDITION: the filename in that file is deleted # ------------------------------------------------------------------ sub exitAll { my ($filename) = @_; if ($filename ne "") { removeIncludeFile($filename); } #check whether file still has content, my $tmp=""; my $i=0; open (FILE, $AXEsse) or die "-Cannot open the file\n"; while() { $i++; } close FILE; # if no, delete the .AXEsse.tb file if ($i == 0) { system "rm .AXEsse.tb"; } Gtk->exit(0); } # ------------------------------------------------------------------ # FUNCTION NAME: EditCut # FUNCTIONALITY: to cut selected text from a text box # PRECONDITION: text box and text are selected # POSTCONDITION: the selected text is cut # ------------------------------------------------------------------ sub EditCut { $FOCUSED_TEXTBOX->cut_clipboard(); } # ------------------------------------------------------------------ # FUNCTION NAME: EditCopy # FUNCTIONALITY: to copy selected text form a text box # PRECONDITION: text box and text are selected # POSTCONDITION: the selected text is copied # ------------------------------------------------------------------ sub EditCopy { $FOCUSED_TEXTBOX->copy_clipboard(); } # ------------------------------------------------------------------ # FUNCTION NAME: EditPaste # FUNCTIONALITY: to paste the content from buffer to selected # text box # PRECONDITION: text box is selected # POSTCONDITION: paste the content of buffer to selected # textbox # ------------------------------------------------------------------ sub EditPaste { $FOCUSED_TEXTBOX->paste_clipboard(); } # ------------------------------------------------------------------ # FUNCTION NAME: EditUndo # FUNCTIONALITY: to undo the previous action # PRECONDITION: user clicks on undo menu item or button # POSTCONDITION: the previous action is undone # ------------------------------------------------------------------ sub EditUndo { my @tmp=(); my $i=0; if (!defined($tmp[$i] = pop @UNDO_BUFFER)) { $STATUS_BAR->set_text("There is nothing to undo"); return; } my $row = $tmp[$i]{listPos}; #INSERT and APPEND ----------------------------------------------- if (($tmp[$i]{bufferType} eq "-insert") || ($tmp[$i]{bufferType} eq "-append")) { # just to make sure I am deleting the correct one if ($ALL_TAGS[$row]{tag} eq $tmp[$i]{tag}) { # Update REDO buffer-------------------------- insertOneList2Array($tmp[$i]); # -------------------------------------------- deleteOneList($row); } while ($tmp[$i]{group} != 0) { $i++; $tmp[$i] = pop @UNDO_BUFFER; $row = $tmp[$i]{listPos}; # just to make sure I am deleting the correct one if ($ALL_TAGS[$row]{tag} eq $tmp[$i]{tag}) { # Update REDO buffer ------------------ insertOneList2Array($tmp[$i]); # ------------------------------------- deleteOneList($row); } } $CLIST->select_row($CLIST_ROW-1,0); } #DELETE------------------------------------------------------- elsif ($tmp[$i]{bufferType} eq "-delete") { # Update REDO buffer-------------------------- insertOneList2Array($tmp[$i]); # -------------------------------------------- #insert back to the list splice @ALL_TAGS, $row, 0, @tmp; add1Tag("-insert", $row, $tmp[$i]{type}, $tmp[$i]{tag}); } #UPDATE ------------------------------------------------------- elsif ($tmp[$i]{bufferType} eq "-update") { while ($tmp[$i]{group} != 0) { #just to make sure I am deleting the correct one if ($ALL_TAGS[$row]{tag} eq $tmp[$i]{tag}) { # Update REDO buffer-------------------- insertOneList2Array($tmp[$i]); # -------------------------------------- deleteOneList($row); } $i++; $tmp[$i] = pop @UNDO_BUFFER; $row = $tmp[$i]{listPos}; } if ($tmp[$i]{group} == 0) { # Update REDO buffer-------------------------- insertOneList2Array($tmp[$i]); # -------------------------------------------- if ($tmp[$i]{type} ne "") { #insert back to the list splice @ALL_TAGS, $row, 0, $tmp[$i]; add1Tag("-insert", $row, $tmp[$i]{type}, $tmp[$i]{tag}); } } $CLIST->select_row($CLIST_ROW-1,0); } } # ------------------------------------------------------------------ # FUNCTION NAME: deleteOneList # FUNCTIONALITY: to delete a list from ALL_TAGS array # PRECONDITION: none # POSTCONDITION: a list from ALL_TAGS array is deleted # ------------------------------------------------------------------ sub deleteOneList { my ($row) = @_; # clean up the text-boxes cleanUp($TEXT); cleanUp($TEXT_PREFIX); cleanUp($TEXT_INFIX); cleanUp($TEXT_POSTFIX); $CLIST->freeze; splice @ALL_TAGS, $row,1; $CLIST->remove($row); $CLIST->thaw; } # ------------------------------------------------------------------ # FUNCTION NAME: insertOneList2Array # FUNCTIONALITY: to insert the list to REDO_BUFFER array # PRECONDITION: REDO_BUFFER exist # POSTCONDITION: REDO_BUFFER is updated # ------------------------------------------------------------------ sub insertOneList2Array { push @REDO_BUFFER, @_; } # ------------------------------------------------------------------ # FUNCTION NAME: EditRedo # FUNCTIONALITY: to redo the action that has been undone # PRECONDITION: redo button/menu item is clicked # POSTCONDITION: the previous action is redone # ------------------------------------------------------------------ sub EditRedo { my @tmp=(); my $i=0; if (!defined($tmp[$i] = pop @REDO_BUFFER)) { $STATUS_BAR->set_text("There is nothing to redo"); return; } my $row = $tmp[$i]{listPos}; $CHANGE = 1; #INSERT and APPEND --------------------------------------------- if (($tmp[$i]{bufferType} eq "-insert") || ($tmp[$i]{bufferType} eq "-append")) { while ( $#REDO_BUFFER > -1) { if ($REDO_BUFFER[$#REDO_BUFFER]{group} != 0) { $i++; $tmp[$i] = pop @REDO_BUFFER; } else { last; } } #UPDATE UNDO LIST ---------------- push @UNDO_BUFFER, @tmp; #-------------------------------- UpdateListAndArray($row,@tmp); } #DELETE------------------------------------------------------- elsif ($tmp[$i]{bufferType} eq "-delete") { #UPDATE UNDO LIST ---------------- push @UNDO_BUFFER, @tmp; #-------------------------------- deleteOneList($row); } #UPDATE ------------------------------------------------------- elsif ($tmp[$i]{bufferType} eq "-update") { my @undo=(); $j=0; while ($REDO_BUFFER[$#REDO_BUFFER]{group} != 0) { $undo[$j] = pop @REDO_BUFFER; $j++; if ($#REDO_BUFFER < 0) {last;} } #UPDATE UNDO LIST ---------------- push @UNDO_BUFFER, @tmp; push @UNDO_BUFFER, @undo; #-------------------------------- deleteOneList($row); UpdateListAndArray($row,@undo); } $CLIST->select_row($CLIST_ROW,0); } # ------------------------------------------------------------------ # FUNCTION NAME: UpdatedTag # FUNCTIONALITY: to update the changes made in text box # PRECONDITION: any of content/prefix/infix/postfix is changed # can update button/menu item is clicked # POSTCONDITION: the contet is updated # ------------------------------------------------------------------ sub UpdateTag { my @updatedList= (); my @list= (); my $content= ""; my $tag= ""; my $infix = ""; my $prefix = ""; my $postfix = ""; # If nothing is changed, don't do anything if (!($TEXT_CHANGE) && !($PREFIX_CHANGE) && !($INFIX_CHANGE) && !($POSTFIX_CHANGE)) { $STATUS_BAR->set_text("There is nothing to update"); return; } if ($TEXT_CHANGE) { $content = $TEXT->get_chars(0,-1); } else { $tag = $ALL_TAGS[$CLIST_ROW]{tag}; $prefix = $TEXT_PREFIX->get_chars(0,-1); $infix = $TEXT_INFIX->get_chars(0,-1); $postfix = $TEXT_POSTFIX->get_chars(0,-1); $content = "<" . $tag . ">" . $prefix . "." . $infix . "." . $postfix . "\n\t\n"; } $CLIST->set_row_height(25); #Validate the change @list = scalarToArray($content); @updatedList = identifyTags(@list); getPIP(\@updatedList); #UPDATE UNDO LIST ---------------- my @undo=(); my $row = $CLIST_ROW; my $i=0; if (!defined $ALL_TAGS[$row]) { $undo[$i] = { type => "", tag => "", content => "", comment => "", prefix => "", infix => "", postfix => "", group => 0, bufferType => "-update", listPos => $row, }; } else { $undo[$i] = { type => $ALL_TAGS[$row]{'type'}, tag => $ALL_TAGS[$row]{'tag'}, content => $ALL_TAGS[$row]{'content'}, comment => $ALL_TAGS[$row]{'comment'}, prefix => $ALL_TAGS[$row]{'prefix'}, infix => $ALL_TAGS[$row]{'infix'}, postfix => $ALL_TAGS[$row]{'postfix'}, group => 0, bufferType => "-update", listPos => $row, }; } $i++; foreach $item (@updatedList) { $undo[$i] = $item; $undo[$i]{'group'} = $i; $undo[$i]{'bufferType'} = "-update"; $undo[$i]{'listPos'} = $row++; $i++; } push @UNDO_BUFFER, @undo; #-------------------------------- my $rowToDelete = $CLIST_ROW; #update the list $row = $CLIST_ROW; UpdateListAndArray($row, @updatedList); #remove the current tag in the list and in the array $rowToDelete = $rowToDelete + 1 + $#updatedList; $CLIST->remove ($rowToDelete); splice @ALL_TAGS, $rowToDelete, 1; $CLIST->select_row($row,0); #after update, change the status of the textboxes to 0 again $TEXT_CHANGE = 0; $PREFIX_CHANGE = 0; $INFIX_CHANGE = 0; $POSTFIX_CHANGE = 0; #set the CHANGE flag to 1, since the document has been modified $CHANGE = 1; } # ------------------------------------------------------------------ # FUNCTION NAME: UpdateListAndArray # FUNCTIONALITY: to modify list to array # PRECONDITION: the row number and the list is provided # POSTCONDITION: the list is modified to array # ------------------------------------------------------------------ sub UpdateListAndArray { my ($clistrow, @InsertTags) = @_; #insert to array ALL_TAGS splice @ALL_TAGS, $clistrow, 0, @InsertTags; # insert to clist $CLIST->set_row_height(25); #add to tag in the list --> the otherway round, #to get the corrent one $CLIST->freeze; my $i=@InsertTags-1; for (; $i>=0;$i--) { add1Tag("-insert", $clistrow, $InsertTags[$i]{type}, $InsertTags[$i]{tag}); } $CLIST->select_row($CLIST_ROW,0); $CLIST->thaw; } # ---------------------------------------------------------------------- # LIST # ---------------------------------------------------------------------- # ------------------------------------------------------------------ # FUNCTION NAME: CreateList # FUNCTIONALITY: to create element list screen # PRECONDITION: a box attached to the main window is provided # POSTCONDITION: the element list screen is created # ------------------------------------------------------------------ sub CreateList { my ($box) = @_; my $scrolledWin; $scrolledWin = new Gtk::ScrolledWindow(undef, undef); $scrolledWin->set_policy ('automatic', 'automatic'); $scrolledWin->set_usize(250,350); $CLIST = new_with_titles Gtk::CList("Tags"); $CLIST->signal_connect('select_row', \&DisplayTag); $CLIST->set_column_width(0, 100); $CLIST->set_selection_mode('browse'); $CLIST->set_column_justification(1, 'right'); $CLIST->border_width(1); $scrolledWin->add($CLIST); $box->pack_start($scrolledWin, 1, 1, 0); $CLIST->show; $scrolledWin->show; #insert separator $separator = new Gtk::HSeparator; $box->pack_start($separator, 0, 1, 0); $separator->show; createInsert($box); } # ------------------------------------------------------------------ # FUNCTION NAME: createInsert # FUNCTIONALITY: to create insert text box, also insert, append # and delete buttons # PRECONDITION: box is provided # POSTCONDITION: insert text box, insert, append and delete # buttons are created # ------------------------------------------------------------------ sub createInsert { my ($box) = @_; #add box for button my $buttonBox = new Gtk::VBox(0,0); $buttonBox->border_width(1); $box->pack_start($buttonBox, 1,1,0); $buttonBox->show; my $label = new Gtk::Label("Insert/Append:"); $buttonBox->pack_start($label, 1,1,0); $label->show; # add text box where to insert $scrolledWin = new Gtk::ScrolledWindow(undef, undef); $scrolledWin->set_policy ('automatic', 'automatic'); $scrolledWin->set_usize(250,150); $entry = new Gtk::Text; $entry->signal_connect("focus_in_event", \&focusHandling); $entry->set_editable(1); $scrolledWin->add($entry); $scrolledWin->show; $buttonBox->pack_start($scrolledWin, 1, 1, 0); $entry->show; #add insert Button my $insertBut = new Gtk::Button "Insert"; $buttonBox->pack_start($insertBut, 1,0,1); $insertBut->signal_connect("clicked", \&InsertTag, $CLIST, $entry); $insertBut->can_default(1); $insertBut->grab_default; $insertBut->show; #add Append Button my $appendBut = new Gtk::Button "Append"; $buttonBox->pack_start($appendBut, 1,0,1); $appendBut->signal_connect("clicked", \&AppendTag, $CLIST, $entry); $appendBut->show; #add delete Button my $deleteBut = new Gtk::Button "Delete"; $buttonBox->pack_start($deleteBut, 1,0,1); $deleteBut->signal_connect("clicked", \&DeleteTag); $deleteBut->show; } # ------------------------------------------------------------------ # FUNCTION NAME: DisplayTag # FUNCTIONALITY: To display the tag content according to which # element user selected # PRECONDITION: a row in the list is selected # POSTCONDITION: the content of that row is selected # ------------------------------------------------------------------ sub DisplayTag { my($widget, $row, $column, $event) = @_; #Initialize the content of the Text box $CLIST_ROW = $row; # clean up the text-boxes cleanUp($TEXT); cleanUp($TEXT_PREFIX); cleanUp($TEXT_INFIX); cleanUp($TEXT_POSTFIX); # change it to uneditable $TEXT->set_editable(0); $TEXT_PREFIX->set_editable(0); $TEXT_INFIX->set_editable(0); $TEXT_POSTFIX->set_editable(0); #Initialise the change circumstances $TEXT_CHANGE = 0; $PREFIX_CHANGE = 0; $INFIX_CHANGE = 0; $POSTFIX_CHANGE = 0; #display statusbar $STATUS_BAR->set_text($ALL_TAGS[$row]{comment}); # Display Tag and set editable of text boxes to true #include if ($ALL_TAGS[$row]{'type'} == 1) { #open new window for the file my ($filename) = ($ALL_TAGS[$row]{'content'} =~ /^include\s*(\S+)/); if (!OpenPanes ($filename, "-include")) { $STATUS_BAR->set_text("The file - $filename - does not exist or is not readable"); } $TEXT->insert(undef, $TEXT->style->black, undef, $ALL_TAGS[$row]{'content'}); $TEXT->set_editable(1); } #tag elsif ($ALL_TAGS[$row]{'type'} == 3) { $TEXT->set_editable(1); $TEXT_PREFIX->set_editable(1); $TEXT_INFIX->set_editable(1); $TEXT_POSTFIX->set_editable(1); $TEXT->insert(undef, $TEXT->style->black, undef, $ALL_TAGS[$row]{'content'}); # Insert Prefix $TEXT_PREFIX->insert(undef, $TEXT_PREFIX->style->black, undef, $ALL_TAGS[$row]{'prefix'}); # Insert Infix $TEXT_INFIX->insert(undef, $TEXT_INFIX->style->black, undef, $ALL_TAGS[$row]{'infix'}); # Insert Postfix $TEXT_POSTFIX->insert(undef, $TEXT_POSTFIX->style->black, undef, $ALL_TAGS[$row]{'postfix'}); } #error elsif ($ALL_TAGS[$row]{'type'} == 6) { $TEXT->set_editable(1); $TEXT->insert(undef, $TEXT->style->black, undef, $ALL_TAGS[$row]{'content'}); $TEXT_PREFIX->set_editable(1); $TEXT_INFIX->set_editable(1); $TEXT_POSTFIX->set_editable(1); } # others only have the text, don't have prefix, infix, and postfix # so, make them none editable, except for the content display. else { # if it is newline, don't allow any edition if ($ALL_TAGS[$row]{'type'} != 5) { $TEXT->set_editable(1); } $TEXT->insert(undef, $TEXT->style->black, undef, $ALL_TAGS[$row]{'content'}); $TEXT_PREFIX->set_editable(0); $TEXT_INFIX->set_editable(0); $TEXT_POSTFIX->set_editable(0); } } # ------------------------------------------------------------------ # FUNCTION NAME: cleanUp # FUNCTIONALITY: to clear up the text box # PRECONDITION: a text box is provided # POSTCONDITION: the text box is cleaned # ------------------------------------------------------------------ sub cleanUp { my ($text) = @_; $len = $text->get_length; $text->set_point(0); $text->forward_delete($len); } # ------------------------------------------------------------------ # FUNCTION NAME: add1Tag # FUNCTIONALITY: to add one element to the list # PRECONDITION: setting, row, type and tag are provided # POSTCONDITION: one element is added to the list # ------------------------------------------------------------------ sub add1Tag { my ($setting, $row, $type, $tag) = @_; if ($setting eq "-append") { $CLIST->append("$tag"); } else { $CLIST->insert($row, $tag); } #include file if ($type == 1) { my ($pixmap1, $mask1) = Gtk::Gdk::Pixmap->create_from_xpm($CLIST->clist_window, $CLIST->style->white, "pict/include.xpm"); $CLIST->set_pixtext($row,0,$tag, 20, $pixmap1, $mask1); } #comment elsif ($type == 2) { my ($pixmap2, $mask2) = Gtk::Gdk::Pixmap->create_from_xpm($CLIST->clist_window, $CLIST->style->white, "pict/comment.xpm"); $CLIST->set_pixtext($row,0,$tag, 20, $pixmap2, $mask2); } #tag elsif ($type == 3) { my ($pixmap3, $mask3) = Gtk::Gdk::Pixmap->create_from_xpm($CLIST->clist_window, $CLIST->style->white, "pict/tag.xpm"); $CLIST->set_pixtext($row,0,$tag, 20, $pixmap3, $mask3); } #element elsif ($type == 4) { my ($pixmap4, $mask4) = Gtk::Gdk::Pixmap->create_from_xpm($CLIST->clist_window, $CLIST->style->white, "pict/element.xpm"); $CLIST->set_pixtext($row,0,$tag, 20, $pixmap4, $mask4); } #newline elsif ($type == 5) { my ($pixmap5, $mask5) = Gtk::Gdk::Pixmap->create_from_xpm($CLIST->clist_window, $CLIST->style->white, "pict/newline.xpm"); $CLIST->set_pixmap($row,0, $pixmap5, $mask5); } #error elsif ($type == 6) { my ($pixmap6, $mask6) = Gtk::Gdk::Pixmap->create_from_xpm($CLIST->clist_window, $CLIST->style->white, "pict/question.xpm"); $CLIST->set_pixtext($row,0,$tag, 20, $pixmap6, $mask6); } } # ------------------------------------------------------------------ # FUNCTION NAME: addTagList # FUNCTIONALITY: to add a list of element to the list # PRECONDITION: none # POSTCONDITION: list of element is added # ------------------------------------------------------------------ sub addTagList { my $i=0; $CLIST->freeze(); $CLIST->set_row_height(25); foreach $ALL_TAGS (@ALL_TAGS) { add1Tag("-append", $i, $$ALL_TAGS{'type'}, $$ALL_TAGS{'tag'}); $i++; } $CLIST->thaw(); close FILE; } # ------------------------------------------------------------------ # FUNCTION NAME: AppendTag # FUNCTIONALITY: to append element at the end of the list # PRECONDITION: list and text box are provided # POSTCONDITION: the element is appended to the list # ------------------------------------------------------------------ sub AppendTag { my ($widget, $clist, $entry) = @_; my @AppendTags =(); if ($entry->get_chars(0,-1) eq "") { $STATUS_BAR->set_text("There is nothing to append"); return; } $CHANGE = 1; @AppendTags = getInsertTags($entry); #UPDATE UNDO LIST ---------------- my @undo=(); my $row = $#ALL_TAGS+1; my $i=0; foreach $item (@AppendTags) { $undo[$i] = $item; $undo[$i]{'group'} = $i; $undo[$i]{'bufferType'} = "-append"; $undo[$i]{'listPos'} = $row++; $i++; } push @UNDO_BUFFER, @undo; #-------------------------------- $CLIST->set_row_height(25); #set row height #append to array ALL_TAGS my $TagNum = @ALL_TAGS; $CLIST->freeze; foreach $tag (@AppendTags) { $ALL_TAGS[$TagNum] = $tag; add1Tag("-append",$TagNum, $$tag{type}, $$tag{tag}); $TagNum++; } $CLIST->thaw; #clear up the text box cleanUp($entry); $CLIST->select_row($CLIST_ROW,0); } # ------------------------------------------------------------------ # FUNCTION NAME: InsertTag # FUNCTIONALITY: To insert a list of element before the column # number selected # PRECONDITION: list and entry are provided # POSTCONDITION: the elements are inserted # ------------------------------------------------------------------ sub InsertTag { my ($widget, $clist, $entry) = @_; my @InsertTags =(); if ($entry->get_chars(0,-1) eq "") { $STATUS_BAR->set_text("There is nothing to insert"); return; } $CHANGE = 1; @InsertTags = getInsertTags($entry); #UPDATE UNDO LIST ---------------- my @undo=(); my $row = $CLIST_ROW; my $i=0; foreach $item (@InsertTags) { $undo[$i] = $item; $undo[$i]{'group'} = $i; $undo[$i]{'bufferType'} = "-insert"; $undo[$i]{'listPos'} = $row++; $i++; } push @UNDO_BUFFER, @undo; #-------------------------------- UpdateListAndArray($CLIST_ROW, @InsertTags); #clear up the text box cleanUp($entry); $CLIST->select_row($CLIST_ROW,0); } # ------------------------------------------------------------------ # FUNCTION NAME: getInsertTags # FUNCTIONALITY: to get the content, prefix, infix and postfix # PRECONDITION: entry text box is provided # POSTCONDITION: return the information # ------------------------------------------------------------------ sub getInsertTags { my ($entry) = @_; my @InsertContent=(); my @InsertTags =(); my $data = $entry->get_chars(0,-1); @InsertContent = scalarToArray($data); @InsertTags = identifyTags(@InsertContent); getPIP(\@InsertTags); return @InsertTags; } # ------------------------------------------------------------------ # FUNCTION NAME: scalarToArray # FUNCTIONALITY: to modify a list of strings to array # PRECONDITION: a list of string is provided # POSTCONDITION: return the array of that list of string # ------------------------------------------------------------------ sub scalarToArray { my ($tmp) = @_; my $tagNum; my @array=(); my $i=0; while ($tmp ne "") { ($tagNum) = ($tmp =~ s/(.*\n)//); if ($tagNum eq "") { $array[$i++] = $tmp; last; } $array[$i++] = $1; } return @array; } # ------------------------------------------------------------------ # FUNCTION NAME: DeleteTag # FUNCTIONALITY: to delete an element from the list # PRECONDITION: none # POSTCONDITION: the tag is deleted # ------------------------------------------------------------------ sub DeleteTag { my $row = $CLIST_ROW; #check whether there is selected tag to be deleted if (!defined $ALL_TAGS[$row]) { $STATUS_BAR->set_text("There is nothing to delete"); return; } #UPDATE UNDO LIST ---------------- my @delUndo=(); $delUndo[0] = { type => $ALL_TAGS[$row]{'type'}, tag => $ALL_TAGS[$row]{'tag'}, content => $ALL_TAGS[$row]{'content'}, comment => $ALL_TAGS[$row]{'comment'}, prefix => $ALL_TAGS[$row]{'prefix'}, infix => $ALL_TAGS[$row]{'infix'}, postfix => $ALL_TAGS[$row]{'postfix'}, group => 0, bufferType => "-delete", listPos => $row, }; push @UNDO_BUFFER, @delUndo; #-------------------------------- deleteOneList($row); $CLIST->select_row($row-1,0); $CHANGE = 1; } #------------------------------------------------------------------------ # READING THE CONTENT OF FILE AND ABSORB IT TO ARRAYS #------------------------------------------------------------------------ # ------------------------------------------------------------------ # FUNCTION NAME: readTags # FUNCTIONALITY: to read and get the element content/prefix/ # infix, postfix of the file provided # PRECONDITION: provide filename # POSTCONDITION: the ALL_TAGS array is updated with those info # ------------------------------------------------------------------ sub readTags { my ($filename) = @_; readFile($filename); @ALL_TAGS = identifyTags(@FILE_CONTENT); getPIP(\@ALL_TAGS); } # ------------------------------------------------------------------ # FUNCTION NAME: identifyTags # FUNCTIONALITY: to identify which element it is # PRECONDITION: none # POSTCONDITION: the ALL_TAGS array is updated # ------------------------------------------------------------------ #------------------------ # 1 - include # 2 - comment # 3 - tag # 4 - element # 5 - newline # 6 - error #------------------------ sub identifyTags { local (@file_content) = @_; local (@all_tags, $i, $tmp, $tagIndex, $long ); my $tag; # Temporary only.. will change to dynamic filename $i=0; $tagIndex = 0; $long = @file_content; $i=0; while ($i < $long) { $tmp = $file_content[$i]; # include file if ($tmp =~ /^include/) { $all_tags[$tagIndex] = { type => 1, tag => ($tmp =~ /^include\s*(\S+)/), content => $tmp, comment => "", prefix => "", infix => "", postfix => "", }; $tagIndex++; } # comment elsif ($tmp =~ /^#/) { my $commentTemp = $tmp; #get the next line and see whether it is still comment #if yes, stick it with the current comment. my $j=$i+1; while ($j < $long) { $tmp = $file_content[$j]; if (!($tmp =~ /^#/)) { last; } else { $commentTemp .= $tmp; $j++; $i++; } } $all_tags[$tagIndex] = { type => 2, tag => get1Word($commentTemp) . "..", content => $commentTemp, comment => "Comment", prefix => "", infix => "", postfix => "", }; $tagIndex++; } # tag elsif ($tmp =~ /<.*?>/) { $i = checkTag(); } # element elsif ($tmp =~ /&/) { $all_tags[$tagIndex] = { type => 4, tag => get1Word($tmp) . "..", content => $tmp, comment => "Element", prefix => "", infix => "", postfix => "", }; $tagIndex++; } # New line elsif (!($tmp =~ /\S+/)) { $all_tags[$tagIndex] = { type => 5, tag => "", content => $tmp, comment => "New line", prefix => "", infix => "", postfix => "", }; $tagIndex++; } # error tag, not sure what it is else { $all_tags[$tagIndex] = { type => 6, tag => get1Word($file_content[$i]) . "..", content => $file_content[$i], comment => "Error: System is not able to recognize this pattern.", prefix => "", infix => "", postfix => "", }; $tagIndex++; } $i++; } return @all_tags; } # ------------------------------------------------------------------ # FUNCTION NAME: checkTag # FUNCTIONALITY: to identify & get tags from the list # PRECONDITION: list of tags is provided # POSTCONDITION: tags are identified # ------------------------------------------------------------------ sub checkTag { my $j = 0; my $rowToBeCheck = 0; my $rowFlag = 1; my $tag=""; ($tag) = ($tmp =~ /<(.*?)>/); if ($tmp =~ /<$tag>.*?<\/$tag>/) { $tmp =~ s/(<$tag>.*?<\/$tag>)// ; $all_tags[$tagIndex] = { type => 3, tag => $tag, content => $1 . "\n", comment => "Tag - $tag", prefix => "", infix => "", postfix => "", }; $tagIndex++; # if there are more tags/comment/bla after the tag if ($tmp =~ /\S/) { $file_content[$i] = $tmp; return $i-1; } } else { $j = $i+1; if ($j < $long) { my $storage = $tmp . $file_content[$j]; while ($j < $long) { # found the closing tag in different line if ($storage =~ /<$tag>.*?<\/$tag>/s) { $storage =~ s/(<$tag>.*?<\/$tag>)//s ; $all_tags[$tagIndex] = { type => 3, tag => $tag, content => $1, comment => "Tag - $tag", prefix => "", infix => "", postfix => "", }; $tagIndex++; $i = $j; # if there are more tags/comment/bla after the tag if ($storage =~ /\S/) { $file_content[$i] = $storage; return $i-1; } last; } else { if ($j+1<$long) { $storage .= $file_content[++$j]; } else { $j++; } } } } # Can't find the closing tag - error tag if ( $j >= $long) { $all_tags[$tagIndex] = { type => 6, tag => get1Word($file_content[$i]) . "..", content => $file_content[$i], comment => "Error: System is not able to find the closing tag", prefix => "", infix => "", postfix => "", }; $tagIndex++; } } return $i; } # ------------------------------------------------------------------ # FUNCTION NAME: get1Word # FUNCTIONALITY: to get one word from the variable provided # PRECONDITION: provide the variable # POSTCONDITION: return the beginning word from that variable # ------------------------------------------------------------------ sub get1Word { my ($line) = @_; if ($line ne "") { $line =~ /\s*(\S+)/; return $1; } else { return 0; } } # ------------------------------------------------------------------ # FUNCTION NAME: getPIP # FUNCTIONALITY: to get the prefix, infix and postfix content # PRECONDITION: ALL_TAGS are passed by referenced # POSTCONDITION: updated ALL_TAGS with those information # ------------------------------------------------------------------ #ElementTranslation = start prefix ['.' inner ['.' postfix]] end | start inner ['.' postfix] end #start = '<' elementname '>' #prefix = translation ('.' translation)* #inner = '^^' | '$' elementname #postfix = translation ('.' translation)* #translation = single | double | code | string | variable | conditional translation #conditional = '?' '<' attributename '>' #single = "'" non-single-quote-char* "'" #double = '"' non-double-or-escaped-char '"' #code = '{' valid-Perl-code-fragment '}' #string = non-period-char* #variable = scalar-Perl-variable #end = '' sub getPIP { local (*all_tags) = @_; my $i=0; my $tmp=""; foreach $all_tags (@all_tags) { if ($all_tags[$i]{'type'} == 3) { $tmp = $all_tags[$i]{'content'}; ($tag) = ($tmp =~ /<(.*?)>/); #remove the start & end tag $tmp =~ /<$tag>(.*?)<\/$tag>/s ; $tmp = $1; my $result = get1PIP($tmp); $all_tags[$i]{'prefix'} = $result{'prefix'}; $all_tags[$i]{'infix'} = $result{'infix'}; $all_tags[$i]{'postfix'} = $result{'postfix'}; } $i++; } } # ------------------------------------------------------------------ # FUNCTION NAME: get1PIP # FUNCTIONALITY: to get prefix, infix and postfix of one variable # PRECONDITION: a variable is provided # POSTCONDITION: return the prefix, infix and postfix information # ------------------------------------------------------------------ sub get1PIP { my ($tmp) = @_; my $result; my $i=0; #PREFIX . INNER . POSTFIX if ($tmp =~ /(.*)\.\s*(\^\^)\s*\.(.*)/s) { $result{'prefix'} = $1; $result{'infix'} = $2; $result{'postfix'} = $3; return $result; } #PREFIX . INNER elsif ($tmp =~ /(.*)\.(\^\^|\$\S+)/s) { $result{'prefix'} = $1; $result{'infix'} = $2; $result{'postfix'} = ""; return $result; } #INNER . POSTFIX elsif ($tmp =~ /(@@)\.(.*)/) { $result{'prefix'} = ""; $result{'infix'} = $1; $result{'postfix'} = $2; return $result; } #INNER only elsif ($tmp =~ /\s*(\^\^)\s*/s) { $result{'prefix'} = ""; $result{'infix'} = $1; $result{'postfix'} = ""; return $result; } #PREFIX only elsif (!($tmp =~ /\^\^/s)) { $result{'prefix'} = $1; $result{'infix'} = ""; $result{'postfix'} = ""; return $result; } #don't know else { print "Not sure what is it.\n"; } } # ------------------------------------------------------------------ # FUNCTION NAME: readFile # FUNCTIONALITY: to read a file provided # PRECONDITION: filename is provided # POSTCONDITION: read the content of the file # ------------------------------------------------------------------ sub readFile { my ($filename) = @_; my $tmp = ""; @FILE_CONTENT=(); #check whether the file is exist, if not prompt user. #not just directly die. if (open (FILE, $filename)) { my $i=0; while($tmp = ) { $FILE_CONTENT[$i++] = $tmp; } close FILE; } else { CreateDiaBox ("The file - $filename - does not exist or ". "is not readable.\n" . "Please make sure that the file is exist and readable.", "-O", "-openPanes"); } } # ------------------------------------------------------------------ # FUNCTION NAME: printTag # FUNCTIONALITY: to print the content of ALL_TAGS to stdin # PRECONDITION: ALL_TAGS is passed by reference # POSTCONDITION: pritn the content of ALL_TAGS to stdin # ------------------------------------------------------------------ sub printTag { (*all_tags) = @_; print "\n\n\n"; my $i=0; foreach $all_tags (@all_tags) { print "--$i\n"; print "type = $all_tags[$i]{'type'}\n"; print "tag = $all_tags[$i]{'tag'}\n"; print "content = $all_tags[$i]{'content'}\n"; print "prefix = $all_tags[$i]{'prefix'}\n"; print "infix = $all_tags[$i]{'infix'}\n"; print "postfix = $all_tags[$i]{'postfix'}\n"; # for undo buffer print "group = $all_tags[$i]{'group'}\n"; print "bufferType = $all_tags[$i]{'bufferType'}\n"; print "listPos = $all_tags[$i]{'listPos'}\n"; $i++; } } # ------------------------------------------------------------------ # FUNCTION NAME: OpenPanes # FUNCTIONALITY: to display new window using system command # PRECONDITION: provide filename and typeFlag # POSTCONDITION: new window is displayed # ------------------------------------------------------------------ sub OpenPanes { my ($filename, $typeFlag) = @_; if ($filename eq "") { system "perl AXEsse.pl &"; return; } # Check whether the file is in the directory of the first file # if yes, open that file # else, try to open file in the current directory. my $tmpFilename = $PATH . $filename; if (-e $tmpFilename) { $filename = $tmpFilename; } # Only open when the file is exist and readable. if ((-e $filename) && (-r $filename)) { if ($typeFlag eq "-include") { updateIncludeFile($filename, "-new"); $STATUS_BAR->set_text("The file is already opened"); } else { system "perl AXEsse.pl $filename &"; } } else { if ($typeFlag eq "-include") { return 0; } else { CreateDiaBox ("The file - $filename - does not exist or ". "is not readable.\n" . "Please make sure that the file is exist and readable.", "-O", "-openPanes"); } } return 1; } # --------------------------------------------------------------- # include file handling # --------------------------------------------------------------- # ------------------------------------------------------------------ # FUNCTION NAME: readIncludeFile # FUNCTIONALITY: to read the content of the include file # PRECONDITION: the file's content # POSTCONDITION: the file is read # ------------------------------------------------------------------ sub readIncludeFile { (*includedFile) = @_; # if the file AXEsse.tb does not exist or no readable, # pop up error message # the file must exist and readable, # because the program is running at the moment. if ((!-e $AXEsse) || (! -r $AXEsse)) { CreateDiaBox ("The system encounters some problems while ". "trying to open the included document\n". "Please save the document, quit the program". " and reload the AXEsse program.", "-O", "-openPanes"); return 0; } # the file AXEsse.tb does exist open (FILE, $AXEsse); my $i=0; my $tmp = ""; while($tmp = ) { $includedFile[$i++] = $tmp; } close FILE; return 1; } # ------------------------------------------------------------------ # FUNCTION NAME: removeIncludeFile # FUNCTIONALITY: to remove the filename from .AXEsse.tb # PRECONDITION: filename is provided # POSTCONDITION: the filename in .AXEsse.tb is deleted # ------------------------------------------------------------------ sub removeIncludeFile { my ($filename) = @_; my @includeFile=(); if (!readIncludeFile(\@includeFile)) { return; } # check whether the file exists # if yes, remove it my $i=0; foreach $item (@includeFile) { if ($item eq "$filename\n") { splice @includeFile, $i, 1; if (writeIncludeFile(\@includeFile)) { return;} } $i++; } } # ------------------------------------------------------------------ # FUNCTION NAME: writeIncludeFile # FUNCTIONALITY: to write the include filename to .AXEsse.tb # PRECONDITION: AXEsse.tb exist # POSTCONDITION: the filename is written in .AXEsse.tb # ------------------------------------------------------------------ sub writeIncludeFile { (*includedFile) = @_; # if the file AXEsse.tb does not exist or no readable, # pop up error message # the file must exist and readable, # because the program is running at the moment. if ((!-e $AXEsse) || (! -r $AXEsse)) { CreateDiaBox ("The system encounters some problems while ". "trying to open the included document ". "named $filename.\n". "Please save the document, quit the program". " and reload the AXEsse program." , "-O", "-openPanes"); return 0; } # the file AXEsse.tb does exist open (FILE, ">$AXEsse"); foreach $item (@includedFile) { print FILE "$item"; } close FILE; return 1; } # ------------------------------------------------------------------ # FUNCTION NAME: updateIncludeFile # FUNCTIONALITY: to update the content of the file # PRECONDITION: filename and flag is provided # POSTCONDITION: the file .AXEsse.tb is updated # ------------------------------------------------------------------ sub updateIncludeFile { my ($filename, $flag) = @_; if (!readIncludeFile(\@includeFile)) { return; } # check whether the file exists # if yes, do nothing foreach $item (@includeFile) { if ($item eq "$filename\n") { return; } } # if no, do system call and add filename to the file if ($flag eq "-new") { open (FILE, ">>$AXEsse"); print FILE "$filename\n"; close(FILE); system "perl AXEsse.pl -i $filename &"; } } # ------------------------------------------ # create session of AXEsse # ------------------------------------------ # ------------------------------------------------------------------ # FUNCTION NAME: createAXEsse # FUNCTIONALITY: to create the components in the window # PRECONDITION: filename is provided # POSTCONDITION: components in window are created # ------------------------------------------------------------------ sub createAXEsse { my ($filename) = @_; # Only open when the file is exist and readable. $FILENAME = $filename; create_panes($FILENAME); readTags($FILENAME); addTagList(); } # ------------------------------------------------------------------ # FUNCTION NAME: openAXEsse # FUNCTIONALITY: to open .AXEsse.tb and append the filename # PRECONDITION: filename and flag are provided # POSTCONDITION: filename is appeded to the file # ------------------------------------------------------------------ sub openAXEsse { my ($filename, $flag) = @_; if ($PATH eq "") { $filename =~ /(\/.*\/)*.*/; if (defined $1) { $PATH = $1; } } if ($PATH ne "") { my $tmpFilename = $PATH . $filename; if (-e $tmpFilename) { $filename = $tmpFilename; } } # Only open when the file is exist and readable. if ((-e $filename) && (-r $filename)) { if ($flag eq "-normal") { open (FILE, ">>$AXEsse"); print FILE "$filename\n"; close(FILE); } createAXEsse($filename); } else { # Need to pop up message box, said that this file can't be open. create_panes(""); CreateDiaBox ("The file - $filename - does not exist or is not readable.". "\nPlease make sure that the file is exist and readable.", "-O", "-openPanes"); } } # --------------------------------------------------------- # MAIN # --------------------------------------------------------- if ($#ARGV == 0) { $filename = $ARGV[0]; openAXEsse ($filename, "-normal"); } elsif ($#ARGV > 0) { if ($#ARGV == 1) { $filename = $ARGV[1]; openAXEsse($filename, "-include"); } else { die "Error! Usage = perl AXEsse.pl filename\n"; } } else { open (FILE, ">>$AXEsse"); close(FILE); create_panes(""); } main Gtk;