Logo Search packages:      
Sourcecode: manedit version File versions  Download package

editorop.c

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <gtk/gtk.h>
#include <unistd.h>           /* For unlink() */

#include "../include/string.h"
#include "../include/strexp.h"
#include "../include/disk.h"

#include "guiutils.h"
#include "cdialog.h"

#include "editor.h"
#include "editorcb.h"
#include "editorop.h"
#include "editorfio.h"

#include "viewer.h"
#include "viewerfio.h"

#include "manedit.h"
#include "maneditop.h"
#include "config.h"


void EditorSyntaxHighlight(
      editor_struct *editor, GtkWidget *w,
      gint cursor_pos, gint start_pos, gint end_pos
);

void EditorDoFetchValues(editor_struct *editor, GtkCTreeNode *branch);
void EditorDoApplyValues(editor_struct *editor, GtkCTreeNode *branch);
void EditorDoClearValues(editor_struct *editor);

void EditorDoPreview(
      editor_struct *editor, GtkCTreeNode *branch,
      gint viewer_num
);

gboolean EditorDoFind(
      editor_struct *editor, GtkText *text,
      gchar *haystack, gchar *needle,
      gint haystack_len, gint start_pos,
      gboolean case_sensitive,
      gboolean move_to,
      gboolean *search_wrapped
);
gboolean EditorDoReplace(
      editor_struct *editor, GtkText *text,
      gchar *haystack, gchar *needle, const gchar *replacement,
      gint haystack_len, gint start_pos,
      gboolean case_sensitive
);
gint EditorDoReplaceAll(
      editor_struct *editor, GtkText *text,
      gchar *needle, const gchar *replacement,
      gboolean case_sensitive
);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s) (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)  (((a) > (b)) ? (a) : (b))
#define MIN(a,b)  (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s) (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *    Performs syntax highlighting on the GtkText widget w.
 *
 *    Any given position input values may be -1. If all are -1
 *    then entire buffer will have syntax highlighting performed on
 *    it.
 *
 *    Avoid making this call if the text widget is frozen.
 */
