ClickSpotter 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +167 -0
- data/bin/clickspotter +4 -0
- data/data/worldmap-large.jpg +0 -0
- data/data/worldmap.png +0 -0
- data/lib/About.rb +22 -0
- data/lib/AboutDlg.rb +169 -0
- data/lib/AppConfig.rb +68 -0
- data/lib/AsyncResolverWithCache.rb +207 -0
- data/lib/BrowserLauncher.rb +23 -0
- data/lib/CSListView.rb +118 -0
- data/lib/CSListViewItem.rb +49 -0
- data/lib/ClickableCanvasView.rb +24 -0
- data/lib/Configuration.rb +123 -0
- data/lib/ConfigurationDlg.rb +372 -0
- data/lib/DNSResolver.rb +53 -0
- data/lib/GSServerLogSettings.rb +24 -0
- data/lib/GeoDistView.rb +351 -0
- data/lib/GeoLocator.rb +91 -0
- data/lib/GlobalSettings.rb +237 -0
- data/lib/HitRecord.rb +39 -0
- data/lib/HostNameDlg.rb +83 -0
- data/lib/LogFileSelector.rb +65 -0
- data/lib/LogFileSelectorDlg.rb +97 -0
- data/lib/LogParser.rb +120 -0
- data/lib/MainWindow.rb +627 -0
- data/lib/MainWindowDlg.rb +1054 -0
- data/lib/OccurenceCounter.rb +65 -0
- data/lib/PageInformation.rb +147 -0
- data/lib/PageInformationDlg.rb +159 -0
- data/lib/PageRecord.rb +77 -0
- data/lib/RefererInformation.rb +114 -0
- data/lib/RefererInformationDlg.rb +106 -0
- data/lib/RefererRecord.rb +51 -0
- data/lib/ServerLogSettings.rb +152 -0
- data/lib/ServerLogSettingsDlg.rb +202 -0
- data/lib/StatusCode.rb +72 -0
- data/lib/TraceRouter.rb +53 -0
- data/lib/VisitorInformation.rb +132 -0
- data/lib/VisitorInformationDlg.rb +351 -0
- data/lib/VisitorRecord.rb +94 -0
- data/lib/WorldMap.rb +93 -0
- data/lib/WorldMapDlg.rb +166 -0
- data/lib/clickspotter.rb +38 -0
- metadata +87 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
#
|
2
|
+
# OccurenceCounter.rb - ClickSpotter
|
3
|
+
#
|
4
|
+
# Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of version 2 of the GNU General Public License as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# $Id: OccurenceCounter.rb 8 2006-01-22 15:19:51Z cs $
|
10
|
+
#
|
11
|
+
|
12
|
+
# This OccurenceCounter class can be used to count the occurence of entries.
|
13
|
+
# Optionally the number of different entries that are tracked can be
|
14
|
+
# limited. In case the limit is reached, the oldest entered or
|
15
|
+
# incremented entry will be dropped for each new entry.
|
16
|
+
class OccurenceCounter
|
17
|
+
|
18
|
+
# Optionally you can limit the number of different tracked entries.
|
19
|
+
def initialize(size = 0)
|
20
|
+
@max = size
|
21
|
+
@buffer = []
|
22
|
+
end
|
23
|
+
|
24
|
+
# This is the main function to track entries. Whenever it's called,
|
25
|
+
# the function tries to lookup the entry in the buffer. In case it
|
26
|
+
# already in there, the counter is increased. New entries are
|
27
|
+
# inserted with a count of 1.
|
28
|
+
def push(entry)
|
29
|
+
return if entry == nil
|
30
|
+
|
31
|
+
for i in 0 ... @buffer.length
|
32
|
+
if @buffer[i][0] == entry
|
33
|
+
if i == 0
|
34
|
+
# If the new entry is the same as the last one, we just
|
35
|
+
# increase the counter.
|
36
|
+
@buffer[0] = [entry, @buffer[0][1]]
|
37
|
+
return
|
38
|
+
end
|
39
|
+
# Move entry to buffer position 0 and shift down all entries
|
40
|
+
# between position 0 and i - 1
|
41
|
+
count = @buffer[i][1]
|
42
|
+
i.downto(1) { |j| @buffer[j] = @buffer[j - 1] }
|
43
|
+
@buffer[0] = [entry, count + 1]
|
44
|
+
return
|
45
|
+
end
|
46
|
+
end
|
47
|
+
# Insert new entry at front and drop the last one if the buffer
|
48
|
+
# became too big.
|
49
|
+
@buffer.insert(0, [entry, 1])
|
50
|
+
@buffer.pop if @max > 0 && @buffer.length > @max
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete(entry)
|
55
|
+
@buffer.delete(entry)
|
56
|
+
end
|
57
|
+
|
58
|
+
# This is the iterator to read out the list of entries with their
|
59
|
+
# counters. Each call of yield retrieves an entry-counter pair.
|
60
|
+
def each
|
61
|
+
@buffer.each { |entry, count| yield(entry, count) }
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
@@ -0,0 +1,147 @@
|
|
1
|
+
#
|
2
|
+
# PageInformation.rb - ClickSpotter
|
3
|
+
#
|
4
|
+
# Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of version 2 of the GNU General Public License as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# $Id: PageInformation.rb 8 2006-01-22 15:19:51Z cs $
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'PageInformationDlg'
|
13
|
+
require 'VisitorInformation'
|
14
|
+
require 'RefererInformation'
|
15
|
+
require 'BrowserLauncher'
|
16
|
+
|
17
|
+
class PageInformation < PageInformationDlg
|
18
|
+
|
19
|
+
include BrowserLauncher
|
20
|
+
|
21
|
+
slots 'hostClicked(QListViewItem*)',
|
22
|
+
'refererClicked(QListViewItem*)',
|
23
|
+
'nextPageClicked(QListViewItem*)',
|
24
|
+
'openPage()'
|
25
|
+
|
26
|
+
def initialize(page, parent = nil, name = nil)
|
27
|
+
super(parent, name)
|
28
|
+
$windowList.push(self)
|
29
|
+
|
30
|
+
@page = page
|
31
|
+
|
32
|
+
setCaption("Page Information - %s" % page.url)
|
33
|
+
|
34
|
+
@visitorListCSLV = CSListView.new(@visitorList)
|
35
|
+
@visitorList.setSorting(1, false)
|
36
|
+
@visitorListCSLV.setColumnWidth(0, 400)
|
37
|
+
|
38
|
+
@refererListCSLV = CSListView.new(@refererList)
|
39
|
+
@refererList.setSorting(1, false)
|
40
|
+
@refererListCSLV.setColumnWidth(0, 400)
|
41
|
+
|
42
|
+
@nextPageListCSLV = CSListView.new(@nextPageList)
|
43
|
+
@nextPageList.setSorting(1, false)
|
44
|
+
@nextPageListCSLV.setColumnWidth(0, 400)
|
45
|
+
|
46
|
+
connect(@visitorList, SIGNAL('clicked(QListViewItem*)'),
|
47
|
+
SLOT('hostClicked(QListViewItem*)'))
|
48
|
+
connect(@refererList, SIGNAL('clicked(QListViewItem*)'),
|
49
|
+
SLOT('refererClicked(QListViewItem*)'))
|
50
|
+
connect(@nextPageList, SIGNAL('clicked(QListViewItem*)'),
|
51
|
+
SLOT('nextPageClicked(QListViewItem*)'))
|
52
|
+
connect(@openButton, SIGNAL('clicked()'), SLOT('openPage()'))
|
53
|
+
|
54
|
+
if $globals.getSetting("PageWindowW") > 0 &&
|
55
|
+
$globals.getSetting("PageWindowH") > 0
|
56
|
+
resize($globals.getSetting("PageWindowW"),
|
57
|
+
$globals.getSetting("PageWindowH"))
|
58
|
+
end
|
59
|
+
|
60
|
+
updateWindow
|
61
|
+
show
|
62
|
+
end
|
63
|
+
|
64
|
+
def updateWindow
|
65
|
+
# Close window if page has been purged
|
66
|
+
if !$pages[@page.url]
|
67
|
+
close(true)
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
@pageURL.setText(@page.url)
|
72
|
+
@hits.setText(@page.hitCount().to_s)
|
73
|
+
@entries.setText(@page.entryCount().to_s)
|
74
|
+
@exits.setText(@page.exitCount().to_s)
|
75
|
+
visitors = {}
|
76
|
+
referers = Hash.new(0)
|
77
|
+
@page.hits.each do |h|
|
78
|
+
visitors[h.visitor] = true
|
79
|
+
next if h.referer == nil
|
80
|
+
referers[h.referer] += 1
|
81
|
+
end
|
82
|
+
# Update visitor list
|
83
|
+
@visitorListCSLV.startUpdate
|
84
|
+
showRobots = $globals.getSetting("ShowRobots") != 0
|
85
|
+
showSurfers = $globals.getSetting("ShowSurfers") != 0
|
86
|
+
visitors.each_key do |v|
|
87
|
+
if (v.robot && !showRobots) || (!v.robot && !showSurfers)
|
88
|
+
next
|
89
|
+
end
|
90
|
+
@visitorListCSLV.insertItem(v, v.host, v.pageCount, v.ip, v.browser)
|
91
|
+
end
|
92
|
+
@visitorListCSLV.finishUpdate
|
93
|
+
|
94
|
+
# Update referer list
|
95
|
+
@refererListCSLV.startUpdate
|
96
|
+
referers.each do |r, count|
|
97
|
+
@refererListCSLV.insertItem(r, r.url, count)
|
98
|
+
end
|
99
|
+
@refererListCSLV.finishUpdate
|
100
|
+
|
101
|
+
# Update nextPages list
|
102
|
+
showRegularPages = $globals.getSetting("ShowRegularPages") != 0
|
103
|
+
showAuxPages = $globals.getSetting("ShowAuxPages") != 0
|
104
|
+
@nextPageListCSLV.startUpdate
|
105
|
+
@page.nextPages.each do |p, count|
|
106
|
+
if ($pages[p].isPage && !showRegularPages) ||
|
107
|
+
(!$pages[p].isPage && !showAuxPages)
|
108
|
+
next
|
109
|
+
end
|
110
|
+
@nextPageListCSLV.insertItem(p, p, count)
|
111
|
+
end
|
112
|
+
@nextPageListCSLV.finishUpdate
|
113
|
+
end
|
114
|
+
|
115
|
+
def hostClicked(item)
|
116
|
+
return if item == nil
|
117
|
+
VisitorInformation.new($visitors[item.text(2) + "|" + item.text(3)])
|
118
|
+
end
|
119
|
+
|
120
|
+
def refererClicked(item)
|
121
|
+
return if item == nil
|
122
|
+
referer = $referers[item.text(0)]
|
123
|
+
if referer.external?
|
124
|
+
RefererInformation.new(referer)
|
125
|
+
else
|
126
|
+
PageInformation.new($pages[item.text(0)])
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def nextPageClicked(item)
|
131
|
+
return if item == nil || !$pages.has_key?(item.text(0))
|
132
|
+
PageInformation.new($pages[item.text(0)])
|
133
|
+
end
|
134
|
+
|
135
|
+
def openPage
|
136
|
+
browseURL(@page.url)
|
137
|
+
end
|
138
|
+
|
139
|
+
def close(dummy)
|
140
|
+
$globals.setSetting("PageWindowW", width())
|
141
|
+
$globals.setSetting("PageWindowH", height())
|
142
|
+
$windowList.delete(self)
|
143
|
+
super(true)
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# Form implementation generated from reading ui file 'PageInformationDlg.ui'
|
2
|
+
#
|
3
|
+
# Created: Mon Jan 23 23:21:52 2006
|
4
|
+
# by: The QtRuby User Interface Compiler (rbuic)
|
5
|
+
#
|
6
|
+
# WARNING! All changes made in this file will be lost!
|
7
|
+
|
8
|
+
|
9
|
+
require 'Qt'
|
10
|
+
|
11
|
+
class PageInformationDlg < Qt::Widget
|
12
|
+
|
13
|
+
attr_reader :textLabel5
|
14
|
+
attr_reader :textLabel1
|
15
|
+
attr_reader :exits
|
16
|
+
attr_reader :hits
|
17
|
+
attr_reader :textLabel11
|
18
|
+
attr_reader :textLabel8
|
19
|
+
attr_reader :entries
|
20
|
+
attr_reader :splitter5
|
21
|
+
attr_reader :groupBox1
|
22
|
+
attr_reader :visitorList
|
23
|
+
attr_reader :groupBox2
|
24
|
+
attr_reader :refererList
|
25
|
+
attr_reader :groupBox3
|
26
|
+
attr_reader :nextPageList
|
27
|
+
attr_reader :pageURL
|
28
|
+
attr_reader :openButton
|
29
|
+
|
30
|
+
|
31
|
+
def initialize(parent = nil, name = nil, fl = 0)
|
32
|
+
super
|
33
|
+
|
34
|
+
if name.nil?
|
35
|
+
setName("PageInformationDlg")
|
36
|
+
end
|
37
|
+
|
38
|
+
@PageInformationDlgLayout = Qt::GridLayout.new(self, 1, 1, 11, 6, 'PageInformationDlgLayout')
|
39
|
+
|
40
|
+
@textLabel5 = Qt::Label.new(self, "textLabel5")
|
41
|
+
|
42
|
+
@PageInformationDlgLayout.addWidget(@textLabel5, 1, 0)
|
43
|
+
|
44
|
+
@textLabel1 = Qt::Label.new(self, "textLabel1")
|
45
|
+
|
46
|
+
@PageInformationDlgLayout.addWidget(@textLabel1, 0, 0)
|
47
|
+
|
48
|
+
@exits = Qt::LineEdit.new(self, "exits")
|
49
|
+
@exits.setAlignment( Qt::LineEdit::AlignRight )
|
50
|
+
@exits.setReadOnly( true )
|
51
|
+
|
52
|
+
@PageInformationDlgLayout.addMultiCellWidget(@exits, 1, 1, 5, 6)
|
53
|
+
|
54
|
+
@hits = Qt::LineEdit.new(self, "hits")
|
55
|
+
@hits.setAlignment( Qt::LineEdit::AlignRight )
|
56
|
+
@hits.setReadOnly( true )
|
57
|
+
|
58
|
+
@PageInformationDlgLayout.addWidget(@hits, 1, 1)
|
59
|
+
|
60
|
+
@textLabel11 = Qt::Label.new(self, "textLabel11")
|
61
|
+
|
62
|
+
@PageInformationDlgLayout.addWidget(@textLabel11, 1, 4)
|
63
|
+
|
64
|
+
@textLabel8 = Qt::Label.new(self, "textLabel8")
|
65
|
+
|
66
|
+
@PageInformationDlgLayout.addWidget(@textLabel8, 1, 2)
|
67
|
+
|
68
|
+
@entries = Qt::LineEdit.new(self, "entries")
|
69
|
+
@entries.setAlignment( Qt::LineEdit::AlignRight )
|
70
|
+
@entries.setReadOnly( true )
|
71
|
+
|
72
|
+
@PageInformationDlgLayout.addWidget(@entries, 1, 3)
|
73
|
+
|
74
|
+
@splitter5 = Qt::Splitter.new(self, "splitter5")
|
75
|
+
@splitter5.setOrientation( Qt::Splitter::Vertical )
|
76
|
+
|
77
|
+
@groupBox1 = Qt::GroupBox.new(@splitter5, "groupBox1")
|
78
|
+
@groupBox1.setColumnLayout( 0, Qt::Vertical )
|
79
|
+
@groupBox1.layout().setSpacing(6)
|
80
|
+
@groupBox1.layout().setMargin(11)
|
81
|
+
@groupBox1Layout = Qt::GridLayout.new(@groupBox1.layout() )
|
82
|
+
@groupBox1Layout.setAlignment( AlignTop )
|
83
|
+
|
84
|
+
@visitorList = Qt::ListView.new(@groupBox1, "visitorList")
|
85
|
+
@visitorList.addColumn(trUtf8("Host"))
|
86
|
+
@visitorList.addColumn(trUtf8("Pages"))
|
87
|
+
@visitorList.addColumn(trUtf8("IP"))
|
88
|
+
@visitorList.addColumn(trUtf8("Browser"))
|
89
|
+
|
90
|
+
@groupBox1Layout.addWidget(@visitorList, 0, 0)
|
91
|
+
|
92
|
+
@groupBox2 = Qt::GroupBox.new(@splitter5, "groupBox2")
|
93
|
+
@groupBox2.setColumnLayout( 0, Qt::Vertical )
|
94
|
+
@groupBox2.layout().setSpacing(6)
|
95
|
+
@groupBox2.layout().setMargin(11)
|
96
|
+
@groupBox2Layout = Qt::GridLayout.new(@groupBox2.layout() )
|
97
|
+
@groupBox2Layout.setAlignment( AlignTop )
|
98
|
+
|
99
|
+
@refererList = Qt::ListView.new(@groupBox2, "refererList")
|
100
|
+
@refererList.addColumn(trUtf8("URL"))
|
101
|
+
@refererList.addColumn(trUtf8("Count"))
|
102
|
+
|
103
|
+
@groupBox2Layout.addWidget(@refererList, 0, 0)
|
104
|
+
|
105
|
+
@groupBox3 = Qt::GroupBox.new(@splitter5, "groupBox3")
|
106
|
+
@groupBox3.setColumnLayout( 0, Qt::Vertical )
|
107
|
+
@groupBox3.layout().setSpacing(6)
|
108
|
+
@groupBox3.layout().setMargin(11)
|
109
|
+
@groupBox3Layout = Qt::GridLayout.new(@groupBox3.layout() )
|
110
|
+
@groupBox3Layout.setAlignment( AlignTop )
|
111
|
+
|
112
|
+
@nextPageList = Qt::ListView.new(@groupBox3, "nextPageList")
|
113
|
+
@nextPageList.addColumn(trUtf8("Page"))
|
114
|
+
@nextPageList.addColumn(trUtf8("Count"))
|
115
|
+
|
116
|
+
@groupBox3Layout.addWidget(@nextPageList, 0, 0)
|
117
|
+
|
118
|
+
@PageInformationDlgLayout.addMultiCellWidget(@splitter5, 2, 2, 0, 6)
|
119
|
+
|
120
|
+
@pageURL = Qt::LineEdit.new(self, "pageURL")
|
121
|
+
@pageURL.setReadOnly( true )
|
122
|
+
|
123
|
+
@PageInformationDlgLayout.addMultiCellWidget(@pageURL, 0, 0, 1, 5)
|
124
|
+
|
125
|
+
@openButton = Qt::PushButton.new(self, "openButton")
|
126
|
+
|
127
|
+
@PageInformationDlgLayout.addWidget(@openButton, 0, 6)
|
128
|
+
languageChange()
|
129
|
+
resize( Qt::Size.new(661, 625).expandedTo(minimumSizeHint()) )
|
130
|
+
clearWState( WState_Polished )
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Sets the strings of the subwidgets using the current
|
135
|
+
# language.
|
136
|
+
#
|
137
|
+
def languageChange()
|
138
|
+
setCaption(trUtf8("Page Information"))
|
139
|
+
@textLabel5.setText( trUtf8("<b>Hits:</b>") )
|
140
|
+
@textLabel1.setText( trUtf8("<b>Page:</b>") )
|
141
|
+
@textLabel11.setText( trUtf8("<b>Exists:</b>") )
|
142
|
+
@textLabel8.setText( trUtf8("<b>Entries:</b>") )
|
143
|
+
@groupBox1.setTitle( trUtf8("Visitors") )
|
144
|
+
@visitorList.header().setLabel( 0, trUtf8("Host") )
|
145
|
+
@visitorList.header().setLabel( 1, trUtf8("Pages") )
|
146
|
+
@visitorList.header().setLabel( 2, trUtf8("IP") )
|
147
|
+
@visitorList.header().setLabel( 3, trUtf8("Browser") )
|
148
|
+
@groupBox2.setTitle( trUtf8("Referers") )
|
149
|
+
@refererList.header().setLabel( 0, trUtf8("URL") )
|
150
|
+
@refererList.header().setLabel( 1, trUtf8("Count") )
|
151
|
+
@groupBox3.setTitle( trUtf8("Next Pages") )
|
152
|
+
@nextPageList.header().setLabel( 0, trUtf8("Page") )
|
153
|
+
@nextPageList.header().setLabel( 1, trUtf8("Count") )
|
154
|
+
@openButton.setText( trUtf8("Open") )
|
155
|
+
end
|
156
|
+
protected :languageChange
|
157
|
+
|
158
|
+
|
159
|
+
end
|
data/lib/PageRecord.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#
|
2
|
+
# PageRecord.rb - ClickSpotter
|
3
|
+
#
|
4
|
+
# Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of version 2 of the GNU General Public License as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# $Id: PageRecord.rb 8 2006-01-22 15:19:51Z cs $
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'HitRecord'
|
13
|
+
|
14
|
+
class PageRecord
|
15
|
+
|
16
|
+
attr_reader :url, :nextPages, :hits, :isPage
|
17
|
+
|
18
|
+
def initialize(url, isPage)
|
19
|
+
@hits = []
|
20
|
+
@nextPages = {}
|
21
|
+
@url = url
|
22
|
+
@isPage = isPage
|
23
|
+
end
|
24
|
+
|
25
|
+
def addHit(hit)
|
26
|
+
@hits.push(hit)
|
27
|
+
hit.page = self
|
28
|
+
end
|
29
|
+
|
30
|
+
def purge(deadline)
|
31
|
+
@hits.each do |h|
|
32
|
+
if h.timeStamp < deadline
|
33
|
+
@hits.delete(h)
|
34
|
+
else
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
@hits.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def purgeNextPages(pages)
|
42
|
+
pages.each { |p| @nextPages.delete(p) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def hitCount
|
46
|
+
return @hits.length()
|
47
|
+
end
|
48
|
+
|
49
|
+
def addReferral(nextPage)
|
50
|
+
if nextPages.has_key?(nextPage)
|
51
|
+
nextPages[nextPage] += 1
|
52
|
+
else
|
53
|
+
nextPages[nextPage] = 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def entryCount
|
58
|
+
count = 0
|
59
|
+
@hits.each do |h|
|
60
|
+
count += 1 if h.entry
|
61
|
+
end
|
62
|
+
return count
|
63
|
+
end
|
64
|
+
|
65
|
+
def exitCount
|
66
|
+
count = 0
|
67
|
+
@hits.each do |h|
|
68
|
+
count+= 1 if h.exit
|
69
|
+
end
|
70
|
+
return count
|
71
|
+
end
|
72
|
+
|
73
|
+
def lastHit
|
74
|
+
return @hits[-1]
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|