Search CodeCentral from within Delphi and C++ Builder

By: John Kaster

Abstract: John K describes the functionality of the CodeCentral IDE Expert for Delphi and C++ Builder, and shows the Open Tools source code used for doing it

The CodeCentral™ Expert for Delphi and C++ Builder

by John Kaster

This article describes the CodeCentral expert Jeff Overcash (of TeamB fame) and I wrote. This expert uses the Open Tools API to install itself into the Delphi and C++ Builder IDE menu so the Borland CodeCentral™ repository can be searched from within the IDEs.

A little bit of conference magic goes a long way

Like every year, this year's Borland Conference was a frenetic few days spent visiting old acquaintances, making new ones, catching up on the latest technology, having fun, and brainstorming on cool geek things to do.

As with many developers, I've got development plans that would require years to fulfill. Many times, I find that talking with other developers will change the order of my development priorities. This conference was no exception. During an informal (and private) meeting we had with some of our Delphi field testers, one of them wished (very strongly) for the ability to search an on-line knowledge base for source code examples from within the Delphi IDE. While I'm no genie, I decided as I left the meeting that the conference was the perfect place to fulfill his wish.

An IDE-based interface for CodeCentral was always part of the plan. I just never expected it to take a year. Sometimes the "have-to-do" things get in the way of the "want-to-do" things on your list. This was one of those times. I had talks to prepare (I usually do "bleeding edge" topics, so conference time is sleep deprivation time for me) and present for the conference. My first wedding anniversary was also during the conference (in case you were wondering why no one saw me on Monday night). I also wanted to present something brand new for the community site at the closing session. It looked like once again my plans would have to be postponed, unless I could find some help.

Who you gonna call?

Jeff Overcash has done a great job of living the TeamB motto (We'll do anything as long as you don't pay us), donating a lot of his time and expertise to help me upgrade the interface and functionality of CodeCentral before the conference.

Jeff wasn't speaking at the conference (I haven't been able to talk him into it yet), and once again he volunteered his time to help me get something done for the community site. I told him what I wanted, and he got a demonstrable version of it done before the closing session of the conference. It's great the way that works!

The CodeCentral Expert (CCExpert) is an IDE expert for searching the Borland CodeCentral web site, using the search conditions you enter on the search form. After you enter your search request and hit the Search button, your browser window will be opened and the CodeCentral search results will be displayed.

This search expert is an IDE interface to the CodeCentral web search form. You can also go directly to the search form without having to use the CodeCentral expert.

Installing CCExpert

Just a disclaimer: you are using this IDE expert at your own risk. Jeff and I will only provide support for this expert through comments attached to this upload on CodeCentral, or the CodeCentral newsgroup. If you have suggestions for enhancing it, plesae attach them to this article, or put them in the CodeCentral newsgroup.

You can download the complete source code for CCExpert (CodeCentral ID 15111) here.

To install CCExpert into your Delphi IDE, open CCExpert.dpk, compile it, and click the Install button. To install CCExpert into your C++ Builder IDE, open CCCExpert.bpk, compile it and click the Install button.

Once it is successfully installed, you will have a new menu item in the Help menu called CodeCentral.

Using CCExpert

I have many plans for enhancing this expert, and also for releasing the JBuilder version that was demonstrated at the conference, but most of that will have to wait until the new Windows-based client is released.

The Help|CodeCentral menu

When you install CodeCentral, it inserts a submenu item in the Help menu of the IDE. Here's the code that inserts the menu item.


procedure TdmCodeCentral.DataModuleCreate(Sender: TObject);
const
  SMainMenu = 'HelpMenu';
  {$ifdef VER130} // Delphi 5 or C++ Builder 5 specific
    {$ifdef BCB}
  SSubMenu = 'HelpCommunityPage';
    {$else}
  SSubMenu = 'HelpBorlandCommunityPage';
    {$endif}
  {$else} // This should be for Delphi 6 and beyond
    {$ifdef VER140}
  SSubMenu = 'HelpCommunityPage';
    {$else} // Previous versions of Delphi or C++ Builder
  SSubMenu = 'HelpWinSDKItem';
    {$endif}
  {$endif}
var
  Main : TMenuItem;
  Item : TMenuItem;
  MainMenu : TMainMenu;
  i : Integer;
  {
    You can use the conditonal LIST_MENUS code to find out what the menu
    item names are for the help menu. Simply define LIST_MENUS by removing
    the space in front of the $define (below), and try to install the menu.
    You will be provided with a list of the Help Menu names when you
    try to install this package in the IDE.
  }
  { $define LIST_MENUS}
  {$ifdef LIST_MENUS}
  Menus : string;
  {$endif}