void EditorSyntaxHighlight(
      editor_struct *editor, GtkWidget *w,
      gint cursor_pos, gint start_pos, gint end_pos
)
{
      gboolean in_tag, in_sym;
      gint c, orig_cur_pos, cur_pos, text_start, text_end;
      gboolean orig_has_selection;
      gint orig_sel_start = -1, orig_sel_end = -1;
      GtkStyle *style_ptr;
      GtkText *text = (GtkText *)w;
      GtkEditable *editable = (GtkEditable *)w;
      medit_core_struct *core_ptr;
      medit_styles_list_struct *styles_list;
      if((editor == NULL) || (w == NULL))
          return;

      if(!editor->initialized)
          return;

      /* No syntax highlighting? */
      if(!editor->syntax_highlighting)
          return;

      core_ptr = (medit_core_struct *)editor->core_ptr;
      if(core_ptr == NULL)
          return;

      styles_list = &core_ptr->styles_list;

      /* Set text bounds */
      text_start = 0;         /* Duh */
      text_end = (gint)gtk_text_get_length(text);

      /* Make sure start and end positions are in bounds */
      if(cursor_pos >= text_end)
          cursor_pos = text_end - 1;
      if(start_pos >= text_end)
          start_pos = text_end - 1;
      if(end_pos > text_end)
          end_pos = text_end;


      /* Use start position as cursor position if cursor position
       * is invalid and start position is valid.
       */
      if((cursor_pos < 0) && (start_pos > -1))
          cursor_pos = start_pos;

      /* Record original cursor position */
      orig_cur_pos = gtk_editable_get_position(editable);

      /* Record original selection */
      orig_has_selection = editable->has_selection;
      if(orig_has_selection)
      {
          orig_sel_start = editable->selection_start_pos;
          orig_sel_end = editable->selection_end_pos;
      }

      /* Cursor position defined? */
      if(cursor_pos > -1)
      {
          /* Set starting cursor position */
          cur_pos = cursor_pos;

          /* Itterate backwards untill a deliminator is encountered,
           * if a deliminator is encountered then it will be colored and
           * then the style will be updated for regular or tag
           * text and in_tag will be set accordingly.
           * If no tags were encountered then regular style will
           * be set.
           */
          in_tag = FALSE;
          in_sym = FALSE;
gtk_text_freeze(text);
          while(cur_pos >= text_start)
          {
            c = GTK_TEXT_INDEX(text, cur_pos);
            /* Is character a tag deliminator start? */
            if(c == '<')
            {
                style_ptr = styles_list->edit_text_tag_deliminator;
                if(style_ptr != NULL)
                {
                  gtk_text_set_point(text, cur_pos);
                  gtk_text_forward_delete(text, 1);
                  gtk_text_insert(
                      text,
                      style_ptr->font,
                      &style_ptr->fg[GTK_STATE_NORMAL],
                      NULL,
                      "<",
                      1
                  );
                }
                in_tag = TRUE;
                cur_pos++;    /* Seek past tag */
                break;
            }
            /* Is character an tag deliminator end? */
            else if(c == '>')
            {
                style_ptr = styles_list->edit_text_tag_deliminator;
                if(style_ptr != NULL)
                {
                  gtk_text_set_point(text, cur_pos);
                  gtk_text_forward_delete(text, 1);
                  gtk_text_insert(
                      text,
                      style_ptr->font,
                      &style_ptr->fg[GTK_STATE_NORMAL],
                      NULL,
                      ">",
                      1
                  );
                }
                cur_pos++;    /* Seek past tag */
                break;
            }
            /* Is character a start of a symbol representation? */
            else if(c == '&')
            {
                style_ptr = styles_list->edit_text_tag_symrep;
                if(style_ptr != NULL)
                {
                  gtk_text_set_point(text, cur_pos);
                  gtk_text_forward_delete(text, 1);
                  gtk_text_insert(
                      text,
                      style_ptr->font,
                      &style_ptr->fg[GTK_STATE_NORMAL],
                      NULL,
                      "&",
                      1
                  );
                }
                in_sym = TRUE;
                cur_pos++;  /* Seek past symbol rep */
                break;
            }
            /* Skip symbol representation end ';' when itterating
             * backwards.
             */
            else
            {
                cur_pos--;
            }
          }
          /* Make sure current position stays at or above text_start */
          if(cur_pos < text_start)
            cur_pos = text_start;

          if(TRUE)
          {
            /* Itterate to end of text or to a start or end
             * deliminator after end_pos.
             */
            while(cur_pos < text_end)
            {
                c = GTK_TEXT_INDEX(text, cur_pos);
                /* Is character a tag deliminator start? */
                if((c == '<') && !in_tag)
                {
                  style_ptr = styles_list->edit_text_tag_deliminator;
                  if(style_ptr != NULL)
                  {
                      gtk_text_set_point(text, cur_pos);
                      gtk_text_forward_delete(text, 1);
                      gtk_text_insert(
                        text,
                        style_ptr->font,
                        &style_ptr->fg[GTK_STATE_NORMAL],
                        NULL,
                        "<",
                        1
                      );         
                  }
                  in_tag = TRUE;    /* Mark as in a tag */

                  /* Encountered a deliminator after end_pos? */
                  if(end_pos > -1)
                  {
                      if(cur_pos > end_pos)
                        break;
                  }
                }
                /* Is character a tag deliminator end? */
                else if((c == '>') && in_tag)
                {
                  style_ptr = styles_list->edit_text_tag_deliminator;
                  if(style_ptr != NULL)
                  {
                      gtk_text_set_point(text, cur_pos);
                      gtk_text_forward_delete(text, 1);
                      gtk_text_insert(
                        text,
                        style_ptr->font,
                        &style_ptr->fg[GTK_STATE_NORMAL],
                        NULL,
                        ">",
                        1  
                      );
                  }
                  in_tag = FALSE;   /* Mark no longer in a tag */

                  /* Encountered a deliminator after end_pos? */
                  if(end_pos > -1)
                  {
                      if(cur_pos > end_pos)
                        break;
                  }
                }
                /* Is character a symbol representation start? */
                else if((c == '&') && !in_sym)
                {
                  style_ptr = styles_list->edit_text_tag_symrep;
                  if(style_ptr != NULL)
                  {
                      gtk_text_set_point(text, cur_pos);
                      gtk_text_forward_delete(text, 1);
                      gtk_text_insert(
                        text,
                        style_ptr->font,
                        &style_ptr->fg[GTK_STATE_NORMAL],
                        NULL,
                        "&",
                        1
                      );
                  }
                  in_sym = TRUE;  /* Mark as in a sym */

                  /* Encountered a deliminator after end_pos? */
                  if(end_pos > -1)
                  {
                      if(cur_pos > end_pos)
                        break;
                  }
                }
                /* Is character a symbol representation end? */
                else if((c == ';') && in_sym)
                {
                  style_ptr = styles_list->edit_text_tag_symrep;
                  if(style_ptr != NULL)
                  {
                      gtk_text_set_point(text, cur_pos);
                      gtk_text_forward_delete(text, 1);
                      gtk_text_insert(
                        text,
                        style_ptr->font,
                        &style_ptr->fg[GTK_STATE_NORMAL],
                        NULL,
                        ";",
                        1
                      );
                  }
                  in_sym = FALSE;  /* Mark as no longer in sym */

                  /* Encountered a deliminator after end_pos? */
                  if(end_pos > -1)
                  {
                      if(cur_pos > end_pos)
                        break;
                  }
                }
                else
                {
                  if(in_tag)
                      style_ptr = styles_list->edit_text_tag_text;
                  else if(in_sym)
                      style_ptr = styles_list->edit_text_tag_symrep;
                  else
                      style_ptr = styles_list->edit_text_standard;
                  if(style_ptr != NULL)
                  {
                      gchar tmp_str[2];

                      tmp_str[0] = (char)c;
                      tmp_str[1] = '\0';

                      gtk_text_set_point(text, cur_pos);
                      gtk_text_forward_delete(text, 1);
                      gtk_text_insert(
                        text,
                        style_ptr->font,
                        &style_ptr->fg[GTK_STATE_NORMAL],
                        NULL,
                        tmp_str,
                        1
                      );
                  }
                }

                /* Increment to next position */
                cur_pos++;
            }
          }
gtk_text_thaw(text);
      }
      else
      {
          /* Highlight entire buffer */

          /* Set cur_pos at start of text */
          cur_pos = text_start;

          /* Reset in tag marker */
          in_tag = FALSE;
          in_sym = FALSE;

          /* Itterate to end of text */
gtk_text_freeze(text);
          while(cur_pos < text_end)
          {
            c = GTK_TEXT_INDEX(text, cur_pos);
            /* Is character a tag deliminator start? */
            if((c == '<') && !in_tag)
            {
                style_ptr = styles_list->edit_text_tag_deliminator;
                if(style_ptr != NULL)
                {
                  gtk_text_set_point(text, cur_pos);
                  gtk_text_forward_delete(text, 1);
                  gtk_text_insert(
                      text,
                      style_ptr->font,
                      &style_ptr->fg[GTK_STATE_NORMAL],
                      NULL,
                      "<",
                      1
                  );
                }
                in_tag = TRUE;      /* Mark as in a tag */
            }
            /* Is character a tag deliminator end? */
            else if((c == '>') && in_tag)
            {
                style_ptr = styles_list->edit_text_tag_deliminator;
                if(style_ptr != NULL)
                {
                  gtk_text_set_point(text, cur_pos);
                  gtk_text_forward_delete(text, 1);
                  gtk_text_insert(
                      text,
                      style_ptr->font,
                      &style_ptr->fg[GTK_STATE_NORMAL],
                      NULL,
                      ">",
                      1
                  );
                }
                in_tag = FALSE; /* Mark no longer in a tag */
            }
            /* Is character a symbol representation start? */
            else if((c == '&') && !in_sym)
            {
                style_ptr = styles_list->edit_text_tag_symrep;
                if(style_ptr != NULL)
                {
                  gtk_text_set_point(text, cur_pos);
                  gtk_text_forward_delete(text, 1); 
                  gtk_text_insert(
                      text,
                      style_ptr->font,
                      &style_ptr->fg[GTK_STATE_NORMAL],
                      NULL,
                      "&", 
                      1   
                  );   
                }
                in_sym = TRUE;      /* Mark as in a sym */
            }
            /* Is character a symbol representation end? */
            else if((c == ';') && in_sym)
            {
                style_ptr = styles_list->edit_text_tag_symrep;
                if(style_ptr != NULL)
                {
                  gtk_text_set_point(text, cur_pos);
                  gtk_text_forward_delete(text, 1);
                  gtk_text_insert(
                      text,
                      style_ptr->font,
                      &style_ptr->fg[GTK_STATE_NORMAL],
                      NULL,
                      ";",
                      1
                  );
                }
                in_sym = FALSE;     /* Mark no longer in a sym */
            }
            else
            {
                if(in_tag)
                  style_ptr = styles_list->edit_text_tag_text;
                else if(in_sym)
                  style_ptr = styles_list->edit_text_tag_symrep;
                else
                  style_ptr = styles_list->edit_text_standard;
                if(style_ptr != NULL)
                {
                  gchar tmp_str[2];

                  tmp_str[0] = (char)c;
                  tmp_str[1] = '\0';

                  gtk_text_set_point(text, cur_pos);
                  gtk_text_forward_delete(text, 1);
                  gtk_text_insert(   
                      text,
                      style_ptr->font,
                      &style_ptr->fg[GTK_STATE_NORMAL],
                      NULL,
                      tmp_str,
                      1
                  );
                }
            }
            cur_pos++;
          }
gtk_text_thaw(text);
      }

      /* Set back original cursor position */
      gtk_text_set_point(text, orig_cur_pos);
      gtk_editable_set_position(editable, orig_cur_pos);

      /* Set back originally had selection? */
      if(orig_has_selection)
      {
          gtk_editable_select_region(
            editable, orig_sel_start, orig_sel_end
          );
      }


}


