commit 0e9b164405d0532184ef88037cf8322d1a843376 Author: Gary Cramblitt Date: Sun Jan 25 04:02:17 2004 +0000 More server nick info tracking. If you want to play with this, uncomment define USE_NICKINFO in server.h. svn path=/trunk/kdeextragear-2/konversation/; revision=282414 diff --git a/konversation/inputfilter.cpp b/konversation/inputfilter.cpp index 40ba570..3d06134 100644 --- a/konversation/inputfilter.cpp +++ b/konversation/inputfilter.cpp @@ -972,6 +972,11 @@ void InputFilter::parseServerCommand(const QString &prefix, const QString &comma } case RPL_AWAY: { +#ifdef USE_NICKINFO + NickInfo* nickInfo = server->obtainNickInfo(parameterList[1]); + nickInfo->setAway(true); + nickInfo->setAwayMessage(trailing); +#endif server->appendStatusMessage(i18n("Away"),i18n("%1 is away: %2").arg(parameterList[1]).arg(trailing)); break; } @@ -980,8 +985,23 @@ void InputFilter::parseServerCommand(const QString &prefix, const QString &comma server->appendStatusMessage(i18n("Invite"),i18n("You invited %1 into channel %2.").arg(parameterList[1]).arg(parameterList[2])); break; } +/* Sample WHOIS response +/WHOIS psn +[19:11] :zahn.freenode.net 311 PhantomsDad psn ~psn h106n2fls23o1068.bredband.comhem.se * :Peter Simonsson +[19:11] :zahn.freenode.net 319 PhantomsDad psn :#kde-devel #koffice +[19:11] :zahn.freenode.net 312 PhantomsDad psn irc.freenode.net :http://freenode.net/ +[19:11] :zahn.freenode.net 301 PhantomsDad psn :away +[19:11] :zahn.freenode.net 320 PhantomsDad psn :is an identified user +[19:11] :zahn.freenode.net 317 PhantomsDad psn 4921 1074973024 :seconds idle, signon time +[19:11] :zahn.freenode.net 318 PhantomsDad psn :End of /WHOIS list. +*/ case RPL_WHOISUSER: { +#ifdef USE_NICKINFO + NickInfo* nickInfo = server->obtainNickInfo(parameterList[1]); + nickInfo->setHostmask(i18n("%1@%2").arg(parameterList[2]).arg(parameterList[3])); + nickInfo->setRealName(trailing); +#endif server->appendStatusMessage(i18n("Whois"), i18n("%1 is %2@%3 (%4)").arg(parameterList[1]) // Use @ instead of @ .arg(parameterList[2]) // to avoid parsing as email @@ -1002,17 +1022,47 @@ void InputFilter::parseServerCommand(const QString &prefix, const QString &comma { QString lookChannel=channelList[index]; if(lookChannel.startsWith("*")) + { adminChannels.append(lookChannel.mid(1)); +#ifdef USE_NICKINFO + server->setChannelNick(lookChannel.mid(1), parameterList[1], 16); +#endif + } else if(lookChannel.startsWith("!")) + { ownerChannels.append(lookChannel.mid(1)); +#ifdef USE_NICKINFO + server->setChannelNick(lookChannel.mid(1), parameterList[1], 8); +#endif + } else if(lookChannel.startsWith("@")) + { opChannels.append(lookChannel.mid(1)); +#ifdef USE_NICKINFO + server->setChannelNick(lookChannel.mid(1), parameterList[1], 4); +#endif + } else if(lookChannel.startsWith("%")) + { halfopChannels.append(lookChannel.mid(1)); +#ifdef USE_NICKINFO + server->setChannelNick(lookChannel.mid(1), parameterList[1], 2); +#endif + } else if(lookChannel.startsWith("+")) + { voiceChannels.append(lookChannel.mid(1)); +#ifdef USE_NICKINFO + server->setChannelNick(lookChannel.mid(1), parameterList[1], 1); +#endif + } else + { userChannels.append(lookChannel); +#ifdef USE_NICKINFO + server->setChannelNick(lookChannel, parameterList[1], 0); +#endif + } } // endfor if(userChannels.count()) { @@ -1054,6 +1104,15 @@ void InputFilter::parseServerCommand(const QString &prefix, const QString &comma } case RPL_WHOISSERVER: { +#ifdef USE_NICKINFO + NickInfo* nickInfo = server->obtainNickInfo(parameterList[1]); + nickInfo->setNetServer(parameterList[2]); + nickInfo->setNetServerInfo(trailing); + // Clear the away state on assumption that if nick is away, this message will be followed + // by a 301 RPL_AWAY message. Not necessary a invalid assumption, but what can we do? + nickInfo->setAway(false); + nickInfo->setAwayMessage(QString::null); +#endif server->appendStatusMessage(i18n("Whois"), i18n("%1 is online via %2 (%3)").arg(parameterList[1]) .arg(parameterList[2]) @@ -1096,12 +1155,20 @@ void InputFilter::parseServerCommand(const QString &prefix, const QString &comma QDateTime when; when.setTime_t(parameterList[3].toUInt()); +#ifdef USE_NICKINFO + NickInfo* nickInfo = server->obtainNickInfo(parameterList[1]); + nickInfo->setOnlineSince(when); +#endif server->appendStatusMessage(i18n("Whois"),i18n("%1 is online since %2.").arg(parameterList[1]).arg(when.toString(Qt::LocalDate))); break; } } case RPL_ENDOFWHOIS: { +#ifdef USE_NICKINFO + NickInfo* nickInfo = server->getNickInfo(parameterList[1]); + if (nickInfo) server->nickInfoUpdated(nickInfo); +#endif server->appendStatusMessage(i18n("Whois"),i18n("End of WHOIS list.")); break; } @@ -1124,7 +1191,7 @@ void InputFilter::parseServerCommand(const QString &prefix, const QString &comma mask=mask.mid(1); if(ircOp) nick=nick.left(nick.length()-1); - // inform serer of this user's data + // inform server of this user's data emit userhost(nick,mask,away,ircOp); // display message only if this was no automatic request diff --git a/konversation/nickinfo.cpp b/konversation/nickinfo.cpp index 8ea7773..b068741 100644 --- a/konversation/nickinfo.cpp +++ b/konversation/nickinfo.cpp @@ -45,6 +45,10 @@ QString NickInfo::getAwayMessage() { return awayMessage; } QString NickInfo::getIdentdInfo() { return identdInfo; } QString NickInfo::getVersionInfo() { return versionInfo; } bool NickInfo::isNotified() { return notified; } +QString NickInfo::getRealName() { return realName; } +QString NickInfo::getNetServer() { return netServer; } +QString NickInfo::getNetServerInfo() { return netServerInfo; } +QDateTime NickInfo::getOnlineSince() { return onlineSince; } // Return the Server object that owns this NickInfo object. Server* NickInfo::getServer() { return owningServer; } @@ -52,13 +56,13 @@ Server* NickInfo::getServer() { return owningServer; } // Set properties of NickInfo object. // If any of these are called, call Server::nickInfoUpdated to let Server know about the change. void NickInfo::setNickname(const QString& newNickname) { nickname = newNickname; } -void NickInfo::setHostmask(const QString& newMask) -{ - if (!newMask.isEmpty()) hostmask = newMask; -} +void NickInfo::setHostmask(const QString& newMask) { if (!newMask.isEmpty()) hostmask = newMask; } void NickInfo::setAway(bool state) { away = state; } void NickInfo::setAwayMessage(const QString& newMessage) { awayMessage = newMessage; } void NickInfo::setIdentdInfo(const QString& newIdentdInfo) {identdInfo = newIdentdInfo; } void NickInfo::setVersionInfo(const QString& newVersionInfo) { versionInfo = newVersionInfo; } void NickInfo::setNotified(bool state) { notified = state; } - +void NickInfo::setRealName(const QString& newRealName) { if (!newRealName.isEmpty()) realName = newRealName; } +void NickInfo::setNetServer(const QString& newNetServer) { if (!newNetServer.isEmpty()) netServer = newNetServer; } +void NickInfo::setNetServerInfo(const QString& newNetServerInfo) { if (!newNetServerInfo.isEmpty()) netServerInfo = newNetServerInfo; } +void NickInfo::setOnlineSince(const QDateTime& datetime) { if (!datetime.isNull()) onlineSince = datetime; } diff --git a/konversation/nickinfo.h b/konversation/nickinfo.h index a7bf135..6e4a6dc 100644 --- a/konversation/nickinfo.h +++ b/konversation/nickinfo.h @@ -20,6 +20,7 @@ */ #include +#include class Server; @@ -44,6 +45,10 @@ class NickInfo QString getIdentdInfo(); QString getVersionInfo(); bool isNotified(); + QString getRealName(); + QString getNetServer(); + QString getNetServerInfo(); + QDateTime getOnlineSince(); // Return the Server object that owns this NickInfo object. Server* getServer(); @@ -57,6 +62,10 @@ class NickInfo void setIdentdInfo(const QString& newIdentdInfo); void setVersionInfo(const QString& newVersionInfo); void setNotified(bool state); + void setRealName(const QString& newRealName); + void setNetServer(const QString& newNetServer); + void setNetServerInfo(const QString& newNetServerInfo); + void setOnlineSince(const QDateTime& datetime); protected: QString nickname; @@ -67,6 +76,10 @@ class NickInfo QString identdInfo; QString versionInfo; bool notified; + QString realName; + QString netServer; + QString netServerInfo; + QDateTime onlineSince; }; #endif diff --git a/konversation/nicksonline.cpp b/konversation/nicksonline.cpp index d85eea8..52f1970 100644 --- a/konversation/nicksonline.cpp +++ b/konversation/nicksonline.cpp @@ -26,6 +26,10 @@ #include "server.h" #include "konversationapplication.h" +#ifdef USE_NICKINFO +#include "images.h" +#endif + NicksOnline::NicksOnline(QWidget* parent): ChatWindow(parent) { setName(i18n("Watched Nicks Online")); @@ -69,31 +73,49 @@ void NicksOnline::setOnlineList(const QString& serverName,const QStringList& lis nickListView->setColumnText(0, i18n("Server/Nickname/Channel")); } KListViewItem* newServerRoot=new KListViewItem(nickListView,serverName); + // Get a green LED for flagging of joined channels. + Images leds; + QIconSet currentLeds = leds.getGreenLed(false); + QPixmap joinedLed = currentLeds.pixmap(QIconSet::Automatic, QIconSet::Active, QIconSet::On); + // Get the server object corresponding to the server name. KonversationApplication *konvApp=static_cast(KApplication::kApplication()); Server* server = konvApp->getServerByName(serverName); + // List online nicknames. const NickInfoList* nickInfoList = server->getNicksOnline(); NickInfoListIterator itOnline(*nickInfoList); - // Online nicknames. NickInfo* nickInfo; for ( ; (nickInfo=itOnline.current()) ; ++itOnline) { QString lcNickName = itOnline.currentKey(); QString nickname = nickInfo->getNickname(); + // Construct additional information string for nick. QString nickAdditionalInfo; if (nickInfo->isAway()) { nickAdditionalInfo = nickAdditionalInfo + i18n("Away"); - QString awayMsg = nickInfo->getAwayMessage(); - if (!awayMsg.isEmpty()) nickAdditionalInfo = nickAdditionalInfo + "(" + awayMsg + ")"; + if (!nickInfo->getAwayMessage().isEmpty()) + nickAdditionalInfo = nickAdditionalInfo + "(" + nickInfo->getAwayMessage() + ")"; + } + if (!nickInfo->getHostmask().isEmpty()) + nickAdditionalInfo = nickAdditionalInfo + " " + nickInfo->getHostmask(); + if (!nickInfo->getRealName().isEmpty()) + nickAdditionalInfo = nickAdditionalInfo + " (" + nickInfo->getRealName() + ")"; + if (!nickInfo->getNetServer().isEmpty()) + { + nickAdditionalInfo = nickAdditionalInfo + " online via " + nickInfo->getNetServer(); + if (!nickInfo->getNetServerInfo().isEmpty()) + nickAdditionalInfo = nickAdditionalInfo + " (" + nickInfo->getNetServerInfo() + ")"; } - nickAdditionalInfo = nickAdditionalInfo + " "; - nickAdditionalInfo = nickAdditionalInfo + nickInfo->getHostmask(); + if (!nickInfo->getOnlineSince().isNull()) + nickAdditionalInfo = nickAdditionalInfo + " since " + nickInfo->getOnlineSince().toString(Qt::LocalDate); + KListViewItem* nickRoot = new KListViewItem(newServerRoot, nickname, nickAdditionalInfo); QStringList channelList = server->getNickChannels(nickname); for ( unsigned int index=0; indexgetChannelNick(channelList[index].lower(), lcNickName); + QString channelName = channelList[index]; + ChannelNick* channelNick = server->getChannelNick(channelName, lcNickName); unsigned int nickModeWord = channelNick->mode; QString nickMode; if (nickModeWord & 1) nickMode = nickMode + i18n(" Voice"); @@ -105,11 +127,15 @@ void NicksOnline::setOnlineList(const QString& serverName,const QStringList& lis if (nickModeWord & 1) nickMode = nickMode + i18n(" Owner"); nickModeWord >>= 1; if (nickModeWord & 1) nickMode = nickMode + i18n(" Admin"); - new KListViewItem(nickRoot, channelList[index], nickMode); + KListViewItem* channelItem = new KListViewItem(nickRoot, channelName, nickMode); + if (server->getJoinedChannelMembers(channelName) != 0) + { + channelItem->setPixmap(0, joinedLed); + } } nickRoot->setOpen(true); } - // Offline nicknames. + // List offline nicknames. KListViewItem* offlineRoot = new KListViewItem(newServerRoot, i18n("Offline")); nickInfoList = server->getNicksOffline(); NickInfoListIterator itOffline(*nickInfoList); @@ -120,6 +146,7 @@ void NicksOnline::setOnlineList(const QString& serverName,const QStringList& lis newServerRoot->setOpen(true); offlineRoot->setOpen(true); nickListView->adjustColumn(0); + nickListView->adjustColumn(1); } #else diff --git a/konversation/server.cpp b/konversation/server.cpp index 01a3a86..5ca81fe 100644 --- a/konversation/server.cpp +++ b/konversation/server.cpp @@ -881,21 +881,44 @@ NickInfo* Server::getNickInfo(const QString& nickname) return allNicks.find(lcNickname); } -// Returns the list of members for a channel in the joinedChannels list. 0 if channel is not in the joinedChannels list. +// Anyone who changes the contents of a NickInfo should call this method to let server +// know that it has changed. +void Server::nickInfoUpdated(const NickInfo* nickInfo) +{ + if (nickInfo) emit nickInfoChanged(this, nickInfo); +} + +// Given a nickname, returns an existing NickInfo object, or creates a new NickInfo object. +// Returns pointer to the found or created NickInfo object. +NickInfo* Server::obtainNickInfo(const QString& nickname) +{ + NickInfo* nickInfo = getNickInfo(nickname); + if (!nickInfo) + { + nickInfo = new NickInfo(nickname, this); + allNicks.insert(nickname.lower(), nickInfo); + } + return nickInfo; +} + +// Returns the list of members for a channel in the joinedChannels list. +// 0 if channel is not in the joinedChannels list. // Using code must not alter the list. const ChannelNickList* Server::getJoinedChannelMembers(const QString& channelName) const { return joinedChannels.find(channelName); } -// Returns the list of members for a channel in the unjoinedChannels list. 0 if channel is not in the unjoinedChannels list. +// Returns the list of members for a channel in the unjoinedChannels list. +// 0 if channel is not in the unjoinedChannels list. // Using code must not alter the list. const ChannelNickList* Server::getUnjoinedChannelMembers(const QString& channelName) const { return unjoinedChannels.find(channelName); } -// Searches the Joined and Unjoined lists for the given channel and returns the member list. 0 if channel is not in either list. +// Searches the Joined and Unjoined lists for the given channel and returns the member list. +// 0 if channel is not in either list. // Using code must not alter the list. const ChannelNickList* Server::getChannelMembers(const QString& channelName) const { @@ -921,6 +944,35 @@ ChannelNick* Server::getChannelNick(const QString& channelName, const QString& n } } +// Updates a nickname in a channel. If not on the joined or unjoined lists, and nick +// is in the watch list, adds the channel and nick to the unjoinedChannels list. +// If mode != 99, sets the mode for the nick in the channel. +// Returns the NickInfo object if nick is on any lists, otherwise 0. +NickInfo* Server::setChannelNick(const QString& channelName, const QString& nickname, unsigned int mode) +{ + QString lcNickname = nickname.lower(); + // If already on a list, update mode. + ChannelNick* channelNick = getChannelNick(channelName, lcNickname); + if (channelNick) + { + if (mode != 99) channelNick->mode = mode; + return channelNick->nickInfo; + } + else + { + // Get watch list from preferences. + QString watchlist=KonversationApplication::preferences.getNotifyString(); + // Create a lower case nick list from the watch list. + QStringList watchLowerList=QStringList::split(' ',watchlist.lower()); + // If on the watch list, add channel and nick to unjoinedChannels list. + if (watchLowerList.find(lcNickname) != watchLowerList.end()) + { + return addNickToUnjoinedChannelsList(channelName, nickname, mode); + } + else return 0; + } +} + // Returns a list of all the channels (joined or unjoined) that a nick is in. QStringList Server::getNickChannels(QString& nickname) { @@ -1597,7 +1649,7 @@ NickInfo* Server::addNickToUnjoinedChannelsList(const QString& channelName, cons } // Move the channel from joined list (if present) to unjoined list. QString lcChannelName = channelName.lower(); - ChannelNickList* members=joinedChannels.find(lcChannelName); + ChannelNickList* members = joinedChannels.find(lcChannelName); if (members) { joinedChannels.remove(lcChannelName); @@ -1606,18 +1658,18 @@ NickInfo* Server::addNickToUnjoinedChannelsList(const QString& channelName, cons else { // Create a new list in the unjoined channels if not already present. - members=unjoinedChannels.find(lcChannelName); + members = unjoinedChannels.find(lcChannelName); if (!members) { members = new ChannelNickList; unjoinedChannels.insert(lcChannelName, members); } } - // Add NickInfo to joinedChannels list if not already in the list. - ChannelNick* channelNick=members->find(lcNickname); + // Add NickInfo to unjoinedChannels list if not already in the list. + ChannelNick* channelNick = members->find(lcNickname); if (!channelNick) { - ChannelNick* channelNick = new ChannelNick; + channelNick = new ChannelNick; channelNick->nickInfo = nickInfo; channelNick->mode = 0; members->insert(lcNickname, channelNick); @@ -1636,7 +1688,8 @@ NickInfo* Server::addNickToUnjoinedChannelsList(const QString& channelName, cons NickInfo* Server::addNickToUnjoinedChannelsList(const QString&, const QString&, unsigned int) { return 0; } #endif -// Adds a nickname to the Online list, removing it from the Offline list, if present. Returns the NickInfo of the nickname. +// Adds a nickname to the Online list, removing it from the Offline list, if present. +// Returns the NickInfo of the nickname. // Creates new NickInfo if necessary. #ifdef USE_NICKINFO NickInfo* Server::addNickToOnlineList(const QString& nickname) @@ -1659,7 +1712,8 @@ NickInfo* Server::addNickToOnlineList(const QString& nickname) NickInfo* Server::addNickToOnlineList(const QString&) { return 0; } #endif -// Adds a nickname to the Offline list provided it is on the watch list, removing it from the Online list, if present. +// Adds a nickname to the Offline list provided it is on the watch list, +// removing it from the Online list, if present. // Also removes it from all channels on the joined and unjoined lists. // Returns the NickInfo of the nickname or 0 if deleted altogether. // Creates new NickInfo if necessary. @@ -1843,7 +1897,11 @@ void Server::addNickToChannel(const QString &channelName,const QString &nickname #ifdef USE_NICKINFO // Update NickInfo. - unsigned int mode = (admin << 4) | (owner << 3) | (op << 2) | (halfop << 1) | voice; + unsigned int mode = (admin ? 16 : 0)+ + (owner ? 8 : 0)+ + (op ? 4 : 0)+ + (halfop ? 2 : 0)+ + (voice ? 1 : 0); NickInfo* nickInfo = addNickToJoinedChannelsList(channelName, nickname, mode); nickInfo->setHostmask(hostmask); #endif diff --git a/konversation/server.h b/konversation/server.h index 59dcffb..c79374d 100644 --- a/konversation/server.h +++ b/konversation/server.h @@ -154,20 +154,34 @@ class Server : public QObject // Given a nickname, returns NickInfo object. 0 if not found. NickInfo* getNickInfo(const QString& nickname); - // Returns the list of members for a channel in the joinedChannels list. 0 if channel is not in the joinedChannels list. + // Given a nickname, returns an existing NickInfo object, or creates a new NickInfo object. + // Returns pointer to the found or created NickInfo object. + NickInfo* obtainNickInfo(const QString& nickname); + // Anyone who changes the contents of a NickInfo should call this method to let server + // know that it has changed. + void nickInfoUpdated(const NickInfo* nickInfo); + // Returns the list of members for a channel in the joinedChannels list. + // 0 if channel is not in the joinedChannels list. // Using code must not alter the list. const ChannelNickList* getJoinedChannelMembers(const QString& channelName) const; - // Returns the list of members for a channel in the unjoinedChannels list. 0 if channel is not in the unjoinedChannels list. + // Returns the list of members for a channel in the unjoinedChannels list. + // 0 if channel is not in the unjoinedChannels list. // Using code must not alter the list. const ChannelNickList* getUnjoinedChannelMembers(const QString& channelName) const; - // Searches the Joined and Unjoined lists for the given channel and returns the member list. 0 if channel is not in either list. + // Searches the Joined and Unjoined lists for the given channel and returns the member list. + // 0 if channel is not in either list. // Using code must not alter the list. const ChannelNickList* getChannelMembers(const QString& channelName) const; // Returns a list of all the channels (joined or unjoined) that a nick is in. QStringList getNickChannels(QString& nickname); // Returns pointer to the ChannelNick (mode and pointer to NickInfo) for a given channel and nickname. - // 0 if not found. + // 0 if not found. ChannelNick* getChannelNick(const QString& channelName, const QString& nickname); + // Updates a nickname in a channel. If not on the joined or unjoined lists, and nick + // is in the watch list, adds the channel and nick to the unjoinedChannels list. + // If mode != 99, sets the mode for the nick in the channel. + // Returns the NickInfo object if nick is on any lists, otherwise 0. + NickInfo* setChannelNick(const QString& channelName, const QString& nickname, unsigned int mode = 99); // Returns a list of the nicks on the watch list that are online. const NickInfoList* getNicksOnline(); // Returns a list of the nicks on the watch list that are offline. @@ -186,6 +200,22 @@ class Server : public QObject void awayState(bool away); // will be connected to any user input panel; void multiServerCommand(const QString& command, const QString& parameter); void serverOnline(bool state); // will be connected to all server dependant tabs + // Note that these signals haven't been implemented yet. + // Fires when the information in a NickInfo object changes. + void nickInfoChanged(Server* server, const NickInfo* nickInfo); + // Fires when the mode of a nick in a channel changes. + void channelNickChanged(Server* server, const ChannelNick* channelNick); + // Fires when a nick leaves or joins a channel. Based on joined flag, receiver could + // call getJoinedChannelMembers or getUnjoinedChannelMembers, or just + // getChannelMembers to get a list of all the nicks now in the channel. + // parted indicates whether the nick joined or left the channel. + void channelMembersChanged(Server* server, const QString& channelName, bool joined, bool parted, const QString& nickname); + // Fires when a channel is moved to/from the Joinied/Unjoined lists. + // joined indicates which list it is now on. Note that if joined is False, it is + // possible the channel does not exist in any list anymore. + void channelJoinedOrUnjoined(Server* server, const QString& channelName, bool joined); + // Fires when a nick on the watch list goes online or offline. + void watchedNickChanged(Server* server, const NickInfo* nickInfo, bool online); public slots: void connectToIRCServer(); @@ -276,10 +306,12 @@ class Server : public QObject // If mode != 99 sets the mode for this nick in this channel. // Returns the NickInfo for the nickname. NickInfo* addNickToUnjoinedChannelsList(const QString& channelName, const QString& nickname, unsigned int mode = 99); - // Adds a nickname to the Online list, removing it from the Offline list, if present. Returns the NickInfo of the nickname. + // Adds a nickname to the Online list, removing it from the Offline list, if present. + // Returns the NickInfo of the nickname. // Creates new NickInfo if necessary. NickInfo* addNickToOnlineList(const QString& nickname); - // Adds a nickname to the Offline list provided it is on the watch list, removing it from the Online list, if present. + // Adds a nickname to the Offline list provided it is on the watch list, + // removing it from the Online list, if present. // Returns the NickInfo of the nickname or 0 if deleted altogether. // Creates new NickInfo if necessary. NickInfo* addNickToOfflineList(const QString& nickname, const QStringList& watchList);