1 #ifndef _KVI_WINDOW_H_
2 #define _KVI_WINDOW_H_
3 //=============================================================================
4 //
5 //   File : KviWindow.h
6 //   Creation date : Tue Jul 6 1999 14:52:20 by Szymon Stefanek
7 //
8 //   This file is part of the KVIrc IRC client distribution
9 //   Copyright (C) 1999-2010 Szymon Stefanek (pragma at kvirc dot net)
10 //
11 //   This program is FREE software. You can redistribute it and/or
12 //   modify it under the terms of the GNU General Public License
13 //   as published by the Free Software Foundation; either version 2
14 //   of the License, or (at your option) any later version.
15 //
16 //   This program is distributed in the HOPE that it will be USEFUL,
17 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
18 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 //   See the GNU General Public License for more details.
20 //
21 //   You should have received a copy of the GNU General Public License
22 //   along with this program. If not, write to the Free Software Foundation,
23 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 //
25 //=============================================================================
26 
27 /**
28 * \file KviWindow.h
29 * \brief Contains the KviWindow class
30 */
31 
32 #include "kvi_settings.h"
33 #include "KviApplication.h"
34 #include "KviCString.h"
35 #include "KviQString.h"
36 #include "KviIrcContext.h"
37 #include "KviIrcConnection.h"
38 #include "KviInput.h"
39 #include "KviTalHBox.h"
40 #include "KviTalSplitter.h"
41 #include "KviIconManager.h"
42 
43 #include <QFrame>
44 #include <QWidget>
45 #include <QToolButton>
46 #include <QTextEncoder>
47 #include <QByteArray>
48 #include <QDateTime>
49 
50 class QPushButton;
51 class QPixmap;
52 class QTextCodec;
53 class KviMainWindow;
54 class KviWindowListItem;
55 class KviConfigurationFile;
56 class KviIrcView;
57 class KviConsoleWindow;
58 class KviIrcConnection;
59 class KviWindowToolPageButton;
60 class QMenu;
61 class KviTalHBox;
62 
63 #ifdef COMPILE_CRYPT_SUPPORT
64 class KviCryptController;
65 class KviCryptSessionInfo;
66 #endif
67 
68 #define KVI_WINDOW_TYPE_USER 10000
69 
70 /**
71 * \class KviWindow
72 * \brief Base class for all windows in KVIrc
73 */
74 class KVIRC_API KviWindow : public QWidget
75 {
76 	friend class KviInput;
77 	friend class KviMainWindow;
78 	friend class KviWindowStack;
79 	friend class KviWindowListItem;
80 	friend class KviWindowListButton;
81 	friend class KviTreeWindowListItem;
82 	friend class KviTreeWindowList;
83 	friend class KviTreeWindowListItemDelegate;
84 	Q_PROPERTY(int KviProperty_ChildFocusOwner READ type)
85 	Q_OBJECT
86 public:
87 	/**
88 	* \enum ActivityValue
89 	* \brief Holds the activity meter in value scale
90 	*/
91 	enum ActivityValue
92 	{
93 		None = 0,    /**< None */
94 		VeryLow = 1, /**< Very low */
95 		Low = 2,     /**< Low */
96 		Medium = 3,  /**< Medium */
97 		High = 4,    /**< High */
98 		VeryHigh = 5 /**< Very high */
99 	};
100 
101 	/**
102 	* \enum ActivityTemperature
103 	* \brief Holds the activity meter in temperature scale
104 	*/
105 	enum ActivityTemperature
106 	{
107 		Ice = 0,       /**< Ice */
108 		VeryCold = 1,  /**< Very cold */
109 		Cold = 2,      /**< Cold */
110 		Undefined = 3, /**< Undefined */
111 		Hot = 4,       /**< Hot */
112 		VeryHot = 5,   /**< Very hot */
113 		Fire = 6       /**< Fire */
114 	};
115 
116 	/**
117 	* \enum AttentionLevel
118 	* \brief attention levels usable in hasAttention()
119 	*/
120 	enum AttentionLevel
121 	{
122 		VisibleAndActive = 0,   /**< The window is visible and active (aka: has user focus) */
123 		MainWindowIsVisible = 1 /**< The kvirc frame is visible but the window is not the active one */
124 	};
125 	/**
126 	* \enum Type
127 	* \brief Holds the types of a window; these are used by the KVIrc core and distributed modules
128 	* \note If you add a new type, insert it just before Unknown
129 	*/
130 	enum Type
131 	{
132 		Console = 0,
133 		Channel = 1,
134 		Query = 2,
135 		DeadChannel = 3,
136 		DeadQuery = 4,
137 		Editor = 5,
138 		Help = 6,
139 		Terminal = 7,
140 		SocketSpy = 8,
141 		Links = 9,
142 		List = 10,
143 		DccChat = 11,
144 		DccTransfer = 12,
145 		DccCanvas = 13,
146 		DccVoice = 14,
147 		DccVideo = 15,
148 		UserWindow = 16,
149 		Tool = 17,
150 		IOGraph = 18,
151 		DirBrowser = 19,   //!\ no longer exists please reuse entry
152 		ScriptEditor = 20,
153 		ScriptObject = 21,
154 		LogView = 22,
155 		Offer = 23,
156 		Debug = 24,
157 		Unknown = 25,
158 		TypeCount = 26
159 	};
160 
161 	/**
162 	* \brief Constructs the window object
163 	* \param eType The type of the window
164 	* \param lpFrm The main window
165 	* \param szName The name of the window
166 	* \param pConsole The parent console
167 	* \return KviWindow
168 	*/
169 	KviWindow(Type eType, const QString & szName, KviConsoleWindow * pConsole = nullptr);
170 
171 	/**
172 	* \brief Destroys the window object
173 	*/
174 	~KviWindow();
175 
176 protected:            // almost private: don't touch :D
177 	QString m_szName; // the current window name (usually also the target)
178 	KviConsoleWindow * m_pConsole;
179 	Type m_eType;
180 	KviWindowListItem * m_pWindowListItem;
181 	QWidget * m_pFocusHandler;
182 	QString m_szPlainTextCaption;
183 	KviIrcView * m_pIrcView;
184 	KviInput * m_pInput;
185 	KviTalSplitter * m_pSplitter;
186 	KviTalHBox * m_pButtonBox;
187 	unsigned long int m_uId;
188 	QString m_szTextEncoding;
189 #ifdef COMPILE_CRYPT_SUPPORT
190 	KviWindowToolPageButton * m_pCryptControllerButton;
191 	KviCryptController * m_pCryptController;
192 	KviCryptSessionInfo * m_pCryptSessionInfo;
193 #endif
194 	QToolButton * m_pTextEncodingButton;
195 	QToolButton * m_pHideToolsButton;
196 	QWidget * m_pLastFocusedChild;
197 	static const char * m_typeTable[TypeCount];
198 	// text encoding and decoding
199 	//unsigned int              m_uTextEncoding;
200 	QTextCodec * m_pTextCodec;
201 	//KviToolWindowsContainer * m_pEditorsContainer;
202 	bool m_bIsDocked;
203 	bool m_bProcessingInputEvent;
204 
205 public:
isDocked()206 	bool isDocked() const { return m_bIsDocked; }
207 
208 	/**
209 	* \brief Returns the global ID of this window
210 	*
211 	* This is unique in the application
212 	* \return QString
213 	*/
id()214 	QString id() const { return QString("%1").arg(m_uId); }
215 
216 	/**
217 	* \brief Returns the global ID of this window
218 	*
219 	* This is unique in the application
220 	* \return QString
221 	*/
numericId()222 	unsigned long int numericId() const { return m_uId; }
223 
224 	/**
225 	* \brief Returns the name of this window
226 	* \return const QString &
227 	*/
windowName()228 	const QString & windowName() const { return m_szName; }
229 
230 	/**
231 	* \brief Sets the name of the window
232 	* \param szName The name of the window
233 	* \return void
234 	*/
235 	void setWindowName(const QString & szName);
236 
237 	/**
238 	* \brief Sets the progress for the WindowList item
239 	*
240 	* If "progress" makes sense in your window, well, use this
241 	* \param iProgress The progress to set
242 	* \return void
243 	*/
244 	void setProgress(int iProgress);
245 
246 	/**
247 	* \brief Returns the type of the window
248 	* \return Type
249 	*/
type()250 	Type type() const { return m_eType; }
251 
252 	/**
253 	* Returns true if the window is a channel
254 	*/
isChannel()255 	bool isChannel() const { return m_eType == Channel; }
256 
257 	/**
258 	* Returns true if the window is a query
259 	*/
isQuery()260 	bool isQuery() const { return m_eType == Query; }
261 
262 	/**
263 	* Returns true if the window is a console
264 	*/
isConsole()265 	bool isConsole() const { return m_eType == Console; }
266 
267 	/**
268 	* \brief Returns a descriptive name of the window type
269 	* \return const char *
270 	*/
271 	virtual const char * typeString();
272 
textCodec()273 	QTextCodec * textCodec() { return m_pTextCodec ? m_pTextCodec : defaultTextCodec(); }
274 	void forceTextCodec(QTextCodec * pCodec);
275 
276 	/**
277 	* \brief Returns the KviIrcView of this window
278 	*
279 	* May be nullptr if the window has no KviIrcView (and thus supports no direct output)
280 	* \return KviIrcView *
281 	*/
view()282 	KviIrcView * view() const { return m_pIrcView; }
283 
284 	/**
285 	* \brief Returns the KviIrcView that was last clicked in this window
286 	*
287 	* Acts as view() except for split view windows
288 	* See also: view()
289 	* \return KviIrcView *
290 	*/
lastClickedView()291 	virtual KviIrcView * lastClickedView() const { return m_pIrcView; };
292 
293 	/**
294 	* \brief Returns the console that this window belongs to
295 	*
296 	* May be null for windows that aren't bound to irc contexts
297 	* \return KviConsoleWindow *
298 	*/
console()299 	KviConsoleWindow * console() const { return m_pConsole; }
300 
301 	KviIrcContext * context();
302 
303 	/**
304 	* \brief Returns the current IRC connection (if any)
305 	* \return KviIrcConnection *
306 	*/
307 	KviIrcConnection * connection();
308 
309 	/**
310 	* \brief Returns the splitter of this window
311 	*
312 	* It *shouldn't* be null... but... well... who knows ? :D ...better check it
313 	* \return KviTalSplitter *
314 	*/
splitter()315 	KviTalSplitter * splitter() const { return m_pSplitter; }
316 
317 	/**
318 	* \brief Returns the windowList item
319 	*
320 	* The window has ALWAYS a WindowList item
321 	* \return KviWindowListItem *
322 	*/
windowListItem()323 	KviWindowListItem * windowListItem() const { return m_pWindowListItem; }
324 
325 	// The window *might* have a button container
buttonContainer()326 	virtual QFrame * buttonContainer() { return (QFrame *)m_pButtonBox; };
327 	virtual void toggleButtonContainer();
328 
329 	// The window *might* have an output proxy: if it has no view() for example
330 	virtual KviWindow * outputProxy();
331 
332 	// The window input widget
input()333 	KviInput * input() const { return m_pInput; }
334 
335 	// The target of this window: empty when it makes no sense :D
target()336 	virtual const QString & target() { return KviQString::Empty; };
337 
338 	// The local nickname bound to this window: might be empty when a local nickname makes no sense
localNick()339 	virtual const QString & localNick() { return KviQString::Empty; };
340 
341 #ifdef COMPILE_CRYPT_SUPPORT
cryptSessionInfo()342 	KviCryptSessionInfo * cryptSessionInfo()
343 	{
344 		return m_pCryptSessionInfo;
345 	};
346 	void setCryptSessionInfo(KviCryptSessionInfo * pInfo);
347 #endif
348 
349 	virtual bool activityMeter(unsigned int * puActivityValue, unsigned int * puActivityTemperature);
350 
351 	//* \param puValue Highlight level
352 	virtual bool highlightMeter(unsigned int * puValue);
353 	virtual bool highlightMe(unsigned int uValue);
354 
355 	void unhighlight();
356 
getWindowListTipText(QString & szBuffer)357 	virtual void getWindowListTipText(QString & szBuffer) { szBuffer = m_szPlainTextCaption; }
358 
359 	// This is meaningful only if view() is non nullptr
360 	const QString & lastLineOfText();
361 	const QString & lastMessageText();
362 
textEncoding()363 	const QString & textEncoding() const { return m_szTextEncoding; }
364 	// returns true if the encoding could be successfully set
365 	bool setTextEncoding(const QString & szTextEncoding);
366 	// this must return a default text codec suitable for this window
367 	virtual QTextCodec * defaultTextCodec();
368 	// encode the text from szSource by using m_uTextEncoding
369 	QByteArray encodeText(const QString & szText);
370 	QString decodeText(const char * pcText);
371 	//return a text encoder
372 	QTextEncoder * makeEncoder();
373 
374 	void contextPopup();
375 	// Raises the window (after a light delay to prevent focus pingpongs)
376 	void delayedAutoRaise();
377 
378 	// Retrieves the default log file name: this is pre-build
379 	void getDefaultLogFileName(QString & szBuffer);
380 	void getDefaultLogFileName(QString & szBuffer, QDate date, bool bGzip, unsigned int uDatetimeFormat);
381 
382 	void delayedClose(); // close that jumps out of the current event loop
383 
384 	// Interesting overridables:
385 	virtual void getConfigGroupName(QString & szBuffer);
386 	virtual void getBaseLogFileName(QString & szBuffer);
387 	virtual void updateCaption();
388 	virtual void applyOptions();
389 	virtual void updateIcon();
390 	virtual void ownMessage(const QString &, bool = true){};
ownAction(const QString &)391 	virtual void ownAction(const QString &){};
plainTextCaption()392 	virtual const QString & plainTextCaption() { return m_szPlainTextCaption; };
393 
394 	void internalOutput(KviIrcView * pView, int iMsgType, const kvi_wchar_t * pwText, int iFlags = 0, const QDateTime & datetime = QDateTime());
395 	// You *might* want to override these too.. but better don't touch them :D
396 	virtual void output(int iMsgType, const char * pcFormat, ...);
397 	virtual void output(int iMsgType, const kvi_wchar_t * pwFormat, ...);
398 	virtual void output(int iMsgType, QString szFmt, ...);
399 	void output(int iMsgType, const QDateTime & datetime, const char * pcFormat, ...);
400 	void output(int iMsgType, const QDateTime & datetime, const kvi_wchar_t * pwFormat, ...);
401 	void output(int iMsgType, const QDateTime & datetime, QString szFmt, ...);
402 	virtual void outputNoFmt(int iMsgType, const char * pcText, int iFlags = 0, const QDateTime & datetime = QDateTime());
403 	virtual void outputNoFmt(int iMsgType, const kvi_wchar_t * pwText, int iFlags = 0, const QDateTime & datetime = QDateTime()) { internalOutput(m_pIrcView, iMsgType, pwText, iFlags, datetime); };
404 	virtual void outputNoFmt(int iMsgType, const QString & szText, int iFlags = 0, const QDateTime & datetime = QDateTime()); // <-- iFlags are KviIrcView::AppendTextFlags
405 	// Just helpers.. FIXME: might be redesigned in some other way
406 	void updateBackgrounds(QObject * pObj = nullptr);
407 
408 	/**
409 	* \brief Notify the window manager that this window demands attention
410 	*
411 	* Depending on the os/window manager, this method uses different approaches to
412 	* trigger a notification that typically makes the application entry flash
413 	* on the application bar.
414 	* \return void
415 	*/
416 	void demandAttention();
417 
418 	/**
419 	* \brief Returns whether this window is the active one
420 	*
421 	* This method is useful because it takes in consideration that this window
422 	* can be either docked or undocked, and takes a parameter that defines the strictness
423 	* of the checks used.
424 	* Level MainWindowIsVisible is fine to check if we needs to trigger the notifier
425 	* Level VisibleAndActive is useful to trigger highlights
426 	* @param eLevel the level of checks to be done
427 	* \return bool
428 	*/
429 	bool hasAttention(AttentionLevel eLevel = VisibleAndActive);
430 
431 	// This should die, probably
432 	void listWindowTypes();
433 
434 	// call this in the constructor if your caption is fixed:
435 	// it will set m_szPlainTextCaption to szCaption and it will
436 	// automatically use it without the need of overriding fillCaptionBuffers
setFixedCaption(const QString & szCaption)437 	void setFixedCaption(const QString & szCaption) { m_szPlainTextCaption = szCaption; }
438 
439 	void setWindowTitle(QString & szTitle);
440 
441 	/**
442 	* \brief Pastes the most recent channel log into the buffer
443 	*
444 	* It searches for the most recent channel log of the channel we have just
445 	* joined, and pastes into the buffer the last N lines, where N is get from
446 	* the options
447 	* \return void
448 	*/
449 	void pasteLastLog();
450 
451 private:
452 	/**
453 	* \brief Loads a log file
454 	*
455 	* It opens a logfile, gzipped or not, and returns the content in a buffer
456 	* \param szFileName The filename of the log file
457 	* \param bGzip Whether the log file is gzipped
458 	* \return QByteArray
459 	*/
460 	QByteArray loadLogFile(const QString & szFileName, bool bGzip);
461 
462 protected:
463 	// Loading and saving of properties
464 	// Protected: only KviMainWindow can call these
465 	virtual void saveProperties(KviConfigurationFile * pCfg);
466 	virtual void loadProperties(KviConfigurationFile * pCfg);
467 	// Creation and destruction events: overridden in windows that have script events bound to creation and destruction
triggerCreationEvents()468 	virtual void triggerCreationEvents(){};
triggerDestructionEvents()469 	virtual void triggerDestructionEvents(){};
470 	// Internal: do not touch :D (KviMainWindow)
471 	virtual void createWindowListItem();
472 	virtual void destroyWindowListItem();
473 	// called by KviMainWindow
474 	// either lost the active window status or the frame is no longer active (but we're still the active kvirc's subwindow)
475 	virtual void lostUserFocus();
476 	// this by default calls fillSingleColorCaptionBuffer(plainTextCaption());
477 	virtual void fillCaptionBuffers();
478 	// protected helper
fillSingleColorCaptionBuffers(const QString & szName)479 	void fillSingleColorCaptionBuffers(const QString & szName) { m_szPlainTextCaption = szName; }
480 	// Virtual events that signal dock state change
481 	virtual void youAreDocked();
482 	virtual void youAreUndocked();
483 	// Reimplement to show a special icon in the WindowList items and captions
484 	virtual QPixmap * myIconPtr();
485 	// Sets the type of this window: be careful with this
setType(Type eType)486 	void setType(Type eType) { m_eType = eType; };
487 
488 	bool eventFilter(QObject * pObject, QEvent * pEvent) override;
489 
490 	// Virtuals overridden to manage the internal layouts...
491 	void moveEvent(QMoveEvent * pEvent) override;
492 	void closeEvent(QCloseEvent * pEvent) override;
493 	void childEvent(QChildEvent * pEvent) override;
494 	void focusInEvent(QFocusEvent *) override;
495 	void inputMethodEvent(QInputMethodEvent * e) override;
496 
497 	void childInserted(QWidget * pObject);
498 	void childRemoved(QWidget * pObject);
499 
500 	// Internal helpers
501 	void createCryptControllerButton(QWidget * pPar);
502 	void createTextEncodingButton(QWidget * pPar);
503 	void createSystemTextEncodingPopup();
504 
505 	QToolButton * createToolButton(QWidget * pPar, const char * pcName, KviIconManager::SmallIcon eIcon, const QString & szToolTip, bool bOn);
506 	// This is called by KviInput: actually it links the widgetAdded
507 	virtual void childrenTreeChanged(QWidget * pAdded);
508 
509 	bool focusNextPrevChild(bool bNext) override;
510 
511 	virtual void preprocessMessage(QString & szMessage);
512 public slots:
513 	void dock();
514 	void undock();
515 	void autoRaise();
516 	void reloadImages();
517 	void savePropertiesAsDefault();
518 protected slots:
519 	void toggleCryptController();     // This has to be here even if the crypt support is enabled...moc does not support conditionals
520 	void cryptControllerFinished();   // same as above
521 	void cryptSessionInfoDestroyed(); //  same as above
522 	void textEncodingButtonClicked();
523 	void systemTextEncodingPopupActivated(QAction * pAction);
524 	void childDestroyed();
525 signals:
526 	void windowNameChanged();
527 };
528 
529 #ifndef _KVI_WINDOW_CPP_
530 // The active window:
531 //   This is almost always non null
532 //   The exception is the startup (when there are no windows at all)
533 //   and the last phase of the destructor.
534 //   You usually shouldn't care of checking this pointer for nullptr unless
535 //   you're running very early at startup or very late at shutdown
536 extern KVIRC_API KviWindow * g_pActiveWindow;
537 #endif
538 
encodeText(const QString & szText)539 inline QByteArray KviWindow::encodeText(const QString & szText)
540 {
541 	if(m_pTextCodec)
542 		return m_pTextCodec->fromUnicode(szText);
543 	else
544 		return defaultTextCodec()->fromUnicode(szText);
545 }
546 
decodeText(const char * pcText)547 inline QString KviWindow::decodeText(const char * pcText)
548 {
549 	if(m_pTextCodec)
550 		return m_pTextCodec->toUnicode(pcText);
551 	else
552 		return defaultTextCodec()->toUnicode(pcText);
553 }
554 
555 #endif //_KVI_WINDOW_H_
556