/*
 *    Procedure to fetch values from the given branch and map
 *    the appropriate editor panel widgets on the editor.
 */
void EditorDoFetchValues(editor_struct *editor, GtkCTreeNode *branch)
{
      gint i;
      gint map_editor_panel_type = -1;
      GtkStyle *style;
      GtkWidget *w;
      editor_item_struct *item;
      medit_core_struct *core_ptr;
      medit_styles_list_struct *styles_list;

      if((editor == NULL) || (branch == NULL))
          return;

      if(!editor->initialized)
          return;

      /* Check if already processing */
      if(editor->processing)
          return;

      /* Get core pointer and subsequently the styles list */
      core_ptr = MEDIT_CORE(editor->core_ptr);
      styles_list = (core_ptr != NULL) ?
          &core_ptr->styles_list : NULL;


      /* Get pointer to item data from ctree branch node */
      item = EditorBranchGetData(
          GTK_CTREE(editor->layout_ctree), branch
      );


      /* Map and unmap editor panel widgets */
      if(item != NULL)
          map_editor_panel_type = item->type;

      for(i = 0; i < MEDIT_EDIT_PANEL_MAX; i++)
      {
          w = editor->edit_panel_vbox[i];
          if(w == NULL)
            continue;

          if(i == map_editor_panel_type)
            gtk_widget_show(w);
          else
            gtk_widget_hide(w);
      }


      /* Load data into widgets by the type of item data from
       * the given branch.
       */
      switch(map_editor_panel_type)
      {
        case EditorItemTypeFile:

          break;

        case EditorItemTypeHeader:
          /* Set entry widgets */
          w = editor->header_name_entry;
          if(w != NULL)
          {
            if((item == NULL) ?
                0 : (item->header_name != NULL)
            )
                gtk_entry_set_text(
                  GTK_ENTRY(w), item->header_name
                );
          }

          w = editor->header_section_number_entry;
          if(w != NULL)
          {
            if((item == NULL) ?    
                0 : (item->header_section_number != NULL)
            )
                gtk_entry_set_text(
                  GTK_ENTRY(w), item->header_section_number
                );
          }     

          w = editor->header_version_entry;
          if(w != NULL)
          {
            if((item == NULL) ?
                0 : (item->header_version != NULL)
            )
                gtk_entry_set_text(
                  GTK_ENTRY(w), item->header_version
                );
          }

          w = editor->header_author_entry;
          if(w != NULL)
          {
            if((item == NULL) ?
                0 : (item->header_author != NULL)
            )
                gtk_entry_set_text(
                  GTK_ENTRY(w), item->header_author
                );
          }

          w = editor->header_catagory_entry;
          if(w != NULL)
          {
            if((item == NULL) ?
                0 : (item->header_catagory != NULL)
            )
                gtk_entry_set_text(
                  GTK_ENTRY(w), item->header_catagory
                );
          }

          /* Get pointer to header text widget */
          w = editor->header_text;
          if(w != NULL)
          {
            gint text_len;

            /* Remove all text */
            text_len = gtk_text_get_length(GTK_TEXT(w));
            gtk_text_set_point(GTK_TEXT(w), 0);
            gtk_text_freeze(GTK_TEXT(w));
            gtk_text_forward_delete(GTK_TEXT(w), text_len);
            gtk_text_thaw(GTK_TEXT(w));

            /* Item data valid? */
            if(item != NULL)
            {
                gchar *line_ptr;


                if(styles_list != NULL)
                  style = styles_list->edit_text_standard;
                else
                  style = NULL;

                /* Set lines from item to text widget */
                gtk_text_freeze(GTK_TEXT(w));
                for(i = 0; i < item->total_lines; i++)
                {
                  line_ptr = item->line[i];
                  if(line_ptr == NULL)
                      continue;

                  /* Insert this line */
                  gtk_text_insert(
                      GTK_TEXT(w),
                      (style != NULL) ? style->font : NULL,
                      NULL,   /* Foreground color */
                      NULL,   /* Background color */
                      line_ptr,
                      -1
                  );

                  /* Need to insert a newline character at end */
                  gtk_text_insert(
                      GTK_TEXT(w),
                      (style != NULL) ? style->font : NULL,
                      NULL,       /* Foreground color */
                      NULL,       /* Background color */
                      "\n",
                      -1
                  );
                }
                gtk_text_thaw(GTK_TEXT(w));
            }
          }
          break;

        case EditorItemTypeSection:
          /* Section name entry */
          w = editor->section_name_entry;
          if(w != NULL)
          {
            gtk_entry_set_text(
                GTK_ENTRY(w),
                (item == NULL) ?
                  "" : item->section_name
            );
          }

          /* Get pointer to section text widget */
          w = editor->section_text;
          if(w != NULL)
          {
            gint text_len;

            /* Remove all text */
            text_len = gtk_text_get_length(GTK_TEXT(w));
            gtk_text_set_point(GTK_TEXT(w), 0);
            gtk_text_freeze(GTK_TEXT(w));
            gtk_text_forward_delete(GTK_TEXT(w), text_len);
            gtk_text_thaw(GTK_TEXT(w));

            /* Item data valid? */  
            if(item != NULL)
            {
                gchar *line_ptr;


                if(styles_list != NULL)
                  style = styles_list->edit_text_standard;
                else  
                  style = NULL;

                /* Set lines from item to text widget */
                gtk_text_freeze(GTK_TEXT(w));
                for(i = 0; i < item->total_lines; i++)
                {
                  line_ptr = item->line[i];
                  if(line_ptr == NULL)
                      continue;

                  /* Insert this line */
                  gtk_text_insert(
                      GTK_TEXT(w),
                      (style != NULL) ? style->font : NULL,
                      NULL,       /* Foreground color */
                      NULL,       /* Background color */
                      line_ptr,
                      -1
                  );

                  /* Need to insert a newline character at end */
                  gtk_text_insert( 
                      GTK_TEXT(w),
                      (style != NULL) ? style->font : NULL,
                      NULL,       /* Foreground color */
                      NULL,       /* Background color */
                      "\n",
                      -1
                  );
                }
                gtk_text_thaw(GTK_TEXT(w));

                /* Syntax highlighting for entire buffer */
                EditorSyntaxHighlight(
                  editor, w,
                  -1, -1, -1
                );
            }
          }
          break;
      }

      /* Update menus */
      EditorUpdateMenus(editor);
}


