summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/dom_ui/net_internals_ui.cc93
-rw-r--r--chrome/browser/net/chrome_net_log.cc3
-rw-r--r--chrome/browser/net/net_log_logger.cc22
-rw-r--r--chrome/browser/net/net_log_logger.h17
-rw-r--r--chrome/browser/resources/net_internals/dataview.js31
-rw-r--r--chrome/browser/resources/net_internals/eventsview.js12
-rw-r--r--chrome/browser/resources/net_internals/index.html44
-rw-r--r--chrome/browser/resources/net_internals/main.js173
-rw-r--r--chrome/browser/resources/net_internals/proxyview.js4
-rw-r--r--chrome/browser/resources/net_internals/tabswitcherview.js7
10 files changed, 363 insertions, 43 deletions
diff --git a/chrome/browser/dom_ui/net_internals_ui.cc b/chrome/browser/dom_ui/net_internals_ui.cc
index 403eb5e..856c2b7 100644
--- a/chrome/browser/dom_ui/net_internals_ui.cc
+++ b/chrome/browser/dom_ui/net_internals_ui.cc
@@ -28,6 +28,9 @@
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/shell_dialogs.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/jstemplate_builder.h"
@@ -136,6 +139,7 @@ class NetInternalsHTMLSource : public ChromeURLDataManager::DataSource {
// TODO(eroman): Can we start on the IO thread to begin with?
class NetInternalsMessageHandler
: public DOMMessageHandler,
+ public SelectFileDialog::Listener,
public base::SupportsWeakPtr<NetInternalsMessageHandler> {
public:
NetInternalsMessageHandler();
@@ -150,12 +154,43 @@ class NetInternalsMessageHandler
void CallJavascriptFunction(const std::wstring& function_name,
const Value* value);
+ // SelectFileDialog::Listener implementation
+ virtual void FileSelected(const FilePath& path, int index, void* params);
+ virtual void FileSelectionCanceled(void* params);
+
+ // The only callback handled on the UI thread. As it needs to access fields
+ // from |dom_ui_|, it can't be called on the IO thread.
+ void OnLoadLogFile(const ListValue* list);
+
private:
class IOThreadImpl;
+ // Task run on the FILE thread to read the contents of a log file. The result
+ // is then passed to IOThreadImpl's CallJavascriptFunction, which sends it
+ // back to the web page. IOThreadImpl is used instead of the
+ // NetInternalsMessageHandler directly because it checks if the message
+ // handler has been destroyed in the meantime.
+ class ReadLogFileTask : public Task {
+ public:
+ ReadLogFileTask(IOThreadImpl* proxy, const FilePath& path);
+
+ virtual void Run();
+
+ private:
+ // IOThreadImpl implements existence checks already. Simpler to reused them
+ // then to reimplement them.
+ scoped_refptr<IOThreadImpl> proxy_;
+
+ // Path of the file to open.
+ const FilePath path_;
+ };
+
// This is the "real" message handler, which lives on the IO thread.
scoped_refptr<IOThreadImpl> proxy_;
+ // Used for loading log files.
+ scoped_refptr<SelectFileDialog> select_log_file_dialog_;
+
DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
};
@@ -243,17 +278,17 @@ class NetInternalsMessageHandler::IOThreadImpl
int result);
virtual void OnCompletedConnectionTestSuite();
+ // Helper that executes |function_name| in the attached renderer.
+ // The function takes ownership of |arg|. Note that this can be called from
+ // any thread.
+ void CallJavascriptFunction(const std::wstring& function_name, Value* arg);
+
private:
class CallbackHelper;
// Helper that runs |method| with |arg|, and deletes |arg| on completion.
void DispatchToMessageHandler(ListValue* arg, MessageHandler method);
- // Helper that executes |function_name| in the attached renderer.
- // The function takes ownership of |arg|. Note that this can be called from
- // any thread.
- void CallJavascriptFunction(const std::wstring& function_name, Value* arg);
-
// Adds |entry| to the queue of pending log entries to be sent to the page via
// Javascript. Must be called on the IO Thread. Also creates a delayed task
// that will call PostPendingEntries, if there isn't one already.
@@ -398,6 +433,8 @@ NetInternalsMessageHandler::~NetInternalsMessageHandler() {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
NewRunnableMethod(proxy_.get(), &IOThreadImpl::Detach));
}
+ if (select_log_file_dialog_)
+ select_log_file_dialog_->ListenerDestroyed();
}
DOMMessageHandler* NetInternalsMessageHandler::Attach(DOMUI* dom_ui) {
@@ -408,8 +445,35 @@ DOMMessageHandler* NetInternalsMessageHandler::Attach(DOMUI* dom_ui) {
return result;
}
+void NetInternalsMessageHandler::FileSelected(
+ const FilePath& path, int index, void* params) {
+ select_log_file_dialog_.release();
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ new ReadLogFileTask(proxy_.get(), path));
+}
+
+void NetInternalsMessageHandler::FileSelectionCanceled(void* params) {
+ select_log_file_dialog_.release();
+}
+
+void NetInternalsMessageHandler::OnLoadLogFile(const ListValue* list) {
+ // Only allow a single dialog at a time.
+ if (select_log_file_dialog_.get())
+ return;
+ select_log_file_dialog_ = SelectFileDialog::Create(this);
+ select_log_file_dialog_->SelectFile(
+ SelectFileDialog::SELECT_OPEN_FILE, string16(), FilePath(), NULL, 0,
+ FILE_PATH_LITERAL(""),
+ dom_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL);
+}
+
void NetInternalsMessageHandler::RegisterMessages() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // Only callback handled on UI thread.
+ dom_ui_->RegisterMessageCallback(
+ "loadLogFile",
+ NewCallback(this, &NetInternalsMessageHandler::OnLoadLogFile));
dom_ui_->RegisterMessageCallback(
"notifyReady",
@@ -471,6 +535,25 @@ void NetInternalsMessageHandler::CallJavascriptFunction(
////////////////////////////////////////////////////////////////////////////////
//
+// NetInternalsMessageHandler::ReadLogFileTask
+//
+////////////////////////////////////////////////////////////////////////////////
+
+NetInternalsMessageHandler::ReadLogFileTask::ReadLogFileTask(
+ IOThreadImpl* proxy, const FilePath& path)
+ : proxy_(proxy), path_(path) {
+}
+
+void NetInternalsMessageHandler::ReadLogFileTask::Run() {
+ std::string file_contents;
+ if (!file_util::ReadFileToString(path_, &file_contents))
+ return;
+ proxy_->CallJavascriptFunction(L"g_browser.loadedLogFile",
+ new StringValue(file_contents));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
// NetInternalsMessageHandler::IOThreadImpl
//
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/net/chrome_net_log.cc b/chrome/browser/net/chrome_net_log.cc
index 58fe6ad..39ebe79 100644
--- a/chrome/browser/net/chrome_net_log.cc
+++ b/chrome/browser/net/chrome_net_log.cc
@@ -67,7 +67,8 @@ ChromeNetLog::ChromeNetLog()
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kLogNetLog)) {
- net_log_logger_.reset(new NetLogLogger());
+ net_log_logger_.reset(new NetLogLogger(
+ command_line.GetSwitchValuePath(switches::kLogNetLog)));
AddObserver(net_log_logger_.get());
}
}
diff --git a/chrome/browser/net/net_log_logger.cc b/chrome/browser/net/net_log_logger.cc
index bba75ca..1468e6f 100644
--- a/chrome/browser/net/net_log_logger.cc
+++ b/chrome/browser/net/net_log_logger.cc
@@ -4,11 +4,19 @@
#include "chrome/browser/net/net_log_logger.h"
+#include <stdio.h>
+
+#include "base/file_util.h"
#include "base/json/json_writer.h"
+#include "base/threading/thread_restrictions.h"
#include "base/values.h"
-NetLogLogger::NetLogLogger()
+NetLogLogger::NetLogLogger(const FilePath &log_path)
: ThreadSafeObserver(net::NetLog::LOG_ALL_BUT_BYTES) {
+ if (!log_path.empty()) {
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ file_.Set(file_util::OpenFile(log_path, "w"));
+ }
}
NetLogLogger::~NetLogLogger() {}
@@ -21,8 +29,16 @@ void NetLogLogger::OnAddEntry(net::NetLog::EventType type,
scoped_ptr<Value> value(net::NetLog::EntryToDictionaryValue(type, time,
source, phase,
params, true));
+ // Don't pretty print, so each JSON value occupies a single line, with no
+ // breaks (Line breaks in any text field will be escaped). Using strings
+ // instead of integer identifiers allows logs from older versions to be
+ // loaded, though a little extra parsing has to be done when loading a log.
std::string json;
- base::JSONWriter::Write(value.get(), true, &json);
- VLOG(1) << json;
+ base::JSONWriter::Write(value.get(), false, &json);
+ if (!file_.get()) {
+ VLOG(1) << json;
+ } else {
+ fprintf(file_.get(), "%s\n", json.c_str());
+ }
}
diff --git a/chrome/browser/net/net_log_logger.h b/chrome/browser/net/net_log_logger.h
index 564f232..2cb88c6 100644
--- a/chrome/browser/net/net_log_logger.h
+++ b/chrome/browser/net/net_log_logger.h
@@ -6,14 +6,23 @@
#define CHROME_BROWSER_NET_NET_LOG_LOGGER_H_
#pragma once
+#include "base/scoped_handle.h"
#include "chrome/browser/net/chrome_net_log.h"
+class FilePath;
+
// NetLogLogger watches the NetLog event stream, and sends all entries to
-// VLOG(1). This is to debug errors that prevent getting to the
-// about:net-internals page.
+// VLOG(1) or a path specified on creation. This is to debug errors that
+// prevent getting to the about:net-internals page.
+//
+// Relies on ChromeNetLog only calling an Observer once at a time for
+// thread-safety.
class NetLogLogger : public ChromeNetLog::ThreadSafeObserver {
public:
- NetLogLogger();
+ // If |log_path| is empty or file creation fails, writes to VLOG(1).
+ // Otherwise, writes to |log_path|. Uses one line per entry, for
+ // easy parsing.
+ explicit NetLogLogger(const FilePath &log_path);
~NetLogLogger();
// ThreadSafeObserver implementation:
@@ -24,6 +33,8 @@ class NetLogLogger : public ChromeNetLog::ThreadSafeObserver {
net::NetLog::EventParameters* params);
private:
+ ScopedStdioHandle file_;
+
DISALLOW_COPY_AND_ASSIGN(NetLogLogger);
};
diff --git a/chrome/browser/resources/net_internals/dataview.js b/chrome/browser/resources/net_internals/dataview.js
index 2535303..5db47ff 100644
--- a/chrome/browser/resources/net_internals/dataview.js
+++ b/chrome/browser/resources/net_internals/dataview.js
@@ -19,7 +19,12 @@ function DataView(mainBoxId,
byteLoggingCheckboxId,
passivelyCapturedCountId,
activelyCapturedCountId,
- deleteAllId) {
+ deleteAllId,
+ dumpDataDivId,
+ loadDataDivId,
+ loadLogFileId,
+ capturingTextSpanId,
+ loggingTextSpanId) {
DivView.call(this, mainBoxId);
this.textPre_ = document.getElementById(outputTextBoxId);
@@ -40,6 +45,14 @@ function DataView(mainBoxId,
document.getElementById(deleteAllId).onclick =
g_browser.deleteAllEvents.bind(g_browser);
+ this.dumpDataDiv_ = document.getElementById(dumpDataDivId);
+ this.loadDataDiv_ = document.getElementById(loadDataDivId);
+ this.capturingTextSpan_ = document.getElementById(capturingTextSpanId);
+ this.loggingTextSpan_ = document.getElementById(loggingTextSpanId);
+
+ document.getElementById(loadLogFileId).onclick =
+ g_browser.loadLogFile.bind(g_browser);
+
this.updateEventCounts_();
this.waitingForUpdate_ = false;
@@ -71,6 +84,18 @@ DataView.prototype.onAllLogEntriesDeleted = function() {
};
/**
+ * Called when either a log file is loaded or when going back to actively
+ * logging events. In either case, called after clearing the old entries,
+ * but before getting any new ones.
+ */
+DataView.prototype.onSetIsViewingLogFile = function(isViewingLogFile) {
+ setNodeDisplay(this.dumpDataDiv_, !isViewingLogFile);
+ setNodeDisplay(this.capturingTextSpan_, !isViewingLogFile);
+ setNodeDisplay(this.loggingTextSpan_, isViewingLogFile);
+ this.setText_('');
+};
+
+/**
* Updates the counters showing how many events have been captured.
*/
DataView.prototype.updateEventCounts_ = function() {
@@ -108,6 +133,10 @@ DataView.prototype.onExportToText_ = function() {
* Presents the captured data as formatted text.
*/
DataView.prototype.onUpdateAllCompleted = function(data) {
+ // It's possible for a log file to be loaded while a dump is being generated.
+ // When that happens, don't display the log dump, to avoid any confusion.
+ if (g_browser.isViewingLogFile())
+ return;
this.waitingForUpdate_ = false;
var text = [];
diff --git a/chrome/browser/resources/net_internals/eventsview.js b/chrome/browser/resources/net_internals/eventsview.js
index 7af86aa..d3768ed 100644
--- a/chrome/browser/resources/net_internals/eventsview.js
+++ b/chrome/browser/resources/net_internals/eventsview.js
@@ -475,10 +475,20 @@ EventsView.prototype.onLogEntriesDeleted = function(sourceIds) {
/**
* Called whenever all log events are deleted.
*/
-EventsView.prototype.onAllLogEntriesDeleted = function(offset) {
+EventsView.prototype.onAllLogEntriesDeleted = function() {
this.initializeSourceList_();
};
+/**
+ * Called when either a log file is loaded or when going back to actively
+ * logging events. In either case, called after clearing the old entries,
+ * but before getting any new ones.
+ */
+EventsView.prototype.onSetIsViewingLogFile = function(isViewingLogFile) {
+ // Needed to sort new sourceless entries correctly.
+ this.maxReceivedSourceId_ = 0;
+};
+
EventsView.prototype.incrementPrefilterCount = function(offset) {
this.numPrefilter_ += offset;
this.invalidateFilterCounter_();
diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html
index 732c4be..0cbadb7 100644
--- a/chrome/browser/resources/net_internals/index.html
+++ b/chrome/browser/resources/net_internals/index.html
@@ -202,23 +202,41 @@ found in the LICENSE file.
<table width=100%>
<tr>
<td valign=top>
- <h2>Dump data</h2>
- <div style="margin: 8px">
- <p><input id=securityStrippingCheckbox type=checkbox checked=yes>
- Strip private information (cookies and credentials).
- </p>
- <p>
- <a href="javascript:displayHelpForBugDump()">
- Help: How to get data for bug reports?
- </a>
- </p>
- <button id=exportToText class=bigButton>Dump to text</button>
+ <div id=dataViewDumpDataDiv>
+ <h2>Dump data</h2>
+ <div style="margin: 8px">
+ <p><input id=securityStrippingCheckbox type=checkbox checked=yes>
+ Strip private information (cookies and credentials).
+ </p>
+ <p>
+ <a href="javascript:displayHelpForBugDump()">
+ Help: How to get data for bug reports?
+ </a>
+ </p>
+ <button id=exportToText class=bigButton>Dump to text</button>
+ </div>
+ </div>
+ <div id=dataViewLoadDataDiv>
+ <h2>Load data</h2>
+ <div style="margin: 8px">
+ <p><input type=button value="Load log from file" id=dataViewLoadLogFile /></p>
+ <p>Only works with log files created with "--log-net-log=file_name".</p>
+ <p>Once a log is loaded, this page will stop collecting data, and will
+ only start gathering data again when the page is
+ <a href="javascript:history.go(0);">reloaded</a>.<BR>
+ </p>
+ </div>
</div>
</td>
<td align=right valign=top>
- <div class="capturingBox">
- <b>Capturing all events...</b>
+ <div class="capturingBox" id=dataViewCapturingBox>
+ <span id=dataViewCapturingTextSpan>
+ <b>Capturing all events...</b>
+ </span>
+ <span id=dataViewLoggingTextSpan style="display: none;">
+ <b>Viewing loaded log file.</b>
+ </span>
<table style="margin: 8px">
<tr>
<td>Passively captured:</td>
diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js
index d879c87..de8b43c 100644
--- a/chrome/browser/resources/net_internals/main.js
+++ b/chrome/browser/resources/net_internals/main.js
@@ -75,10 +75,12 @@ function onLoaded() {
// captured data.
var dataView = new DataView('dataTabContent', 'exportedDataText',
'exportToText', 'securityStrippingCheckbox',
- 'byteLoggingCheckbox',
- 'passivelyCapturedCount',
- 'activelyCapturedCount',
- 'dataViewDeleteAll');
+ 'byteLoggingCheckbox', 'passivelyCapturedCount',
+ 'activelyCapturedCount', 'dataViewDeleteAll',
+ 'dataViewDumpDataDiv', 'dataViewLoadDataDiv',
+ 'dataViewLoadLogFile',
+ 'dataViewCapturingTextSpan',
+ 'dataViewLoggingTextSpan');
// Create a view which will display the results and controls for connection
// tests.
@@ -108,6 +110,7 @@ function onLoaded() {
// Create a view which lets you tab between the different sub-views.
var categoryTabSwitcher = new TabSwitcherView('categoryTabHandles');
+ g_browser.setTabSwitcher(categoryTabSwitcher);
// Populate the main tabs.
categoryTabSwitcher.addTab('eventsTab', eventsView, false);
@@ -144,6 +147,9 @@ function onLoaded() {
// Select the initial view based on the current URL.
window.onhashchange();
+ // Inform observers a log file is not currently being displayed.
+ g_browser.setIsViewingLogFile_(false);
+
// Tell the browser that we are ready to start receiving log events.
g_browser.sendReady();
}
@@ -191,6 +197,11 @@ function BrowserBridge() {
// Next unique id to be assigned to a log entry without a source.
// Needed to simplify deletion, identify associated GUI elements, etc.
this.nextSourcelessEventId_ = -1;
+
+ // True when viewing a log file rather than actively logged events.
+ // When viewing a log file, all tabs are hidden except the event view,
+ // and all received events are ignored.
+ this.isViewingLogFile_ = false;
}
/*
@@ -302,23 +313,19 @@ BrowserBridge.prototype.setLogLevel = function(logLevel) {
chrome.send('setLogLevel', ['' + logLevel]);
}
+BrowserBridge.prototype.loadLogFile = function() {
+ chrome.send('loadLogFile');
+}
+
//------------------------------------------------------------------------------
// Messages received from the browser
//------------------------------------------------------------------------------
BrowserBridge.prototype.receivedLogEntries = function(logEntries) {
- for (var e = 0; e < logEntries.length; ++e) {
- var logEntry = logEntries[e];
-
- // Assign unique ID, if needed.
- if (logEntry.source.id == 0) {
- logEntry.source.id = this.nextSourcelessEventId_;
- --this.nextSourcelessEventId_;
- }
- this.capturedEvents_.push(logEntry);
- for (var i = 0; i < this.logObservers_.length; ++i)
- this.logObservers_[i].onLogEntryAdded(logEntry);
- }
+ // Does nothing if viewing a log file.
+ if (this.isViewingLogFile_)
+ return;
+ this.addLogEntries(logEntries);
};
BrowserBridge.prototype.receivedLogEventTypeConstants = function(constantsMap) {
@@ -439,9 +446,91 @@ BrowserBridge.prototype.receivedHttpCacheInfo = function(info) {
this.pollableDataHelpers_.httpCacheInfo.update(info);
};
+BrowserBridge.prototype.loadedLogFile = function(logFileContents) {
+ var match;
+ // Replace carriage returns with linebreaks and then split around linebreaks.
+ var lines = logFileContents.replace(/\r/g, '\n').split('\n');
+ var entries = [];
+ var numInvalidLines = 0;
+
+ for (var i = 0; i < lines.length; ++i) {
+ if (lines[i].trim().length == 0)
+ continue;
+ // Parse all valid lines, skipping any others.
+ try {
+ var entry = JSON.parse(lines[i]);
+ if (entry &&
+ typeof(entry) == 'object' &&
+ entry.phase != undefined &&
+ entry.source != undefined &&
+ entry.time != undefined &&
+ entry.type != undefined) {
+ entries.push(entry);
+ continue;
+ }
+ } catch (err) {
+ }
+ ++numInvalidLines;
+ console.log('Unable to parse log line: ' + lines[i]);
+ }
+
+ if (entries.length == 0) {
+ window.alert('Loading log file failed.');
+ return;
+ }
+
+ this.deleteAllEvents();
+
+ this.setIsViewingLogFile_(true);
+
+ var validEntries = [];
+ for (var i = 0; i < entries.length; ++i) {
+ entries[i].wasPassivelyCaptured = true;
+ if (LogEventType[entries[i].type] != undefined &&
+ LogSourceType[entries[i].source.type] != undefined &&
+ LogEventPhase[entries[i].phase] != undefined) {
+ entries[i].type = LogEventType[entries[i].type];
+ entries[i].source.type = LogSourceType[entries[i].source.type];
+ entries[i].phase = LogEventPhase[entries[i].phase];
+ validEntries.push(entries[i]);
+ } else {
+ // TODO(mmenke): Do something reasonable when the event type isn't
+ // found, which could happen when event types are
+ // removed or added between versions. Could also happen
+ // with source types, but less likely.
+ console.log(
+ 'Unrecognized values in log entry: ' + JSON.stringify(entry));
+ }
+ }
+
+ this.numPassivelyCapturedEvents_ = validEntries.length;
+ this.addLogEntries(validEntries);
+
+ var numInvalidEntries = entries.length - validEntries.length;
+ if (numInvalidEntries > 0 || numInvalidLines > 0) {
+ window.alert(
+ numInvalidLines.toString() +
+ ' could not be parsed as JSON strings, and ' +
+ numInvalidEntries.toString() +
+ ' entries don\'t have valid data.\n\n' +
+ 'Unparseable lines may indicate log file corruption.\n' +
+ 'Entries with invalid data may be caused by version differences.\n\n' +
+ 'See console for more information.');
+ }
+}
+
//------------------------------------------------------------------------------
/**
+ * Sets the |categoryTabSwitcher_| of BrowserBridge. Since views depend on
+ * g_browser being initialized, have to have a BrowserBridge prior to tab
+ * construction.
+ */
+BrowserBridge.prototype.setTabSwitcher = function(categoryTabSwitcher) {
+ this.categoryTabSwitcher_ = categoryTabSwitcher;
+};
+
+/**
* Adds a listener of log entries. |observer| will be called back when new log
* data arrives, through:
*
@@ -592,6 +681,25 @@ BrowserBridge.prototype.getNumPassivelyCapturedEvents = function() {
};
/**
+ * Sends each entry to all log observers, and updates |capturedEvents_|.
+ * Also assigns unique ids to log entries without a source.
+ */
+BrowserBridge.prototype.addLogEntries = function(logEntries) {
+ for (var e = 0; e < logEntries.length; ++e) {
+ var logEntry = logEntries[e];
+
+ // Assign unique ID, if needed.
+ if (logEntry.source.id == 0) {
+ logEntry.source.id = this.nextSourcelessEventId_;
+ --this.nextSourcelessEventId_;
+ }
+ this.capturedEvents_.push(logEntry);
+ for (var i = 0; i < this.logObservers_.length; ++i)
+ this.logObservers_[i].onLogEntryAdded(logEntry);
+ }
+};
+
+/**
* Deletes captured events with source IDs in |sourceIds|.
*/
BrowserBridge.prototype.deleteEventsBySourceId = function(sourceIds) {
@@ -626,6 +734,39 @@ BrowserBridge.prototype.deleteAllEvents = function() {
};
/**
+ * Informs log observers whether or not future events will be from a log file.
+ * Hides all tabs except the events and data tabs when viewing a log file, shows
+ * them all otherwise.
+ */
+BrowserBridge.prototype.setIsViewingLogFile_ = function(isViewingLogFile) {
+ this.isViewingLogFile_ = isViewingLogFile;
+ var tabIds = this.categoryTabSwitcher_.getAllTabIds();
+
+ for (var i = 0; i < this.logObservers_.length; ++i)
+ this.logObservers_[i].onSetIsViewingLogFile(isViewingLogFile);
+
+ // Shows/hides tabs not used when viewing a log file.
+ for (var i = 0; i < tabIds.length; ++i) {
+ if (tabIds[i] == 'eventsTab' || tabIds[i] == 'dataTab')
+ continue;
+ this.categoryTabSwitcher_.showTabHandleNode(tabIds[i], !isViewingLogFile);
+ }
+
+ if (isViewingLogFile) {
+ var activeTab = this.categoryTabSwitcher_.findActiveTab();
+ if (activeTab.id != 'eventsTab')
+ this.categoryTabSwitcher_.switchToTab('dataTab', null);
+ }
+};
+
+/**
+ * Returns true if a log file is currently being viewed.
+ */
+BrowserBridge.prototype.isViewingLogFile = function() {
+ return this.isViewingLogFile_;
+};
+
+/**
* If |force| is true, calls all startUpdate functions. Otherwise, just
* runs updates with active observers.
*/
diff --git a/chrome/browser/resources/net_internals/proxyview.js b/chrome/browser/resources/net_internals/proxyview.js
index 0f7f68b..a6ff9a9 100644
--- a/chrome/browser/resources/net_internals/proxyview.js
+++ b/chrome/browser/resources/net_internals/proxyview.js
@@ -114,3 +114,7 @@ ProxyView.prototype.onLogEntriesDeleted = function(sourceIds) {
ProxyView.prototype.onAllLogEntriesDeleted = function() {
this.clearLog_();
};
+
+ProxyView.prototype.onSetIsViewingLogFile = function(isViewingLogFile) {
+};
+
diff --git a/chrome/browser/resources/net_internals/tabswitcherview.js b/chrome/browser/resources/net_internals/tabswitcherview.js
index 646c983..18cfa7a 100644
--- a/chrome/browser/resources/net_internals/tabswitcherview.js
+++ b/chrome/browser/resources/net_internals/tabswitcherview.js
@@ -136,6 +136,13 @@ TabSwitcherView.prototype.getAllTabIds = function() {
return ids;
};
+// Shows/hides the DOM node that is used to select the tab. Will not change
+// the active tab.
+TabSwitcherView.prototype.showTabHandleNode = function(id, isVisible) {
+ var tab = this.findTabById(id);
+ setNodeDisplay(tab.getTabHandleNode(), isVisible);
+};
+
//-----------------------------------------------------------------------------
/**