home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Exec 3 / CD_Magazyn_EXEC_nr_3.iso / Recent / misc / edu / WhirlDisc.lha / WhirlDisc / Source / search.c < prev    next >
C/C++ Source or Header  |  2000-08-13  |  15KB  |  538 lines

  1. /*
  2.  
  3. File: search.c
  4. Author: Neil Cafferkey
  5. Copyright (C) 2000 Neil Cafferkey
  6.  
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  20. MA 02111-1307, USA.
  21.  
  22. */
  23.  
  24. #include "viewer.h"
  25. #include <stdlib.h>
  26. #include <exec/memory.h>
  27. #include <intuition/screens.h>
  28. #include <libraries/gadtools.h>
  29.  
  30. #include "search_protos.h"
  31. #include "general_protos.h"
  32. #include "article_protos.h"
  33. #include "index_protos.h"
  34. #include "paedia_protos.h"
  35. #include <proto/exec.h>
  36. #include <proto/intuition.h>
  37. #include <proto/graphics.h>
  38. #include <proto/gadtools.h>
  39.  
  40.  
  41. #define SUBJECT_LINE_COUNT 4
  42. #define MIN_ARTICLE_LINE_COUNT 4
  43. #define DEFAULT_SEARCH_WIDTH 250
  44. #define DEFAULT_SEARCH_HEIGHT 250
  45. enum {KEYWORD_BOX_ID=1,SEARCH_BUTTON_ID,SUBJECT_VIEW_ID,ARTICLE_VIEW_ID};
  46.  
  47. const TEXT *keyword_box_label="Search Words";
  48. const TEXT *search_button_label="Search";
  49. const TEXT *subject_view_label="Subjects";
  50. const TEXT *article_view_label="Articles";
  51.  
  52.  
  53. /* Prototypes */
  54.  
  55. static BOOL OpenSearchGadgets(Search search);
  56. static VOID CloseSearchGadgets(Search search);
  57.  
  58.  
  59.  
  60. /* Function: CreateSearch
  61.  * ======================
  62.  * Creates a Search.
  63.  */
  64.  
  65. Search CreateSearch(struct MsgPort *msg_port,Paedia paedia,
  66.    struct MinList *object_list,UWORD left,UWORD top)
  67. {
  68.    Search search;
  69.    BOOL success=TRUE;
  70.    struct Screen *screen=NULL;
  71.    struct IntuiText i_text;
  72.    struct Window *window;
  73.  
  74.    if(search=AllocMem(sizeof(Search_imp),MEMF_CLEAR))
  75.    {
  76.  
  77.       search->node.ln_Type=NT_SEARCH;
  78.       search->paedia=paedia;
  79.       search->object_list=object_list;
  80.       search->msg_port=msg_port;
  81.  
  82.       /* Allocate memory for search string */
  83.  
  84.       if((search->keywords=AllocMem(64+1,MEMF_ANY))!=NULL)
  85.       {
  86.          *search->keywords='\0';
  87.       }
  88.       else
  89.       {
  90.          ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
  91.          success=FALSE;
  92.       }
  93.  
  94.       /* Open the search window */
  95.  
  96.       search->window=window=OpenWindowTags(NULL,
  97.          WA_Left,left,
  98.          WA_Top,top,
  99.          WA_Width,DEFAULT_SEARCH_WIDTH,
  100.          WA_Height,DEFAULT_SEARCH_HEIGHT,
  101.          WA_Flags,WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|WFLG_SIZEBBOTTOM|
  102.             WFLG_SIZEGADGET|WFLG_ACTIVATE|WFLG_NEWLOOKMENUS|WFLG_DRAGBAR,
  103.          WA_Title,"Index",
  104.          WA_MinWidth,0,
  105.          WA_MinHeight,0,
  106.          WA_MaxWidth,-1,
  107.          WA_MaxHeight,-1,
  108.          TAG_END);
  109.  
  110.       /* Lock the screen so it can be examined during the life of this
  111.          Search. */
  112.  
  113.       search->screen=screen=LockPubScreen(NULL);
  114.  
  115.       if(window)
  116.       {
  117.  
  118.          /* Set the window's message port and IDCMP flags */
  119.  
  120.          window->UserPort=msg_port;
  121.  
  122.          ModifyIDCMP(window,IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE|
  123.             IDCMP_CHANGEWINDOW|STRINGIDCMP|BUTTONIDCMP|LISTVIEWIDCMP);
  124.  
  125.          /* Store Search's pointer in its window */
  126.  
  127.          (Search)window->UserData=search;
  128.  
  129.          /* Calculate gadget positions and sizes */
  130.  
  131.          search->font_height=screen->Font->ta_YSize;
  132.          search->gadget_left=window->BorderLeft+INTERWIDTH;
  133.          search->gadget_top=window->BorderTop+INTERHEIGHT
  134.             +search->font_height+INTERHEIGHT;
  135.  
  136.          search->gadget_rel_width=
  137.             -window->BorderRight-INTERWIDTH-search->gadget_left;
  138.  
  139.          i_text.ITextFont=screen->Font;
  140.          i_text.IText=search_button_label;
  141.          i_text.NextText=NULL;
  142.  
  143.          search->search_button_width=IntuiTextLength(&i_text)+12;
  144.          search->search_button_rel_left=-window->BorderLeft
  145.             -INTERWIDTH-search->search_button_width;
  146.  
  147.          search->keyword_box_rel_width=
  148.             -window->BorderRight-2*INTERWIDTH
  149.             -search->search_button_width-search->gadget_left;
  150.          search->keyword_box_height=search->font_height+6;
  151.  
  152.          search->subject_view_top=search->gadget_top
  153.             +search->keyword_box_height+search->font_height+2*INTERHEIGHT;
  154.          search->subject_view_height=search->font_height*SUBJECT_LINE_COUNT
  155.             +4;
  156.          search->article_view_top=search->subject_view_top
  157.             +search->subject_view_height+search->font_height+2*INTERHEIGHT;
  158.          search->article_view_rel_height=-search->article_view_top
  159.             -window->BorderBottom-INTERHEIGHT;
  160.  
  161.          /* Set minimum window dimensions */
  162.  
  163.          i_text.IText=keyword_box_label;
  164.          search->min_width=-search->search_button_rel_left
  165.             +IntuiTextLength(&i_text)+2*INTERWIDTH+window->BorderLeft;
  166.  
  167.          search->min_height=search->article_view_top+search->font_height*
  168.             MIN_ARTICLE_LINE_COUNT+4+INTERHEIGHT+window->BorderBottom;
  169.  
  170.  
  171.          if(!WindowLimits(window,search->min_width,search->min_height,0,0))
  172.             ChangeWindowBox(window,window->LeftEdge,window->TopEdge,
  173.                search->min_width,search->min_height);
  174.  
  175.          /* Create gadgets */
  176.  
  177.          search->visual_info=GetVisualInfoA(screen,NULL);
  178.          OpenSearchGadgets(search);
  179.  
  180.       }
  181.       else
  182.       {
  183.          success=FALSE;
  184.       }
  185.  
  186.       if(!success)
  187.       {
  188.          KillSearch(search);
  189.          search=NULL;
  190.       }
  191.    }
  192.    else
  193.       ReportError(NULL,ERROR_REPORT_MEM,NULL,0);
  194.  
  195.    return search;
  196. }
  197.  
  198.  
  199.  
  200. /* Function: OpenSearchGadgets
  201.  * ===========================
  202.  * Sets up a Search's gadgets. Returns a success flag.
  203.  */
  204.  
  205. static BOOL OpenSearchGadgets(Search search)
  206. {
  207.    BOOL success=TRUE;
  208.    struct Screen *screen=search->screen;
  209.    struct NewGadget new_gadget;
  210.    struct Window *window=search->window;
  211.  
  212.    /* Recalculate variable gadget positions and sizes */
  213.  
  214.  
  215.  
  216.    /* Create a gadtools context for this window */
  217.  
  218.    search->context=CreateContext(&search->gadgets);
  219.  
  220.    /* Create the keyword box */
  221.  
  222.    new_gadget.ng_LeftEdge=search->gadget_left;
  223.    new_gadget.ng_TopEdge=search->gadget_top;
  224.    new_gadget.ng_Width=window->Width+search->keyword_box_rel_width;
  225.    new_gadget.ng_Height=search->keyword_box_height;
  226.    new_gadget.ng_GadgetText=keyword_box_label;
  227.    new_gadget.ng_TextAttr=screen->Font;
  228.    new_gadget.ng_GadgetID=KEYWORD_BOX_ID;
  229.    new_gadget.ng_Flags=PLACETEXT_ABOVE|NG_HIGHLABEL;
  230.    new_gadget.ng_VisualInfo=search->visual_info;
  231.    new_gadget.ng_UserData=0;
  232.  
  233.    search->keyword_box=CreateGadget(STRING_KIND,search->context,
  234.       &new_gadget,GTST_String,search->keywords,TAG_END);
  235.  
  236.    /* Create the search button */
  237.  
  238.    new_gadget.ng_LeftEdge=window->Width+search->search_button_rel_left;
  239.    new_gadget.ng_TopEdge=search->gadget_top;
  240.    new_gadget.ng_Width=search->search_button_width;
  241.    new_gadget.ng_Height=search->keyword_box_height;
  242.    new_gadget.ng_GadgetText=search_button_label;
  243.    new_gadget.ng_TextAttr=screen->Font;
  244.    new_gadget.ng_GadgetID=SEARCH_BUTTON_ID;
  245.    new_gadget.ng_Flags=0;
  246.    new_gadget.ng_VisualInfo=search->visual_info;
  247.    new_gadget.ng_UserData=0;
  248.  
  249.    search->search_button=CreateGadget(BUTTON_KIND,search->keyword_box,
  250.       &new_gadget,TAG_END);
  251.  
  252.    /* Create the subject listview */
  253.  
  254.    new_gadget.ng_LeftEdge=search->gadget_left;
  255.    new_gadget.ng_TopEdge=search->subject_view_top;
  256.    new_gadget.ng_Width=window->Width+search->gadget_rel_width;
  257.    new_gadget.ng_Height=search->subject_view_height;
  258.    new_gadget.ng_GadgetText=subject_view_label;
  259.    new_gadget.ng_TextAttr=screen->Font;
  260.    new_gadget.ng_GadgetID=SUBJECT_VIEW_ID;
  261.    new_gadget.ng_Flags=0;
  262.    new_gadget.ng_VisualInfo=search->visual_info;
  263.    new_gadget.ng_UserData=0;
  264.  
  265.    search->subject_view=CreateGadget(LISTVIEW_KIND,search->search_button,
  266.       &new_gadget,GTLV_Labels,search->index_list,GTLV_Selected,
  267.       search->selected_subject_no,GTLV_ShowSelected,NULL,
  268.       GTLV_Top,search->top_subject_no,TAG_END);
  269.  
  270.    /* Create the article listview */
  271.  
  272.    new_gadget.ng_LeftEdge=search->gadget_left;
  273.    new_gadget.ng_TopEdge=search->article_view_top;
  274.    new_gadget.ng_Width=window->Width+search->gadget_rel_width;
  275.    new_gadget.ng_Height=window->Height+search->article_view_rel_height;
  276.    new_gadget.ng_GadgetText=article_view_label;
  277.    new_gadget.ng_TextAttr=screen->Font;
  278.    new_gadget.ng_GadgetID=ARTICLE_VIEW_ID;
  279.    new_gadget.ng_Flags=0;
  280.    new_gadget.ng_VisualInfo=search->visual_info;
  281.    new_gadget.ng_UserData=0;
  282.  
  283.    if(search->current_subject!=NULL)
  284.    {
  285.       search->article_view=CreateGadget(LISTVIEW_KIND,search->subject_view,
  286.          &new_gadget,GTLV_Labels,&search->current_subject->ref_list,
  287.          GTLV_Top,search->top_article_no,TAG_END);
  288.    }
  289.    else
  290.    {
  291.       search->article_view=CreateGadget(LISTVIEW_KIND,search->subject_view,
  292.          &new_gadget,GTLV_Labels,NULL,TAG_END);
  293.    }
  294.  
  295.    /* Add gadgets to window and make them visible */
  296.  
  297.    if(search->gadgets!=NULL)
  298.    {
  299.       AddGList(window,search->gadgets,-1,-1,NULL);
  300.       RefreshGList(search->gadgets,window,NULL,-1);
  301.       GT_RefreshWindow(window,NULL);
  302.    }
  303.    else
  304.    {
  305.       success=FALSE;
  306.    }
  307.  
  308.    if(!success)
  309.    {
  310.       KillSearch(search);
  311.       search=NULL;
  312.    }
  313.  
  314.    return success;
  315. }
  316.  
  317.  
  318.  
  319. /* Function: CloseSearchGadgets
  320.  * ============================
  321.  * Destroys a Search's gadgets.
  322.  */
  323.  
  324. static VOID CloseSearchGadgets(Search search)
  325. {
  326.    TEXT *keywords;
  327.  
  328.    /* Copy keyword string from gadget */
  329.  
  330.    GT_GetGadgetAttrs(search->keyword_box,search->window,NULL,GTST_String,
  331.       &keywords,TAG_END);
  332.    if(search->keywords)
  333.       strcpy(search->keywords,keywords);
  334.  
  335.    /* Store listview attributes */
  336.  
  337.    GT_GetGadgetAttrs(search->subject_view,search->window,NULL,GTLV_Selected,
  338.       &search->selected_subject_no,GTLV_Top,&search->top_subject_no,
  339.       TAG_END);
  340.  
  341. /*printf("search->selected_subject_no=%u\n",search->selected_subject_no);*/
  342.  
  343.    GT_GetGadgetAttrs(search->article_view,search->window,NULL,GTLV_Top,
  344.       &search->top_article_no,TAG_END);
  345.  
  346.    /* Remove and free gadgets */
  347.  
  348.    RemoveGList(search->window,search->gadgets,-1);
  349.    FreeGadgets(search->gadgets);
  350.  
  351.    /* Clear window */
  352.  
  353.    SetRast(search->window->RPort,0);
  354.    RefreshWindowFrame(search->window);
  355.  
  356.    return;
  357. }
  358.  
  359.  
  360.  
  361. /* Function: HandleSearchInput
  362.  * ===========================
  363.  */
  364.  
  365. VOID HandleSearchInput(Search search,struct IntuiMessage *msg)
  366. {
  367.    BOOL close=FALSE;
  368.    ULONG article_no=0;
  369.    struct IntuiMessage *mod_msg;
  370.    struct Gadget *gadget=(struct Gadget *)msg->IAddress;
  371.    TEXT *keywords;
  372.    Article article;
  373.    Reference ref;
  374.    Sequence article_data;
  375.  
  376.    mod_msg=GT_FilterIMsg(msg);
  377.    if(mod_msg!=NULL)
  378.    {
  379.  
  380.       switch(mod_msg->Class)
  381.       {
  382.  
  383.       case IDCMP_NEWSIZE:
  384.          CloseSearchGadgets(search);
  385.          OpenSearchGadgets(search);
  386.          break;
  387.  
  388.       case IDCMP_CLOSEWINDOW:
  389.          close=TRUE;
  390.          break;
  391.  
  392.       case IDCMP_GADGETUP:
  393.  
  394.          switch(gadget->GadgetID)
  395.          {
  396.          case KEYWORD_BOX_ID:
  397.          case SEARCH_BUTTON_ID:
  398.  
  399.             /* Copy keyword string from gadget */
  400.  
  401.             GT_GetGadgetAttrs(search->keyword_box,search->window,NULL,
  402.                GTST_String,&keywords,TAG_END);
  403.             strcpy(search->keywords,keywords);
  404.  
  405.             /* Remove subject and article lists from their gadgets */
  406.  
  407.             GT_SetGadgetAttrs(search->subject_view,search->window,NULL,
  408.                GTLV_Labels,NULL,TAG_END);
  409.  
  410.             GT_SetGadgetAttrs(search->article_view,search->window,NULL,
  411.                GTLV_Labels,NULL,TAG_END);
  412.  
  413.             /* Do a new index search */
  414.  
  415.             if(search->index_list)
  416.                KillIndexResults(search->index_list);
  417.  
  418.             SetWindowPointer(search->window,WA_BusyPointer,TRUE,TAG_END);
  419.  
  420.             search->index_list=FindIndexRecords(search->paedia->index,
  421.                search->keywords);
  422.  
  423.             /* Display new subjects */
  424.  
  425.             GT_SetGadgetAttrs(search->subject_view,search->window,NULL,
  426.                GTLV_Labels,search->index_list,GTLV_Selected,0,TAG_END);
  427.  
  428.             SetWindowPointer(search->window,TAG_END);
  429.  
  430.          case SUBJECT_VIEW_ID:
  431.  
  432.             /* Get current subject number */
  433.  
  434.             GT_GetGadgetAttrs(search->subject_view,search->window,NULL,
  435.                GTLV_Selected,&search->selected_subject_no,TAG_END);
  436.  
  437.             if(search->selected_subject_no!=~0)
  438.             {
  439.                search->current_subject=(IndexRecord)GetMinListNode(
  440.                   (struct MinList *)search->index_list,
  441.                   search->selected_subject_no);
  442.  
  443.                /* Display new article titles */
  444.  
  445.                GT_SetGadgetAttrs(search->article_view,search->window,NULL,
  446.                   GTLV_Labels,&search->current_subject->ref_list,TAG_END);
  447.             }
  448.             else
  449.             {
  450.                search->current_subject=NULL;
  451.             }
  452.  
  453.             break;
  454.  
  455.          case ARTICLE_VIEW_ID:
  456.  
  457.             /* Display selected article */
  458.  
  459.             ref=(Reference)GetMinListNode(
  460.                (struct MinList *)&search->current_subject->ref_list,
  461.                mod_msg->Code);
  462.  
  463.             article_data=GetPaediaItem(search->paedia,ref->link_no);
  464.             article=CreateArticle(article_data,search->msg_port);
  465.             if(article)
  466.                AddTail((struct List *)search->object_list,&article->node);
  467.  
  468.          default:
  469.  
  470.          }
  471.  
  472.       case IDCMP_CHANGEWINDOW:
  473.          if(!WindowLimits(search->window,search->min_width,
  474.             search->min_height,0,0))
  475.             ChangeWindowBox(search->window,search->window->LeftEdge,
  476.                search->window->TopEdge,search->min_width,
  477.                search->min_height);
  478.          break;
  479.  
  480.       default:
  481.  
  482.       }
  483.  
  484.       GT_PostFilterIMsg(mod_msg);
  485.    }
  486.  
  487.    ReplyMsg((struct Message *)msg);
  488.  
  489.    if(close)
  490.    {
  491.       Remove(&search->node);
  492.       KillSearch(search);
  493.    }
  494.  
  495.    return;
  496. }
  497.  
  498.  
  499.  
  500. /* Function: KillSearch
  501.  * ====================
  502.  * Destroys a Search.
  503.  */
  504.  
  505. VOID KillSearch(Search search)
  506. {
  507.  
  508.    if(search->index_list)
  509.       KillIndexResults(search->index_list);
  510.  
  511.    if(search->window)
  512.    {
  513.  
  514.       CloseSearchGadgets(search);
  515.  
  516.       Forbid();
  517.       StripWindowMessages(search->window);
  518.       search->window->UserPort=NULL;
  519.       ModifyIDCMP(search->window,0);
  520.       Permit();
  521.       CloseWindow(search->window);
  522.       UnlockPubScreen(NULL,search->screen);
  523.    }
  524.  
  525.    FreeVisualInfo(search->visual_info);
  526.  
  527.    if(search->keywords!=NULL)
  528.       FreeMem(search->keywords,64+1);
  529.  
  530.    /* Free search structure */
  531.  
  532.    FreeMem(search,sizeof(Search_imp));
  533.  
  534.    return;
  535. }
  536.  
  537.  
  538.