/*
 *      Procedure to apply values to the given branch from the appropriate
 *    widgets depending on the branch data's type.
 */
void EditorDoApplyValues(editor_struct *editor, GtkCTreeNode *branch)
{
      GtkWidget *w;
      editor_item_struct *item;
      medit_pixmaps_list_struct *pixmaps_list;
      medit_core_struct *core_ptr;

      if((editor == NULL) || (branch == NULL))
          return;

      if(!editor->initialized)
          return;

      /* Check if already processing */
      if(editor->processing)   
          return;

      core_ptr = MEDIT_CORE(editor->core_ptr);
      if(core_ptr == NULL)
          return;

      pixmaps_list = &core_ptr->pixmaps_list;


      /* Get pointer to item data from ctree branch node */
      item = EditorBranchGetData(
          GTK_CTREE(editor->layout_ctree), branch
      );
      if(item == NULL)
      {
          /* No data to apply */
          return;
      }

      /* Check ctree branch node data type */
      switch(item->type)
      {
        case EditorItemTypeFile:

          break;
                      
        case EditorItemTypeHeader:
          /* Header name entry */
          w = editor->header_name_entry;
          if((w != NULL) && (item != NULL))
          {
            g_free(item->header_name);
            item->header_name = STRDUP(gtk_entry_get_text(GTK_ENTRY(w)));
          }
          /* Header section number entry */
          w = editor->header_section_number_entry;  
          if((w != NULL) && (item != NULL))
          {
            g_free(item->header_section_number);
            item->header_section_number = STRDUP(gtk_entry_get_text(GTK_ENTRY(w)));
          }
          /* Header version entry */
          w = editor->header_version_entry;
          if((w != NULL) && (item != NULL))
          {
            g_free(item->header_version);
            item->header_version = STRDUP(gtk_entry_get_text(GTK_ENTRY(w)));
          }
          /* Header author entry */
          w = editor->header_author_entry;
          if((w != NULL) && (item != NULL))
          {
            g_free(item->header_author);
            item->header_author = STRDUP(gtk_entry_get_text(GTK_ENTRY(w)));
          }
          /* Header catagory entry */
          w = editor->header_catagory_entry;
          if((w != NULL) && (item != NULL))
          {
            g_free(item->header_catagory); 
            item->header_catagory = STRDUP(gtk_entry_get_text(GTK_ENTRY(w)));
          }
          /* Header text */
          w = editor->header_text;
          if((w != NULL) && (item != NULL))
          {
            gchar *s;

            /* Delete existing lines */
            strlistfree(item->line, item->total_lines);
            item->line = NULL;
            item->total_lines = 0;

            /* Get new lines */
            s = gtk_editable_get_chars(
                GTK_EDITABLE(w), 0, -1
            );
            item->line = strchrexp(s, '\n', &item->total_lines);
            g_free(s);
          }
          break;

        case EditorItemTypeSection:
          /* Section name entry */
          w = editor->section_name_entry;
          if((w != NULL) && (item != NULL))
          {
            gchar *s = gtk_entry_get_text(GTK_ENTRY(w));

            g_free(item->section_name);
            item->section_name = STRDUP(s);

            if(s != NULL)
                gtk_ctree_node_set_pixtext(
                  GTK_CTREE(editor->layout_ctree),
                  branch,           /* Branch node */
                  0,          /* Column */
                  s,
                  MEDIT_LIST_ICON_TEXT_SPACING,
                  pixmaps_list->manpage_section_20x20,
                  pixmaps_list->manpage_section_20x20_mask
                );
          }

          /* Section text */
          w = editor->section_text;
          if(w != NULL)
          {
            gchar *s;

            /* Delete existing lines */
            strlistfree(item->line, item->total_lines);
            item->line = NULL;
            item->total_lines = 0;

            /* Get new lines */
            s = gtk_editable_get_chars(GTK_EDITABLE(w), 0, -1);
            item->line = strchrexp(s, '\n', &item->total_lines);
            g_free(s);
          }
          break;
      }

      /* Update menus */
      EditorUpdateMenus(editor);
}

