urlsup.cpp
来自「Windows CE 6.0 Word Application 源码」· C++ 代码 · 共 865 行 · 第 1/2 页
CPP
865 行
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
* @doc INTERNAL
*
* @module URLSUP.CPP URL detection support |
*
* Author: alexgo 4/3/96
*/
#include "_common.h"
#include "_edit.h"
#include "_urlsup.h"
#include "_m_undo.h"
#include "_select.h"
#include "_clasfyc.h"
ASSERTDATA
// arrays for URL detection. The first array is the protocols
// we support, followed by the "size" of the array.
// NB!! Do _not_ modify these arrays without first making sure
// that the code in ::IsURL is updated appropriately.
const LPCWSTR rgszURL[] = {
L"http:",
L"file:",
L"mailto:",
L"ftp:",
L"https:",
L"gopher:",
L"nntp:",
L"prospero:",
L"telnet:",
L"news:",
L"wais:",
L"outlook:",
};
const LONG rgcchURL[] = {
5,
5,
7,
4,
6,
7,
5,
9,
7,
5,
5,
8
};
const LPCWSTR rgszWWWURL[] = {
L"www."
};
const LONG rgcchWWWURL[] = {
4
};
#define MAXURLHDRSIZE 9
// return TRUE is white space or FE chars
inline BOOL IsURLWhiteSpace(WCHAR ch)
{
return ( IsWhiteSpace(ch) || ch >= 0x03000 );
}
/*
* CDetectURL::CDetectURL
*
* @mfunc constructor; registers this class in the notification manager.
*
* @rdesc void
*/
CDetectURL::CDetectURL(
CTxtEdit *ped) //@parm the edit context to use
{
CNotifyMgr *pnm = ped->GetNotifyMgr();
if( pnm )
{
pnm->Add((ITxNotify *)this);
}
_ped = ped;
}
/*
* CDetectURL::~CDetectURL
*
* @mfunc destructor; removes ths class from the notification manager
*
* @rdesc void
*/
CDetectURL::~CDetectURL()
{
CNotifyMgr *pnm = _ped->GetNotifyMgr();
if( pnm )
{
pnm->Remove((ITxNotify *)this);
}
}
//
// ITxNotify methods
//
/*
* CDetectURL::OnPreRelaceRange
*
* @mfunc called before a change is made
*
* @rdesc void
*/
void CDetectURL::OnPreReplaceRange(
DWORD cp, //@parm start of changes
DWORD cchDel, //@parm #of chars deleted
DWORD cchNew, //@parm #of chars added
DWORD cpFormatMin, //@parm min cp of formatting change
DWORD cpFormatMax) //@parm max cp of formatting change
{
; // don't need to do anything here
}
/*
* CDetectURL::OnPostReplaceRange
*
* @mfunc called after a change has been made to the backing store. We
* simply need to accumulate all such changes
*
* @rdesc void
*
*/
void CDetectURL::OnPostReplaceRange(
DWORD cp, //@parm start of changes
DWORD cchDel, //@parm #of chars deleted
DWORD cchNew, //@parm #of chars added
DWORD cpFormatMin, //@parm min cp of formatting change
DWORD cpFormatMax) //@parm max cp of formatting change
{
// we don't need to worry about format changes; just data changes
// to the backing store
if( cp != INFINITE )
{
Assert(cp != CONVERT_TO_PLAIN);
_adc.UpdateRecalcRegion(cp, cchDel, cchNew);
}
}
/*
* CDetectURL::Zombie ()
*
* @mfunc
* Turn this object into a zombie
*/
void CDetectURL::Zombie ()
{
}
/*
* CDetectURL::ScanAndUpdate
*
* @mfunc scans the affect text, detecting new URL's and removing old ones.
*
* @rdesc void
*
* @comm The algorithm we use is straightforward: <nl>
*
* 1. find the update region and expand out to whitespace in either
* direction. <nl>
*
* 2. Scan through region word by word (where word is contiguous
* non-whitespace).
*
* 3. Strip these words off punctuation marks. This may be a bit
* tricky as some of the punctuation may be part of the URL itself.
* We assume that generally it's not, and if it is, one has to enclose
* the URL in quotes, brackets or such. We stop stripping the
* punctuation off the end as soon as we fing the matching bracket.
*
* 4. If it's a URL, enable the effects, if it's
* incorrectly labelled as a URL, disabled the effects.
*
* Note that this algorithm will only remove
*/
void CDetectURL::ScanAndUpdate(
IUndoBuilder *publdr) //@parm the undo context to use
{
LONG cpStart, cpEnd, cp;
CTxtRange rg(*(CTxtRange *)_ped->GetSel());
const CCharFormat *pcfDefault = _ped->GetCharFormat(-1);
COLORREF crDefault = 0;
URLFLAGS fUseUnderline = URL_NOUNDERLINE;
BOOL fCleanedThisURL;
BOOL fCleanedSomeURL = FALSE;
// clear away some unecessary features of the range that will
// just slow us down.
rg.SetIgnoreFormatUpdate(TRUE);
rg._rpPF.SetToNull();
if( !GetScanRegion(cpStart, cpEnd) )
{
return;
}
if( pcfDefault )
{
crDefault = pcfDefault->crTextColor;
fUseUnderline = (pcfDefault->dwEffects & CFE_UNDERLINE) ?
URL_USEUNDERLINE : URL_NOUNDERLINE;
}
rg.Set(cpStart, 0);
while( (cp = rg.GetCp()) < cpEnd )
{
Assert(rg.GetCch() == 0 );
LONG cchAdvance;
ExpandToURL(rg, cchAdvance);
if( rg.GetCch() == 0 )
{
break;
}
if( IsURL(rg) )
{
SetURLEffects(rg, publdr);
LONG cpNew = rg.GetCp() - rg.GetCch();
// anything before the detected URL did not really belong to it
if (rg.GetCp() > cp)
{
rg.Set(cp, cp - rg.GetCp());
CheckAndCleanBogusURL(rg, crDefault, fUseUnderline,
fCleanedThisURL, publdr);
fCleanedSomeURL |= fCleanedThisURL;
}
// collapse to the end of the URL range so that ExpandToURL will
// find the next candidate.
rg.Set(cpNew, 0);
// skip to the end of word; this can't be another URL!
cp = cpNew;
cchAdvance = -MoveByDelimiters(rg._rpTX, 1, URL_STOPATWHITESPACE, 0);
}
if (cchAdvance)
{
rg.Set(cp, cchAdvance);
CheckAndCleanBogusURL(rg, crDefault, fUseUnderline,
fCleanedThisURL, publdr);
fCleanedSomeURL |= fCleanedThisURL;
// collapse to the end of scanned range so that ExpandToURL will
// find the next candidate.
rg.Set(cp - cchAdvance, 0);
}
}
// if we cleaned some URL, we might need to reset the default format
if (fCleanedSomeURL && !_ped->GetSel()->GetCch())
_ped->GetSel()->Update_iFormat(-1);
return;
}
//
// PRIVATE methods
//
/*
* CDetectURL::GetScanRegion
*
* @mfunc Gets the region of text to scan for new URLs by expanding the
* changed region to be bounded by whitespace
*
* @rdesc void
*/
BOOL CDetectURL::GetScanRegion(
LONG& rcpStart, //@parm where to put the start of the range
LONG& rcpEnd //@parm where to the the end of the range
)
{
DWORD cp, cch, adjlength;
CRchTxtPtr rtp(_ped, 0);
WCHAR chBracket;
LONG cchExpand;
_adc.GetUpdateRegion(&cp, NULL, &cch, NULL, NULL);
if( cp == INFINITE )
{
return FALSE;
}
// first, find the start of the region
rtp.SetCp(cp);
rcpStart = cp;
rcpEnd = cp + cch;
// now let's see if we need to expand to the nearest quotation mark
// we do if we have quotes in our region or we have the LINK bit set
// on either side of the region that we might need or not need to clear
BOOL fExpandToBrackets = (rcpEnd - rcpStart ?
GetAngleBracket(rtp._rpTX, rcpEnd - rcpStart) : 0);
BOOL fKeepGoing = TRUE;
while(fKeepGoing)
{
fKeepGoing = FALSE;
// expand left to the entire word
rtp.SetCp(rcpStart);
rcpStart += MoveByDelimiters(rtp._rpTX, -1, URL_STOPATWHITESPACE, 0);
// now the other end
rtp.SetCp(rcpEnd);
rcpEnd += MoveByDelimiters(rtp._rpTX, 1, URL_STOPATWHITESPACE, 0);
// if we have LINK formatting around, we'll need to expand to nearest quotes
rtp.SetCp(rcpStart);
rtp._rpCF.AdjustBackward();
fExpandToBrackets = fExpandToBrackets ||
(_ped->GetCharFormat(rtp._rpCF.GetFormat())->dwEffects & CFE_LINK);
rtp.SetCp(rcpEnd);
rtp._rpCF.AdjustForward();
fExpandToBrackets = fExpandToBrackets ||
(_ped->GetCharFormat(rtp._rpCF.GetFormat())->dwEffects & CFE_LINK);
if (fExpandToBrackets)
// we have to expand to nearest angle brackets in both directions
{
rtp.SetCp(rcpStart);
chBracket = LEFTANGLEBRACKET;
cchExpand = MoveByDelimiters(rtp._rpTX, -1, URL_STOPATCHAR, &chBracket);
// did we really hit a bracket?
if (chBracket == LEFTANGLEBRACKET)
{
rcpStart += cchExpand;
fKeepGoing = TRUE;
}
// same thing, different direction
rtp.SetCp(rcpEnd);
chBracket = RIGHTANGLEBRACKET;
cchExpand = MoveByDelimiters(rtp._rpTX, 1, URL_STOPATCHAR, &chBracket);
if (chBracket == RIGHTANGLEBRACKET)
{
rcpEnd += cchExpand;
fKeepGoing = TRUE;
}
fExpandToBrackets = FALSE;
}
}
if( rcpEnd > (LONG)(adjlength = _ped->GetAdjustedTextLength()) )
{
rcpEnd = adjlength;
}
return TRUE;
}
/*
* CDetectURL::ExpandToURL
*
* @mfunc skips white space and sets the range to the very next
* block of non-white space text. Strips this block off
* punctuation marks
*
* @rdesc void
*/
void CDetectURL::ExpandToURL(
CTxtRange& rg, //@parm the range to move
LONG &cchAdvance//@parm how much to advance to the next URL from the current cp
)
{
DWORD cp;
LONG cch;
Assert(rg.GetCch() == 0 );
cp = rg.GetCp();
// skip white space first, record the advance
cp -= (cchAdvance = -MoveByDelimiters(rg._rpTX, 1,
URL_EATWHITESPACE|URL_STOPATNONWHITESPACE, 0));
rg.Set(cp, 0);
// strip off punctuation marks
WCHAR chStopChar = URL_INVALID_DELIMITER;
// skip all punctuation from the beginning of the word
LONG cchHead = MoveByDelimiters(rg._rpTX, 1,
URL_STOPATWHITESPACE|URL_STOPATNONPUNCT,
&chStopChar);
// now skip up to white space (i.e. expand to the end of the word).
cch = MoveByDelimiters(rg._rpTX, 1,
URL_STOPATWHITESPACE|URL_EATNONWHITESPACE, 0);
// this is how much we want to advance to start loking for the next URL
// if this does not turn out to be one: one word
// We increment/decrement the advance so we can accumulate changes in there
cchAdvance -= cch;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?