Last modified 16 years ago
Last modified on 09/22/09 12:20:46
Analysis
Overview
The goal of this task is to provide the ability for the user to search the content of the book.
We could make this live search in some of the next revisions, for now the search will be evoked from button or enter key (while the focus is set to the text input field)
It will be nice to have the ability to search resources by their name or meta data in this palette. (From the server and from all open books). And appropriate interface for that.
In this revision:
- The Tools tab has a Search palette. It lets the user search a Sophie book.
- A text field is available at the top of the palette where a user can enter a word or phrase he wants to find in current book.
- Search button will be available next to the text field.
- Below them next and previous buttons should be available.
- The searching palette in the Tools tab provides a list of results with context (some words before and after the match; also the page number).
- The order of the results is the following one:
- Results from different pages are placed from top to bottom with the order of the page number.
- If the results are in single page they appear sorted by the type of the component that holds them
- EXAMPLE: 3 results are available on the same page. One of them comes from text frame, one of them comes from embedded book and the third comes from text frame inside of a group. So on the top is the results from the text frames, after this comes the result from the group and on the bottom seats the result from the embedded book.
- If the results are on the same page and come from the same type of components they are ordered by the z-order of their holders.
- If the results come from one component they are ordered by their appearance in it.
- EXAMPLE: If they are 2 results inside single text frame, they should be ordered from top to bottom. The first one is the one on top etc.
- EXAMPLE: If the results come from embedded book the rules described above are applied to them.
Typical scenario:
- Text is typed in the field at the top of the palette.
- Enter is hit.
- A list of all occurrences in text are provided in the palette.
- All occurrences are highlighted in the text.
- The first result is selected(focused).
- The list itself provides selection(focus) functionality same as previous/next buttons.
- Clicking on a result displays the page of the book with the match.
- The caret is positioned at the beginning of the match.
- The match is selected.
- Searching should be available in both Author and Reader.
Task requirements
- Provide the ability for the user to search the text content for currently opened book.
- Add a "Search" button next to the search box in the palette.
- Make the list to display all occurrences in text. Each list item should contain:
- the page number of the match
- a ":" sign
- three (or less, if less words are available or if they are longer than 50 chars) words before the match
- the match
- and three (or less, applying the same rule) words after the match.
- OPTIONAL: If occurrences are more than 100, only first 100 should be displayed.
Task result
- Source code
Implementation idea
- Use LogicR3Button for the button.
- Use the firstSelectedItem property in ListPalette.
- Extend ListPaletteItem and implement there the logic for displaying a given match.
- A hash-search algorithm can be used when searching larger fragments.
Related
- SEARCH_COMMONS_R0 - for highlighting
How to demo
- Insert a text frame and write something like "dfjkfds abc jfkdjfslk-abc-fdjfslkdfs" (at least two occurrencies of "abc")
- Open the search palette
- Search for "abc"
Design
- Create a module org.sophie2.main.func.search.
- Create class SearchModule that extends SophieModule.
- Add it in both FakeAuthorMain and FakeReaderMain.
- Move the search palette to org.sophie2.main.func.search.view package.
- Rename the SkinElementId to match the new module name.
- Add the palette as an extension.
- Add enum EventIds with the following items:
- SEARCH - Starts searching in selected scope (for now this is the current book).
- ITEM_SELECTED - Fired when a search item is selected (SearchItem.clicked()).
- Add new "Search" LogicR3Button to the JComponent in initHead().
- It should fire SEARCH event.
- Add "<<" and ">>" LogicR3Buttons below the text box and the search button.
- They should set firstSelected of the search palette to the previous/next match (if current is not first/last match in the list) and fire ITEM_SELECTED.
- In SearchPalette.SearchMatch.render construct a string using StringBuffer according to the analysis.
- Create a package org.sophie2.main.func.search.model
- Create a new abstract class SearchMatch
- Prop<ResourceRef> frame()
- This gives enough information about the match's page and book (using the parent relationship).
- In case of embedded books this points to the frame that contains the embedded book (not the actual frame in the embedded book).
- ListProp<ResourceRef> framePath()
- In case of embedded books, this holds references to all frames that need to be selected in order the search match to be viewed.
- All frames except the last have content of type embedded book.
- The frame property should return the first frame of the list.
- Auto property that returns the frame's page.
- Auto property that returns the frame's book.
- Prop<ResourceRef> frame()
- Create class HotTextSearchMatch that extends SearchMatch
- Two HotPos'es - for the beginning and for the end of the search match.
- Create a new abstract class SearchMatch
- Create enum org.sophie2.main.func.search.logic.SearchLogic
- Create the following static methods. All of them should have three arguments:
- The searched object (reference to book, a hot text, etc.)
- The string to search for.
- The list of all found SearchMatches. Every method should fill its results in that list.
- Create static method that searches a string in a book.
- It iterates over all pages. For each page it calls the next method.
- Create static method that searches a string in an Element (Page or Group).
- Searches in all non-grouped frames (which do not contain embedded books), ordered by their z-order descending.
- Then search recursively in all groups
- Finally search in all embedded books (again ordered by z-order; using the method for books).
- Create static method that searches a String in a HotText, starting from a given HotPos.
- The method should have a parameter that specifies the maximum count of results returned.
- Use Rabin-Karp string search algorithm.
- SEARCH:
- Using the event source, find current book and searched string.
- If the string is not empty, call the method that searches in a book. Give the list in the palette as an argument.
- If the string is empty, clear all previous search results.
- ITEM_SELECTED:
- Get the frame list of the match.
- Get the book to which the first frame belongs. Make this book current.
- Get the page of this frame. Make this page current.
- Select the frame.
- If the frame contains an embedded book, recursively select pages and frames.
- Move the caret to that position.
- Select the found text.
- Register the operations as extensions.
- Create the following static methods. All of them should have three arguments:
- Highlighting:
- Currently highlighting is not implemented in Sophie.
- Remove some obsolete classes:
- org.sophie2.main.app.model.book.BookSearcher
Implementation
- Design changes:
- No new module is created.
- SearchMatch now has method getElementView, getPageView and getContext.
- Actual searching is performed recursively in element views. Each view can define its own way of searching, for example, TextFrameView.
- Not implemented in this revision: highlighting, frame selection, sorting results in case of embedded books.
Merged into the trunk at [6606].
Testing
(Place the testing results here.)
Comments
(Write comments for this or later revisions here.)