/*
 *    Clears all data on the editor's branch item editing widgets but
 *    does not unmap anything.
 */
void EditorDoClearValues(editor_struct *editor)
{
      GtkWidget *w;

      if(editor == NULL)
          return;

      if(!editor->initialized)
          return;

      /* Check if already processing */
      if(editor->processing)
          return;

      /* Clear file branch item data widgets */

      /* Header entry widgets */
      w = editor->header_name_entry;
      if(w != NULL)
          gtk_entry_set_text(GTK_ENTRY(w), "");

      w = editor->header_section_number_entry;
      if(w != NULL)
          gtk_entry_set_text(GTK_ENTRY(w), "");

      w = editor->header_version_entry;
      if(w != NULL)
          gtk_entry_set_text(GTK_ENTRY(w), "");

      w = editor->header_author_entry;
      if(w != NULL)
          gtk_entry_set_text(GTK_ENTRY(w), "");

      w = editor->header_catagory_entry;
      if(w != NULL)
          gtk_entry_set_text(GTK_ENTRY(w), "");

      /* Header text */
      w = editor->header_text;
      if(w != NULL)
      {
          gint text_len;

          /* Remove all text */
          text_len = gtk_text_get_length(GTK_TEXT(w));
          gtk_text_set_point(GTK_TEXT(w), 0);
          gtk_text_freeze(GTK_TEXT(w));
          gtk_text_forward_delete(GTK_TEXT(w), text_len);
          gtk_text_thaw(GTK_TEXT(w));
      }


      /* Section name entry */
      w = editor->section_name_entry;
      if(w != NULL)
          gtk_entry_set_text(GTK_ENTRY(w), "");

      /* Section text */
      w = editor->section_text;
      if(w != NULL)
      {
          gint text_len;

          /* Remove all text */
          text_len = gtk_text_get_length(GTK_TEXT(w));
          gtk_text_set_point(GTK_TEXT(w), 0);
          gtk_text_freeze(GTK_TEXT(w));
          gtk_text_forward_delete(GTK_TEXT(w), text_len);
          gtk_text_thaw(GTK_TEXT(w));
      }
}


/*
 *    Checks if viewer_num is a valid viewer and sets it up to load
 *    an exported manual page converted to man formatted output.
 */