begin
  Main := nil;
  MainMenu := (BorlandIDEServices as INTAServices).GetMainMenu;
  for i := 0 to MainMenu.Items.Count - 1 do
  begin
    if MainMenu.Items[i].Name = SMainMenu then
    begin
      Main := MainMenu.Items[i];
      break;
    end;
  end;
  if Main <> nil then
  begin
    Item := mnuCodeCentral.Items[0];
    mnuCodeCentral.Items.Delete(0);

    {$ifdef LIST_MENUS}
    Menus := '';
    for i := 0 to Main.Count - 1 do
      Menus := Menus + Main.Items[i].Name + #13;
    Raise Exception.Create( Menus );
    {$endif}

    i := 0;
    while (i < Main.Count) and (Main.Items[i].Name <> SSubMenu) do
      Inc(i);
    Main.Insert(i + 1, Item);
  end;
end;

In Delphi 5, the Help menu item names are (in order):

  1. HelpContentsItem
  2. HelpDelphiToolsItem
  3. HelpWinSDKItem
  4. HelpInprisePage
  5. HelpBorlandCommunityPage
  6. HelpDelphiPage
  7. HelpProgramsPage
  8. DirectItem
  9. HelpProgGuideSeparator
  10. HelpCustomizeItem
  11. HelpAboutSeparator
  12. HelpAboutItem

As you can see by looking at the source code above, the CCExpert menu item is inserted under the HelpBorlandCommunityPage menu item. If you want to change its location, simply change the SSubMenu constant to the name of the other menu component.

Note! If you examine the $ifdefs above, you will notice that the community page menu item named changed from "HelpBorlandCommunityPage" to "HelpCommunityPage" between Delphi 5 and C++ Builder 5. I am guessing that it will keep its latest name for Delphi 6 and C++ Builder 6, but this is not guaranteed. Borland does not document the names of the IDE menu items because they change so much in each version of Delphi and C++ Builder. Jeff Overcash has a complete IDE menu item explorer/shortcut modifier he has written that is quite handy for this purpose as well. I'm hoping to convince him to find the time to write an article about it in the near future. For now, if the menu name does change, you can find out what the new menu names are in the help menu by $defining LIST_MENUS and attempting to install the expert in the IDE again.

IDE Sensitivity

If you highlight one or more components on a form before starting CCExpert, the names of those components will automatically be entered as the keywords to find in the CodeCentral repository. The expert will also attempt to automatically detect which IDE you are using, and default the product for the search to that IDE. To do this, the CodeCentral Expert uses the Open Tools API. The following code illustrates.


procedure TdmCodeCentral.miCodeCentralClick(Sender: TObject);
var
  FormIntf: TIFormInterface;
  CompIntf: TIComponentInterface;
  CurrentFile, FileExt, UnitName, ComponentName : String;
  ModIntf: TIModuleInterface;
  i : Integer;
  SList : TStringList;

begin
  ModIntf := nil;
  if not Assigned(frmCodeCentral) then
    frmCodeCentral := TfrmCodeCentral.Create(Application);
  with frmCodeCentral do
  begin
    CurrentFile := ToolServices.GetCurrentFile;
    FileExt := ExtractFileExt(CurrentFile);

    { Get the module interface to determine the Product IDE }
    i := Pos(FileExt, CurrentFile);
    if i > 0 then
    begin
      UnitName := Copy(CurrentFile, 1, i) + 'PAS';
      ModIntf := ToolServices.GetModuleInterface(UnitName);
      Product := 'Delphi';
      if ModIntf = nil then
      begin
        UnitName := Copy(CurrentFile, 1, i) + 'CPP';
        ModIntf := ToolServices.GetModuleInterface(UnitName);
        Product := 'C++ Builder';
      end;
      if ModIntf = nil then
        Product := SAnyProduct;
    end;

    { Attempt to fill in the keyword entry based on the components that
      are currently selected on the form }
    if ModIntf <> nil then
    begin
      FormIntf := ModIntf.GetFormInterface;
      if FormIntf <> nil then
      begin
        SList := TStringList.Create;
        try
          SList.Sorted := true;
          SList.Duplicates := dupIgnore;
          for i := 0 to FormIntf.GetSelCount - 1 do
          begin
            CompIntf := FormIntf.GetSelComponent(i);
            try
              if CompIntF <> nil then
              begin
                ComponentName := CompIntf.GetComponentType;
                if Trim(ComponentName) <> '' then
                  SList.Add(ComponentName);
              end;
            finally
              CompIntf.Free;
            end;
          end;
          for i := 0 to SList.Count - 1 do
            edtKeywords.Text := edtKeywords.Text + '+' + SList[i] + ' ';
        finally
          SList.Free;
        end;
      end;
    end;
    Show;
  end;
end;

Using an Action for User Responsiveness

