void SumatraUIAutomationTextRange::SetToDocumentRange() { startPage = 1; startGlyph = 0; endPage = document->GetDM()->PageCount(); endGlyph = GetPageGlyphCount(endPage); }
SumatraUIAutomationTextRange::SumatraUIAutomationTextRange(SumatraUIAutomationDocumentProvider* document, int pageNum) : refCount(1), document(document) { document->AddRef(); startPage = pageNum; startGlyph = 0; endPage = pageNum; endGlyph = GetPageGlyphCount(pageNum); }
HRESULT STDMETHODCALLTYPE SumatraUIAutomationTextRange::ExpandToEnclosingUnit(enum TextUnit textUnit) { //if document is closed, don't do anything if (!document->IsDocumentLoaded()) return E_FAIL; //if not set, don't do anything if (IsNullRange()) return S_OK; if (textUnit == TextUnit_Character) { //done return S_OK; } else if (textUnit == TextUnit_Format) { // what is a "format" anyway? return S_OK; } else if (textUnit == TextUnit_Word) { // select current word at start endpoint int word_beg = FindPreviousWordEndpoint(startPage, startGlyph); int word_end = FindNextWordEndpoint(startPage, startGlyph); endPage = startPage; startGlyph = word_beg; endGlyph = word_end; return S_OK; } else if (textUnit == TextUnit_Line || textUnit == TextUnit_Paragraph) { // select current line or current paragraph. In general case these cannot be differentiated? Right? int word_beg = FindPreviousLineEndpoint(startPage, startGlyph); int word_end = FindNextLineEndpoint(startPage, startGlyph); endPage = startPage; startGlyph = word_beg; endGlyph = word_end; return S_OK; } else if (textUnit == TextUnit_Page) { // select current page // start from the beginning of start page startGlyph = 0; // to the end of the end page endGlyph = GetPageGlyphCount(endPage); return S_OK; } else if (textUnit == TextUnit_Document) { SetToDocumentRange(); return S_OK; } else { return E_INVALIDARG; } }
HRESULT STDMETHODCALLTYPE SumatraUIAutomationTextRange::MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, int count, int *moved) { if (moved == NULL) return E_POINTER; // if document is closed, don't do anything if (!document->IsDocumentLoaded()) return E_FAIL; // if not set, don't do anything if (IsNullRange()) return S_OK; // what to move int *target_page, *target_glyph; if (endpoint == TextPatternRangeEndpoint_Start) { target_page = &startPage; target_glyph = &startGlyph; } else if (endpoint == TextPatternRangeEndpoint_End) { target_page = &endPage; target_glyph = &endGlyph; } else { return E_INVALIDARG; } class EndPointMover { protected: SumatraUIAutomationTextRange* target; int* target_page; int* target_glyph; public: // return false when cannot be moved virtual bool NextEndpoint() const { // HACK: Declaring these as pure virtual causes "unreferenced local variable" warnings ==> define a dummy body to get rid of warnings CrashIf(true); return false; } virtual bool PrevEndpoint() const { CrashIf(true); return false; } // return false when not appliable bool NextPage() const { int max_glyph = target->GetPageGlyphCount(*target_page); if (*target_glyph == max_glyph) { if (*target_page == target->GetPageCount()) { // last page return false; } // go to next page (*target_page)++; (*target_glyph) = 0; } return true; } bool PreviousPage() const { if (*target_glyph == 0) { if (*target_page == 1) { // first page return false; } // go to next page (*target_page)--; (*target_glyph) = target->GetPageGlyphCount(*target_page); } return true; } // do the moving int Move(int count, SumatraUIAutomationTextRange* target, int* target_page, int* target_glyph) { this->target = target; this->target_page = target_page; this->target_glyph = target_glyph; int retVal = 0; if (count > 0) { for (int i=0;i<count && (NextPage() || NextEndpoint());++i) ++retVal; } else { for (int i=0;i<-count && (PreviousPage() || PrevEndpoint());++i) ++retVal; } return retVal; } }; class CharEndPointMover : public EndPointMover { bool NextEndpoint() const { (*target_glyph)++; return true; } bool PrevEndpoint() const { (*target_glyph)--; return true; } }; class WordEndPointMover : public EndPointMover { bool NextEndpoint() const { (*target_glyph) = target->FindNextWordEndpoint(*target_page, *target_glyph, true); return true; } bool PrevEndpoint() const { (*target_glyph) = target->FindPreviousWordEndpoint(*target_page, *target_glyph, true); (*target_glyph)--; return true; } }; class LineEndPointMover : public EndPointMover { bool NextEndpoint() const { (*target_glyph) = target->FindNextLineEndpoint(*target_page, *target_glyph, true); return true; } bool PrevEndpoint() const { (*target_glyph) = target->FindPreviousLineEndpoint(*target_page, *target_glyph, true); (*target_glyph)--; return true; } }; // how much to move if (unit == TextUnit_Character) { CharEndPointMover mover; *moved = mover.Move(count, this, target_page, target_glyph); } else if (unit == TextUnit_Word || unit == TextUnit_Format) { WordEndPointMover mover; *moved = mover.Move(count, this, target_page, target_glyph); } else if (unit == TextUnit_Line || unit == TextUnit_Paragraph) { LineEndPointMover mover; *moved = mover.Move(count, this, target_page, target_glyph); } else if (unit == TextUnit_Page) { *moved = 0; *target_glyph = 0; if (count > 0) { // GetPageCount()+1 => allow overflow momentarily for (int i=0;i<count && *target_page!=GetPageCount()+1;++i) { (*target_page)++; (*moved)++; } // fix overflow, allow seeking to the end this way if (*target_page == GetPageCount()+1) { *target_page = GetPageCount(); *target_glyph = GetPageGlyphCount(*target_page); } } else { for (int i=0;i<-count && *target_page!=1;++i) { (*target_page)--; (*moved)++; } } } else if (unit == TextUnit_Document) { if (count > 0) { int end_page = GetPageCount(); int end_glyph = GetPageGlyphCount(*target_page); if (*target_page != end_page || *target_glyph != end_glyph) { *target_page = end_page; *target_glyph = end_glyph; *moved = 1; } else { *moved = 0; } } else { const int beg_page = 0; const int beg_glyph = 0; if (*target_page != beg_page || *target_glyph != beg_glyph) { *target_page = beg_page; *target_glyph = beg_glyph; *moved = 1; } else { *moved = 0; } } } else { return E_INVALIDARG; } // keep range valid if (endpoint == TextPatternRangeEndpoint_Start) { // drag end with start ValidateEndEndpoint(); } else if (endpoint == TextPatternRangeEndpoint_End) { // drag start with end ValidateStartEndpoint(); } return S_OK; }