void EditorDoPreview(
      editor_struct *editor, GtkCTreeNode *branch,  
      gint viewer_num
)
{
      gint i, status, editor_num;
      viewer_struct *v;
      medit_core_struct *core_ptr;
      GtkCTreeNode *trunk;
      editor_item_struct *item;
      GtkWidget *toplevel;
      GtkCTree *ctree;
      gchar *orig_path, *tmp_path, *prog_tmp_path;

      if(editor == NULL)
          return;

      if(!editor->initialized)
          return;

      /* Check if processing */
      if(editor->processing)   
          return;

      toplevel = editor->toplevel;
      ctree = (GtkCTree *)editor->layout_ctree;
      core_ptr = (medit_core_struct *)editor->core_ptr;
      if((ctree == NULL) || (core_ptr == NULL))
          return;

      /* Find our editor pointer on core */
      for(i = 0; i < core_ptr->total_editors; i++)
      {
          if(core_ptr->editor[i] == editor)
            break;
      }
      if(i < core_ptr->total_editors)
          editor_num = i;
      else
          editor_num = -1;

      /* Check if viewer_num is valid on the core structure */
      v = ((viewer_num >= 0) && (viewer_num < core_ptr->total_viewers)) ?
          core_ptr->viewer[viewer_num] : NULL;
      if(v == NULL)
      {
          gchar *s = g_strdup_printf(
"EditorDoPreview(): Viewer number %i is invalid.",
            viewer_num
          );
          CDialogSetTransientFor(toplevel);
          CDialogGetResponse(
"Non-critical internal error!",
            s,
"The viewer number given to this function is\n\
invalid. Cannot continue with preview.",
            CDIALOG_ICON_ERROR,
            CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
            CDIALOG_BTNFLAG_OK
          );
          CDialogSetTransientFor(NULL);
          g_free(s);
          return;
      }

      /* Got viewer pointer, now check if the viewer is mapped and
       * initialized
       */
      if(!v->initialized || !v->map_state)
          return;

      /* Set up viewer's values */
      v->editor_num = editor_num;

      /* Get given branch's trunk */
      trunk = EditorItemGetToplevel(editor, branch);
      if(trunk == NULL)
      {
          CDialogSetTransientFor(toplevel);
          CDialogGetResponse(
"Non-critical internal error!",
"EditorDoPreview(): Given branch has no trunk.\n",
"The branch pointer given to this function has\n\
no trunk branch pointer that could be found.\n\
Cannot continue with preview.",
            CDIALOG_ICON_ERROR,
            CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
            CDIALOG_BTNFLAG_OK
          );
          CDialogSetTransientFor(NULL);
          return;
      }

      /* Get trunk item pointer */
      item = EditorBranchGetData(ctree, trunk);
      if(item == NULL)
      {
          CDialogSetTransientFor(toplevel);
          CDialogGetResponse(
"Non-critical internal error!",
"EditorDoPreview(): No item data found for given\n\
branch's trunk branch.\n",
"The branch pointer given to this function has\n\
a trunk branch with no item data that contains\n\
the information of the manual pages. Cannot\n\
continue with preview.",
            CDIALOG_ICON_ERROR,
            CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
            CDIALOG_BTNFLAG_OK
          );
          CDialogSetTransientFor(NULL);
          return;
      }


      /* Create tempory files directory for this program as needed
       * (return string needs to be deallocated).
       */
      prog_tmp_path = MEditCreateTempDir(core_ptr);
      if(prog_tmp_path == NULL)
      {
          CDialogSetTransientFor(toplevel);
          CDialogGetResponse(
"Non-critical internal error!",
"EditorDoPreview(): MEditCreateTempDir() did not return a path.",
"Could not obtain program tempory file directory path,\n\
and thus unable to generate tempory files for preview.\n\
Cannot continue with preview.",
            CDIALOG_ICON_ERROR,
            CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
            CDIALOG_BTNFLAG_OK
          );
          CDialogSetTransientFor(NULL);
          return;
      }

      /* Create a tempory file to save trunk to it */
      tmp_path = g_strdup(PrefixPaths(
          prog_tmp_path, "previewXXXXXX"
      ));
      mkstemp(tmp_path);

      /* Here we play a trick, first record the full path name
       * on the item data and replace it with our tempory file path
       * so that it gets saved to that. After saving we set back
       * the file path name on the item data to what it was
       */
      orig_path = item->full_path;
      item->full_path = tmp_path;
      tmp_path = NULL;

      /* Save branch with an updated filename to the tempory file */
      EditorFileSave(editor, branch);

      /* Clear viewer and load new manual page file */
      ViewerViewTextRecordScrollPositions(v);
      ViewerTextDelete(v, 0, -1);
      ViewerTextInsertPosition(v, 0);
      status = ViewerOpenFile(
          v, item->full_path, orig_path
      );

      /* Remove tempory saved manual page */
      if(item->full_path != NULL)
          unlink(item->full_path);


      /* Free tempory path (this was our tmp_path) */
      g_free(item->full_path);

      /* Set back original full file name on item */
      item->full_path = orig_path;
      orig_path = NULL;


      /* Free program tempory files directory path */
      g_free(prog_tmp_path);
      prog_tmp_path = NULL;
}


/*
 *    Procedure to find needle from haystack with respect to
 *    the given text widget.
 *
 *    Both needle and haystack may be modified by this function,
 *    but never deallocated.
 *
 *    Given GtkText widget will be updated and instructed to select
 *    the matched text if a match was made. If case_sensitive is TRUE
 *    then the search will be made case sensitive, and if move_to is
 *    set to TRUE then gtk_editable_set_position() will be called to
 *    scroll to the new matched position.
 *
 *    If haystack_len is -1 then strlen() will be called on haystack
 *    to get the actual length. Given start_pos will be sanitized,
 *    if start_pos is >= haystack_len then start_pos will be set to 0.
 *
 *    Returns TRUE if a match is made.
 *
 *    Pointer to search_wrapped will be set to TRUE if a match
 *    was made after a search wrapped through the entire buffer.
 */