Simply fill in the values on the form the CodeCentral expert displays, and click the Search button. Any values you specify beyond the default values help to restrict the search to a smaller selection list. The search button will only be enabled if you have specified the required values for the search. The following code enforces this behavior. The Search button is assigned the actSearch action, which gets updated whenever a user interface event occurs.


procedure TfrmCodeCentral.actSearchUpdate(Sender: TObject);
var
  LowVer,
  HighVer,
  ShowMe : Extended;

  function GetNum( Control : TCustomEdit ) : extended;
  begin
    Result := -1;
    if Trim( Control.Text ) <> '' then
      try
        Result := StrToFloat( Control.Text );
      except
      end;
  end;

begin
  LowVer := GetNum( edtLowVersion );
  HighVer := GetNum( edtHighVersion );
  ShowMe := GetNum( edtShowMe );

  actSearch.Enabled := ( Trim( edtKeywords.Text + edtSubmitter.Text ) <> '' )
    and ( LowVer >= 0 ) and ( HighVer >= 0 ) and ( ShowMe > 0 )
    and ( HighVer >= LowVer );
end;

Opening the search results page

This version of the expert simply fills in the search values for the CodeCentral web-based search and opens that URL in your browser registered for handling HTTP requests. It does that by using the BrowseTo() procedure that will open a URL.


procedure TfrmCodeCentral.BrowseTo(URL: string);
begin
  ShellExecute(0, 'Open', PChar(URL), '', '', SW_SHOWDEFAULT );
end;

You can click the Home button to go to the CodeCentral Home page, and the Close button to close the expert.

Search Form Values

You can use several different criteria to search the CodeCentral repository.

Product

If CCExpert can determine what IDE is running, it will default the product search value to that IDE. The following code helps to keep the product combobox synchronized with the value determined by the TdmCodeCentral.miCodeCentralClick() procedure listed above.

The values you can select for searching submissions for a specific product are:

  • Any product, which will search across all products
  • Delphi
  • C++ Builder
  • JBuilder
  • MIDAS
  • Interbase
  • BDE
  • Turbo Pascal
  • Borland C++
  • Keywords

    The keywords for every submission are determined by extracting the unique "words" from the title and description of the entry. These "words" can be alphanumeric, since this is a technical database. You can require words in your search by using a plus (+) sign in front of the word. You can exclude entries containing specific words in your search by using a minus (-) sign in front of the word. The or (|) sign is optional, indicating words that may appear in the search but are not required. You can put any number of keywords you want in the keyword field. Keyword matching is case-insensitive. Any keywords you submit are converted to lowercase first.

    Wildcards are also supported for searching. The asterisk (*) is the wildcard for one or more characters in the pattern match. The question mark (?) is the wildcard for a single character. The "*" and "?" get translated to the equivalent SQL LIKE command characters, so putting them at the start of a word pattern will slow down your search, as no SQL index can be used for them.

    The keyword list for every entry in CodeCentral is automatically generated from its title, long description, and short description. All the unique words (other than the really common ones like "a", "the" and so on) are saved in a separate table that can be used for indexed SQL select statements. This solution provides a little bit more performance and flexibility than doing a text search on the blob fields. I'll publish the components and code that does this at a later date.

    Author

    All entries are submitted by a specific CodeCentral user. If you want to search for entries uploaded by a specific person, you can enter their name or email address in this field.

    You can enter:

  • first name followed by last name (like "Frank Borland")
  • last name, first name (like "Borland, Frank")
  • email address (like "fborland@borland.com")
  • CodeCentral will attempt to match the value you put in this field with a CodeCentral user, and give you only submissions uploaded by that user.

    Low Version and High Version

    All entries are submitted for a range of versions. If you want to search for only one version of the product, enter it as both the low and high value for the version. If you want to search for a range of versions, enter the low value as the low version and the high value as the high version, and all submissions that fall between those two versions will appear in your search results. If you want to search for all versions of a product, use zero (0) and zero (0) respectively.

    Show Me

    Because you may find many entries matching your search values (there are thousands of submissions in CodeCentral), you can use this entry to limit the number of results the search engine returns to you.

    Configuring CCExpert

    If you want to modify the location of the CodeCentral web server for any reason, create a file in your package directory called ccexpert.ini. It should look like this:

    
    [CodeCentral]
    Server=http://codecentral.borland.com/codecentral/ccweb.exe
    
    

    Where the value for Server is the new location for the CodeCentral web server.

    More to come

    There should be new features coming to CCExpert, like zipping up the current project you're working on and uploading it to CodeCentral, and the reincarnation of the GUI client executable. If you have suggestions for things you'd like to see, please comment on this article, or use the CodeCentral Newsgroup to let me know what you'd like to see.

    If you're a Java developer, we really need Java-based submissions so the CodeCentral expert for JBuilder (which I should be able to put out soon) will have lots of things to find when people start searching CodeCentral from within the JBuilder IDE.


    Server Response from: ETNASC02