Exemplo n.º 1
0
/*
 *	CRchTxtPtr::ChangeCase(cch, Type, publdr)
 *	
 *	@mfunc
 *		Change case of cch chars starting at this text ptr according to Type,
 *		which has the possible values:
 *
 *		tomSentenceCase	= 0: capitalize first letter of each sentence
 *		tomLowerCase	= 1: change all letters to lower case
 *		tomUpperCase	= 2: change all letters to upper case
 *		tomTitleCase	= 3: capitalize the first letter of each word
 *		tomToggleCase	= 4: toggle the case of each letter
 *	
 *	@rdesc
 *		TRUE iff a change occurred
 *
 *	@devnote
 *		Since this routine only changes the case of characters, it has no
 *		effect on rich-text formatting.  However it is part of the CRchTxtPtr
 *		class in order to notify the display of changes.  CTxtRanges are also
 *		notified just in case the text blocks are modified.
 */
BOOL CRchTxtPtr::ChangeCase (
	LONG		  cch,			//@parm # chars to change case for
	LONG		  Type,			//@parm Type of change case command
	IUndoBuilder *publdr)		//@parm UndoBuilder to receive anti-event
								//  	for any replacements
{
	TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::ChangeCase");
	_TEST_INVARIANT_

#define	BUFFERLEN	256

	LONG	cchChunk, cchFirst, cchGet, cchLast;
	BOOL	fAlpha, fToUpper, fUpper;			// Flags controling case change
	BOOL	fChange = FALSE;					// No change yet
	BOOL	fStart = TRUE;						// Start of Word/Sentence
	TCHAR *	pch;								// Ptr to walk rgCh with
	WORD *	pType;								// Ptr to walk rgType with
	TCHAR	rgCh[BUFFERLEN];					// Char buffer to work in
	WORD	rgType[BUFFERLEN];					// C1_TYPE array for rgCh

	if( GetCp() )
	{
		if( Type == tomSentenceCase )
		{
			fStart = _rpTX.IsAtBOSentence();
		}
		else if( Type == tomTitleCase )
		{
			// check to see if we are at the beginning of
			// a word.  This is the case if the character preceeding
			// our current position is white space.
			fStart = IsWhiteSpace(_rpTX.PrevChar());
			_rpTX.AdvanceCp(1);
		}
	}
	while(cch > 0)								// Do 'em all (or as many as
	{											//  in story)
		cchChunk = min(BUFFERLEN, cch);			// Get next bufferful
		cch -= cchChunk;						// Decrement the count
		cchGet = _rpTX.GetText(cchChunk, rgCh);	// Manipulate chars in buffer
		if(cchGet < cchChunk)					//  (for undo, need to use
		{										//  ReplaceRange())
			cch = 0;							// No more chars in story,
			if(!cchGet)							//  so we'll be done
				break;							// We're done already
			cchChunk = cchGet;					// Something in this chunk
		}

		GetStringTypeEx(0, CT_CTYPE1, rgCh,		// Find out whether chars are
						cchChunk, rgType);		//  UC, LC, or neither
		
		cchLast = 0;							// Default nothing to replace
		cchFirst = -1;
		for(pch = rgCh, pType = rgType;			// Process buffered chars
			cchChunk;
			cchChunk--, pch++, pType++)
		{
			fAlpha = *pType & (C1_UPPER | C1_LOWER); // Nonzero if UC or LC
			fUpper = (*pType & C1_UPPER) != 0;	// TRUE if UC
			fToUpper = fStart ? TRUE : fUpper;	// capitalize first letter of a
												// sentence
			switch(Type)
			{									// Decide whether to change
			case tomLowerCase:					//  case and determine start
				fToUpper = FALSE;				//  of word/sentence for title
				break;							//  and sentence cases

			case tomUpperCase:
				fToUpper = TRUE;
				break;

			case tomToggleCase:
				fToUpper = !fUpper;
				break;

			case tomSentenceCase:
				if(*pch == TEXT('.'))			// If sentence terminator,
					fStart = TRUE;				//  capitalize next alpha
				if(fAlpha)						// If this char is alpha, next
					fStart = FALSE;				//  char can't start a
				break;							//  sentence

			case tomTitleCase:					// If this char is alpha, next
				fStart = (fAlpha == 0);			//  char can't start a word
				break;
			default:
				return FALSE;
			}

			if(fAlpha && (fToUpper ^ fUpper))	// Only change case if it
			{									//  makes a difference (saves
				if(fToUpper)					//  on system calls and undos)
					CharUpperBuff(pch, 1);
				else
					CharLowerBuff(pch, 1);

				fChange = TRUE;					// Return value: change made
				if( cchFirst == -1 )			// Save cch of unchanged
					cchFirst = cchGet-cchChunk;	//  leading string
				cchLast = cchChunk - 1;			// Save cch of unchanged
			}									//  trailing string
		}
		if( cchFirst == -1 )
		{
			Assert(cchLast == 0);
			cchFirst = cchGet;
		}

		Advance(cchFirst);						// Skip unchanged leading
		cchGet -= cchFirst + cchLast;			//  string. cchGet = cch of
		ReplaceRange(cchGet, cchGet, rgCh		//  changed span
			+ cchFirst, publdr, tomUndefined);
		Advance(cchLast);						// Skip unchanged trailing 
	}											//  string
	return fChange;
}
Exemplo n.º 2
0
void CCharBufferText::OnChange (unsigned int start, unsigned int old_count, unsigned int new_count)
{
    unsigned int c_start_line = GetLine (start);
    ASSERT (c_start_line < lines_count);
    unsigned int c_start_position = min (start - line_start [c_start_line], line_length [c_start_line]);

    unsigned int c_old_end_line = GetLine (start + old_count);
    ASSERT (c_old_end_line < lines_count);
    unsigned int c_old_end_position = min (start + old_count - line_start [c_old_end_line], line_length [c_old_end_line]);

    int delta = new_count - old_count;

    unsigned int before = GetLastLineEndingBefore (start);

    if (before > 0 && before < lines_count && line_length [before] == 0) before -= 1;

    unsigned int start_line = before >= lines_count ? 0 : before + 1;
    unsigned int start_pos = before >= lines_count ? 0 : line_start [before] + line_length [before];
    unsigned int after = GetFirstLineStartingAfter (start + old_count);

    if (after < lines_count && line_length [after] == 0) after += 1;

    unsigned int end_line = after >= lines_count ? lines_count : after;
    unsigned int end_pos = after >= lines_count ? data.GetSize () : line_start [after] + delta;
    unsigned int count = end_pos - start_pos;

    vector <unsigned int> starts;
    vector <unsigned int> lengths;

    SplitIntoLines (start_pos, count, starts, lengths);

    int c = starts.size ();
    ASSERT (c > 0);

    if (c == 1 && before < lines_count && after < lines_count) // Join three lines
    {
        line_length [before] += lengths [0] + line_length [after];
        line_length.erase (line_length.begin () + before + 1, line_length.begin () + after + 1);
        line_start.erase (line_start.begin () + before + 1, line_start.begin () + after + 1);

        if (delta != 0)
        {
            unsigned int size = line_length.size ();
            for (unsigned int i = before + 1; i < size; i++)
                line_start [i] += delta;
        }
    }
    else
    {
        unsigned int b = 0;
        unsigned int e = c;

        if (before < lines_count) // Append line
        {
            line_length [before] += lengths [0];
            b = 1;
        }

        if (after < lines_count) // Prepend line
        {
            line_start [after] -= lengths [c - 1];
            line_length [after] += lengths [c - 1];
            e = c - 1;
        }

        if (end_line < start_line) end_line = start_line;

        ReplaceRange (line_length, start_line, end_line - start_line, lengths, b, e - b);
        ReplaceRange (line_start, start_line, end_line - start_line, starts, b, e - b);

        if (delta != 0)
        {
            unsigned int size = line_length.size ();
            for (unsigned int i = (before < lines_count ? before + 1 : 0) + e - b; i < size; i++)
                line_start [i] += delta;
        }
    }

    lines_count = line_length.size ();

    unsigned int c_new_end_line = GetLine (start + new_count);
    ASSERT (c_new_end_line < lines_count);
    unsigned int c_new_end_position = min (start + new_count - line_start [c_new_end_line], line_length [c_new_end_line]);

    FireOnChange (c_start_line, c_start_position, c_old_end_line, c_old_end_position, c_new_end_line, c_new_end_position);
}