gboolean EditorDoFind(  
      editor_struct *editor, GtkText *text,
      gchar *haystack, gchar *needle,
      gint haystack_len, gint start_pos,
      gboolean case_sensitive,
      gboolean move_to,
      gboolean *search_wrapped
)
{
      gchar *bp, *match_ptr;


      /* Reset search wrapped */
      if(search_wrapped != NULL)
          (*search_wrapped) = FALSE;

      /* Inputs valid? */
      if((editor == NULL) || (text == NULL) ||
         (haystack == NULL) || (needle == NULL)
      )
          return(FALSE);

      /* Need to get haystack length ourself? */
      if(haystack_len < 0)
          haystack_len = strlen(haystack);

      /* Empty haystack? */
      if(haystack_len < 1)
          return(FALSE);

      /* Empty needle? */
      if((*needle) == '\0')
          return(FALSE);

      EditorSetStatusMessage(editor, "Finding...");

      /* Sanitize starting position */
      if(start_pos >= haystack_len)
          start_pos = 0;
      else if(start_pos < 0)
          start_pos = 0;


      /* Case insensitive search? */
      if(!case_sensitive)
      {
          /* Need to modify buffers to upper case */

          /* Modify ending portion of haystack */
          bp = (gchar *)(haystack + start_pos);
          while((*bp) != '\0')
          {
            (*bp) = toupper(*bp);
            bp++;
          }

          /* Modify needle */
          bp = needle;
          while((*bp) != '\0')
          {
            (*bp) = toupper(*bp);
            bp++;
          }
      }


      /* Begin search from starting position */
      match_ptr = strstr(
          (gchar *)(haystack + start_pos),
          needle
      );
      if(match_ptr == NULL)
      {
          /* Did not get match, so start from beginning of haystack
           * and search again. First check if this is case insensitive.
           */
          if(!case_sensitive)
          {
            /* Toupper the beginning portion of the buffer */
            bp = haystack;
            while(bp < (gchar *)(haystack + start_pos))
            {
                (*bp) = toupper(*bp);
                bp++;
            }
          }
          /* Now try match again for the second time starting form the
           * beginning.
           */
          match_ptr = strstr(
            (gchar *)(haystack + 0),
            needle
          );
          if(match_ptr != NULL)
          {
            /* Got match the second time, now mark search wrapped
             * as true.
             */
            if(search_wrapped != NULL)
                (*search_wrapped) = TRUE;
          }
      }

      EditorSetStatusMessage(editor, "Find done");

      /* Did we get a match? */
      if(match_ptr == NULL)
      {
          /* Sorry, no match made */
          return(FALSE);
      }
      else
      {
          /* Got match */
          gint match_start_pos = (gint)(match_ptr - haystack);
          gint needle_len = strlen(needle);

          if(match_start_pos < 0)
            match_start_pos = 0;

          /* Now modify the text widget, set new cursor position and
           * select the matched string.
           */
          if(TRUE)
          {
            GtkEditable *editable = (GtkEditable *)text;

            /* Scroll to new matched position? */
            if(move_to)
            {
                gtk_text_set_point(text, match_start_pos);
                gtk_editable_set_position(
                  editable, match_start_pos
                );
            }

            if(needle_len > 0)
            {
                gtk_editable_select_region(
                  editable,
                  match_start_pos,
                  match_start_pos + needle_len
                );
            }
          }

          return(TRUE);
      }
}


/*
 *    Procedure to replace the `next' occurance of needle in
 *    haystack on the given GtkText widget with replacement.
 *
 *    This function calls EditorDoFind() so the given haystack
 *    and needle may be modified.
 *
 *    This function will freeze and thaw the given GtkText widget but
 *    not set its sensitivity.
 *
 *    If the given GtkText widget already has a selection marked
 *    then no find will be made and the selected text will be
 *    replaced with the replacement.
 *
 *    Returns TRUE if a replace was done and FALSE if no replace
 *    was made or error.
 */
gboolean EditorDoReplace(
      editor_struct *editor, GtkText *text,
      gchar *haystack, gchar *needle, const gchar *replacement,
      gint haystack_len, gint start_pos,
      gboolean case_sensitive
)
{
      GtkEditable *editable;
      gint delete_len, replacement_len;
      medit_core_struct *core_ptr;
      medit_styles_list_struct *styles_list;
      GtkStyle *style_ptr;


      /* Inputs valid? */
      if((editor == NULL) || (text == NULL) ||
         (haystack == NULL) || (needle == NULL) || (replacement == NULL)
      )
          return(FALSE);

      /* Get core structure pointer */
      core_ptr = (medit_core_struct *)editor->core_ptr;
      if(core_ptr == NULL)
          return(FALSE);


      /* Get pointer to styles list structure on core structure */
      styles_list = &core_ptr->styles_list;


      editable = GTK_EDITABLE(text);

      /* Get length of replacement string */
      replacement_len = strlen(replacement);


      /* GtkText already has selection? */
      if(editable->has_selection)
      {
          /* Text already selected */

          EditorSetStatusMessage(editor, "Replacing...");

          /* Set new starting position, overriding the given one */
          start_pos = editable->selection_start_pos;

          /* Get length of text to delete, can be 0 */
          delete_len = MAX(
            editable->selection_end_pos - editable->selection_start_pos,
            0
          );
      }
      else
      {
          /* Text not selected, so we need to find first */
          gboolean search_wrapped;
          gboolean got_match = EditorDoFind(
            editor, text,
            haystack, needle,
            haystack_len, start_pos,
            case_sensitive,
            TRUE,             /* Scroll to matched position */
            &search_wrapped
          );

          EditorSetStatusMessage(editor, "Replacing...");

          /* Didn't get match? */
          if(!got_match)
          {
            /* No match, then that means we have nothing to replace */
            EditorSetStatusMessage(editor, "Replace done");
            return(FALSE);
          }

          /* Now hopefully the text widget has its selection and marked */
          if(!editable->has_selection)
          {
            /* Something went wrong, supposedly got match but GtkText
             * widget was not marked as having a selection.
             */
            EditorSetStatusMessage(editor, "Replace done");
            return(FALSE);
          }

          /* Set new starting position, overriding the given one */
          start_pos = editable->selection_start_pos;

          /* Get length of text to delete, can be 0 */
          delete_len = MAX(
            editable->selection_end_pos - editable->selection_start_pos,
            0
          );
      }

      /* Now we do replace, start_pos and delete_len should be valid
       * now.
       */

      /* Any text to delete? */
      if(delete_len > 0)
      {
          if(use_text_delete)
          {
            EditorTextDeleteCB(
                editable, start_pos, start_pos + delete_len,
                (gpointer)editor
            );
            gtk_text_freeze(text);
            gtk_text_set_point(text, (guint)start_pos);
            gtk_text_forward_delete(text, (guint)delete_len);
            gtk_text_thaw(text);
          }
          else
          {
            gtk_text_freeze(text);
            gtk_editable_delete_text(
                editable, start_pos, start_pos + delete_len
            );
            gtk_text_thaw(text);
          }
      }

      /* Insert replacement string? */
      if(replacement_len > 0)
      {
          GdkFont *font;
          gint position;


          /* Select GdkFont from styles list (can be NULL) */
          style_ptr = styles_list->edit_text_standard;
          font = ((style_ptr == NULL) ? NULL : style_ptr->font);

          /* Set insert point and insert replacement text */
          gtk_text_set_point(text, start_pos);
          gtk_text_freeze(text);
          gtk_text_insert(
            text,
            font,
            NULL, NULL,
            replacement,
            replacement_len
          );
          gtk_text_thaw(text);

          /* Call insert callback after inserting text */
          position = start_pos;
          EditorTextInsertCB(
            editable, (const gchar *)replacement,
            replacement_len, &position,
            (gpointer)editor
          );

          /* Move cursor position after replacement */
          gtk_text_set_point(text, start_pos + replacement_len);
          gtk_editable_set_position(
            editable, start_pos + replacement_len
          );

          /* Do not select replacement */
      }


      EditorSetStatusMessage(editor, "Replace done");

      return(TRUE);
}


/*
 *      Procedure to replace the all occurances (if any) of needle in
 *      the given GtkText widget's text with replacement.
 *
 *      This function will freeze and thaw the given GtkText widget but
 *      not set its sensitivity.      
 *
 *      This function calls EditorDoFind() so the given haystack
 *      and needle may be modified. 
 *
 *    Returns the number of replacements made or 0 on error or no
 *    matches.
 */
gint EditorDoReplaceAll(
      editor_struct *editor, GtkText *text,
      gchar *needle, const gchar *replacement,
      gboolean case_sensitive
)
{
      GtkEditable *editable;
      gint delete_len, replacement_len;
      medit_core_struct *core_ptr;
      medit_styles_list_struct *styles_list;
      GtkStyle *style_ptr;
      gint orig_pos;
      gint replace_count = 0;


      /* Inputs valid? */
      if((editor == NULL) || (text == NULL) ||
         (needle == NULL) || (replacement == NULL)
      )
          return(replace_count);

      /* Get core structure pointer */
      core_ptr = (medit_core_struct *)editor->core_ptr;
      if(core_ptr == NULL)
          return(replace_count);

      /* Get pointer to styles list structure on core structure */
      styles_list = &core_ptr->styles_list;


      editable = GTK_EDITABLE(text);

      /* Get length of replacement string */
      replacement_len = strlen(replacement);

      /* Record initial position */
      orig_pos = (gint)gtk_editable_get_position(editable);


      if(TRUE)
      {
          /* Seek back to beginning and do a through search, for each
           * matched find, replace it with replacement.
           */
          gboolean search_wrapped;
          gboolean got_match;
          gint start_pos, next_pos = 0;
          gchar *haystack = NULL;

          do
          {
            /* Get latest haystack from text widget */
            g_free((gpointer)haystack);
            haystack = gtk_editable_get_chars(editable, 0, -1);

            /* Do find */
            got_match = EditorDoFind(
                editor, text,
                haystack, needle,
                -1, next_pos,
                case_sensitive,
                FALSE,        /* No scroll to matched position */
                &search_wrapped
            );
            if(!got_match)
                break;

            /* If the search wrapped then do not perform any more
             * replacements since it may have matched an embedded
             * part of needle in the replacement for example.
             */
            if(search_wrapped)
                break;

            /* Now hopefully the text widget has its selection and
             * marked.
             */
            if(!editable->has_selection)
            {
                /* Something went wrong, supposedly got match but
                 * GtkText widget was not marked as having a
                 * selection.
                 */
                break;
            }

            /* Get start of selection as start position */
            start_pos = editable->selection_start_pos;

            /* Set next starting position, being past the current
             * selected starting position and past what would be
             * the length of the replacement string.
             */
            next_pos = start_pos + replacement_len;

            /* Get length of text to delete, can be 0 */
            delete_len = MAX(
                editable->selection_end_pos -
                  editable->selection_start_pos,
                0
            );

            /* Any text to delete? */
            if(delete_len > 0)
            {
                if(use_text_delete)
                {
                  EditorTextDeleteCB(
                      editable, start_pos, start_pos + delete_len,
                      (gpointer)editor
                  );
                  gtk_text_freeze(text);
                  gtk_text_set_point(text, (guint)start_pos);
                  gtk_text_forward_delete(text, (guint)delete_len);
                  gtk_text_thaw(text);
                }
                else
                {
                  gtk_text_freeze(text);
                  gtk_editable_delete_text(
                      editable, start_pos, start_pos + delete_len
                  );
                  gtk_text_thaw(text);
                }
            }

            /* Insert replacement string? */
            if(replacement_len > 0)
            {
                GdkFont *font;
                gint position;


                /* Select GdkFont from styles list (can be NULL) */
                style_ptr = styles_list->edit_text_standard;
                font = ((style_ptr == NULL) ? NULL : style_ptr->font);

                /* Set insert point and insert replacement text */
                gtk_text_set_point(text, start_pos);
                gtk_text_freeze(text);
                gtk_text_insert(
                  text,
                  font,
                  NULL, NULL,
                  replacement,
                  replacement_len
                );
                gtk_text_thaw(text);

                /* Call insert callback after inserting text */
                position = start_pos;
                EditorTextInsertCB(
                  editable, (const gchar *)replacement,
                  replacement_len, &position,
                  (gpointer)editor
                );

                /* Move cursor position after replacement */
                gtk_text_set_point(text, start_pos + replacement_len);
#if 0
                gtk_editable_set_position(
                  editable, start_pos + replacement_len
                );
#endif
                /* Do not select replacement */
            }

            replace_count++;

          } while(1);

          /* Deallocate haystack as needed */
          g_free((gpointer)haystack);
          haystack = NULL;
      }

      /* Set back original position */
      if(orig_pos > (gint)gtk_text_get_length(text))
          orig_pos = (gint)gtk_text_get_length(text);
      gtk_text_set_point(text, orig_pos);
/*    gtk_editable_set_position(editable, orig_pos); */


      return(replace_count);
}

Generated by  Doxygen 1.6.0   Back to index