This commit is contained in:
Andrzej Kapolka 2014-01-02 15:45:27 -08:00
commit 460a9aacb8
21 changed files with 472 additions and 426 deletions

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="17.186px" height="14px" viewBox="0 0 17.186 14" enable-background="new 0 0 17.186 14" xml:space="preserve">
<g>
<path fill="#666666" d="M12,9.446v1.989C12,11.747,11.987,12,11.675,12H2.806C2.494,12,2,11.747,2,11.435V2.565
C2,2.253,2.494,2,2.806,2H11V0H2.806C1.392,0,0,1.151,0,2.565v8.869C0,12.849,1.392,14,2.806,14h8.869
C13.09,14,14,12.849,14,11.435V8.435L12,9.446z"/>
<path fill="#333333" d="M9.568,10.138c-0.3,0.299-0.769,0.299-1.069,0L4.466,6.105c-0.3-0.301-0.3-0.768,0-1.069l1.032-1.032
c0.3-0.299,0.769-0.299,1.069,0L9.033,6.47l6.068-6.068c0.3-0.299,0.769-0.299,1.069,0l1.032,1.032c0.3,0.301,0.3,0.768,0,1.069
L9.568,10.138z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -1,7 +1,58 @@
QPlainTextEdit {
font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;
font-size: 16px;
padding-left: 28px;
padding-top: 7px;
color: #333333;
background-color: #FFFFFF;
border: none;
}
QLineEdit {
font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;
padding-left: 7px;
background-color: #CCCCCC;
border-width: 0;
border-top-right-radius: 9px;
border-bottom-right-radius: 9px;
color: #333333;
font-size: 12px;
}
QPushButton#searchButton {
background: url(resources/styles/search.svg);
background-repeat: none;
background-position: left center;
background-origin: content;
padding-left: 7px;
background-color: #CCCCCC;
border-width: 0;
border-top-left-radius: 9px;
border-bottom-left-radius: 9px;
}
QPushButton#revealLogButton {
background: url(resources/styles/txt-file.svg);
background-repeat: none;
background-position: left center;
background-origin: content;
padding-left: 10px;
background-color: #333333;
color: #BBBBBB;
border-width: 0;
border-radius: 9px;
font-size: 11px;
}
QCheckBox {
font-family: Helvetica, Arial, sans-serif;
}
QCheckBox::indicator:unchecked {
image: url(resources/styles/unchecked.svg);
}
QCheckBox::indicator:checked {
image: url(resources/styles/checked.svg);
}

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="12px" height="12px" viewBox="0 0 12 12" enable-background="new 0 0 12 12" xml:space="preserve">
<g>
<path d="M10.716,11.573c-0.228,0-0.449-0.094-0.603-0.254L7.815,9.028C7.032,9.57,6.094,9.858,5.143,9.858
c-2.606,0-4.716-2.11-4.716-4.716s2.11-4.716,4.716-4.716s4.716,2.11,4.716,4.716c0,0.951-0.288,1.889-0.831,2.673l2.297,2.297
c0.154,0.154,0.248,0.375,0.248,0.603C11.573,11.185,11.185,11.573,10.716,11.573z M5.143,2.142c-1.655,0-3.001,1.346-3.001,3.001
s1.346,3.001,3.001,3.001s3.001-1.346,3.001-3.001S6.797,2.142,5.143,2.142z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 929 B

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="12.927px" height="15.106px" viewBox="0 0 12.927 15.106" enable-background="new 0 0 12.927 15.106" xml:space="preserve">
<g>
<path fill="#CCCCCC" d="M12.148,13.667c0,0.503-0.408,0.911-0.911,0.911H0.911C0.408,14.578,0,14.17,0,13.667V0.911
C0,0.408,0.408,0,0.911,0h6.074c0.503,0,1.206,0.294,1.557,0.646l2.961,2.961c0.351,0.351,0.646,1.054,0.646,1.557V13.667z
M10.934,13.363V6.074H6.985c-0.503,0-0.911-0.408-0.911-0.911V1.215H1.215v12.148H10.934z M9.719,8.2
c0,0.171-0.133,0.304-0.304,0.304H2.733C2.562,8.504,2.43,8.371,2.43,8.2V7.593c0-0.171,0.133-0.304,0.304-0.304h6.682
c0.171,0,0.304,0.133,0.304,0.304V8.2z M9.719,10.63c0,0.171-0.133,0.304-0.304,0.304H2.733c-0.171,0-0.304-0.133-0.304-0.304
v-0.607c0-0.171,0.133-0.304,0.304-0.304h6.682c0.171,0,0.304,0.133,0.304,0.304V10.63z M10.857,4.859
c-0.057-0.161-0.142-0.323-0.208-0.389L7.678,1.5C7.612,1.433,7.45,1.348,7.289,1.291v3.568H10.857z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="17.186px" height="14px" viewBox="0 0 17.186 14" enable-background="new 0 0 17.186 14" xml:space="preserve">
<g>
<path fill="#666666" d="M14,11.435C14,12.851,12.851,14,11.435,14H2.565C1.149,14,0,12.851,0,11.435V2.565C0,1.149,1.149,0,2.565,0
h8.869C12.851,0,14,1.149,14,2.565V11.435z M12,2.565C12,2.253,11.747,2,11.435,2H2.565C2.253,2,2,2.253,2,2.565v8.869
C2,11.747,2.253,12,2.565,12h8.869C11.747,12,12,11.747,12,11.435V2.565z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 825 B

View file

@ -0,0 +1,34 @@
//
// AbstractLoggerInterface.h
// interface
//
// Created by Stojce Slavkovski on 12/22/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__AbstractLoggerInterface__
#define __interface__AbstractLoggerInterface__
#include <QtCore/QObject>
#include <QString>
#include <QStringList>
class AbstractLoggerInterface : public QObject {
Q_OBJECT
public:
inline bool extraDebugging() { return _extraDebugging; };
inline void setExtraDebugging(bool debugging) { _extraDebugging = debugging; };
virtual void addMessage(QString) = 0;
virtual QStringList getLogData() = 0;
virtual void locateLog() = 0;
signals:
void logReceived(QString message);
private:
bool _extraDebugging;
};
#endif /* defined(__interface__AbstractLoggerInterface__) */

View file

@ -51,7 +51,6 @@
#include "Application.h"
#include "DataServerClient.h"
#include "InterfaceVersion.h"
#include "LogDisplay.h"
#include "Menu.h"
#include "Swatch.h"
#include "Util.h"
@ -89,7 +88,7 @@ const float MIRROR_REARVIEW_BODY_DISTANCE = 1.f;
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) {
fprintf(stdout, "%s", message.toLocal8Bit().constData());
LogDisplay::instance.addMessage(message.toLocal8Bit().constData());
Application::getInstance()->getLogger()->addMessage(message.toLocal8Bit().constData());
}
Application::Application(int& argc, char** argv, timeval &startup_time) :
@ -142,7 +141,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_recentMaxPackets(0),
_resetRecentMaxPacketsSoon(true),
_swatch(NULL),
_pasteMode(false)
_pasteMode(false),
_logger(new FileLogger())
{
_applicationStartupTime = startup_time;
@ -268,7 +268,8 @@ Application::~Application() {
VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown
Menu::getInstance()->deleteLater();
delete _logger;
delete _settings;
delete _followMode;
delete _glWidget;
@ -1357,7 +1358,7 @@ void Application::idle() {
// Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
// details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing
// details normally.
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging);
bool showWarnings = getLogger()->extraDebugging();
PerformanceWarning warn(showWarnings, "Application::idle()");
timeval check;
@ -2694,7 +2695,7 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node
return;
}
bool wantExtraDebugging = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging);
bool wantExtraDebugging = getLogger()->extraDebugging();
// These will be the same for all servers, so we can set them up once and then reuse for each server we send to.
_voxelQuery.setWantLowResMoving(!Menu::getInstance()->isOptionChecked(MenuOption::DisableLowRes));
@ -3378,11 +3379,6 @@ void Application::displayOverlay() {
if (Menu::getInstance()->isOptionChecked(MenuOption::CoverageMap)) {
renderCoverageMap();
}
if (Menu::getInstance()->isOptionChecked(MenuOption::Log)) {
LogDisplay::instance.render(_glWidget->width(), _glWidget->height());
}
// Show chat entry field
if (_chatEntryOn) {
@ -4385,7 +4381,7 @@ void* Application::networkReceive(void* args) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::networkReceive()... _voxelProcessor.queueReceivedPacket()");
bool wantExtraDebugging = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging);
bool wantExtraDebugging = app->getLogger()->extraDebugging();
if (wantExtraDebugging && app->_incomingPacket[0] == PACKET_TYPE_VOXEL_DATA) {
int numBytesPacketHeader = numBytesForPacketHeader(app->_incomingPacket);
unsigned char* dataAt = app->_incomingPacket + numBytesPacketHeader;
@ -4510,7 +4506,7 @@ void Application::loadScript() {
void Application::toggleLogDialog() {
if (! _logDialog) {
_logDialog = new LogDialog(_glWidget);
_logDialog = new LogDialog(_glWidget, getLogger());
_logDialog->show();
} else {
_logDialog->close();

View file

@ -69,6 +69,7 @@
#include "ui/RearMirrorTools.h"
#include "ui/LodToolsDialog.h"
#include "ui/LogDialog.h"
#include "FileLogger.h"
#include "ParticleTreeRenderer.h"
#include "ParticleEditHandle.h"
#include "ControllerScriptingInterface.h"
@ -201,7 +202,8 @@ public:
VoxelShader& getVoxelShader() { return _voxelShader; }
PointShader& getPointShader() { return _pointShader; }
FileLogger* getLogger() { return _logger; }
glm::vec2 getViewportDimensions() const{ return glm::vec2(_glWidget->width(),_glWidget->height()); }
NodeToJurisdictionMap& getVoxelServerJurisdictions() { return _voxelServerJurisdictions; }
NodeToJurisdictionMap& getParticleServerJurisdictions() { return _particleServerJurisdictions; }
@ -508,6 +510,8 @@ private:
std::vector<Avatar*> _avatarFades;
ControllerScriptingInterface _controllerScriptingInterface;
QPointer<LogDialog> _logDialog;
FileLogger* _logger;
};
#endif /* defined(__interface__Application__) */

View file

@ -0,0 +1,44 @@
//
// FileLogger.cpp
// hifi
//
// Created by Stojce Slavkovski on 12/22/13.
//
//
#include "FileLogger.h"
#include "HifiSockAddr.h"
#include <FileUtils.h>
#include <QDateTime>
#include <QFile>
#include <QDir>
#include <QDesktopServices>
FileLogger::FileLogger() : _logData(NULL) {
setExtraDebugging(false);
_fileName = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
QDir logDir(_fileName);
if (!logDir.exists(_fileName)) {
logDir.mkdir(_fileName);
}
QHostAddress clientAddress = QHostAddress(getHostOrderLocalAddress());
QDateTime now = QDateTime::currentDateTime();
_fileName.append(QString("/hifi-log_%1_%2.txt").arg(clientAddress.toString(), now.toString("yyyy-MM-dd_hh.mm.ss")));
}
void FileLogger::addMessage(QString message) {
QMutexLocker locker(&_mutex);
emit logReceived(message);
_logData.append(message);
QFile file(_fileName);
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
QTextStream out(&file);
out << message;
}
}
void FileLogger::locateLog() {
FileUtils::LocateFile(_fileName);
}

View file

@ -0,0 +1,32 @@
//
// FileLogger.h
// hifi
//
// Created by Stojce Slavkovski on 12/22/13.
//
//
#ifndef hifi_FileLogger_h
#define hifi_FileLogger_h
#include "AbstractLoggerInterface.h"
#include <QMutex>
class FileLogger : public AbstractLoggerInterface {
Q_OBJECT
public:
FileLogger();
virtual void addMessage(QString);
virtual QStringList getLogData() { return _logData; };
virtual void locateLog();
private:
QStringList _logData;
QString _fileName;
QMutex _mutex;
};
#endif

View file

@ -1,291 +0,0 @@
//
// LogDisplay.cpp
// interface
//
// Created by Tobias Schwinger on 4/14/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <QStringList>
#include "LogDisplay.h"
#include "Util.h"
using namespace std;
FILE* const LogDisplay::DEFAULT_STREAM = 0l;
//
// Singleton constructor
//
LogDisplay LogDisplay::instance;
//
// State management
//
LogDisplay::LogDisplay() :
_textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT),
_stream(DEFAULT_STREAM),
_chars(0l),
_lines(0l),
_logWidth(DEFAULT_CONSOLE_WIDTH) {
pthread_mutex_init(& _mutex, 0l);
// allocate twice as much (so we have spare space for a copy not to block
// logging from other threads during 'render')
_chars = new char[CHARACTER_BUFFER_SIZE * 2];
_charsEnd = _chars + CHARACTER_BUFFER_SIZE;
_lines = new char*[LINE_BUFFER_SIZE * 2];
_linesEnd = _lines + LINE_BUFFER_SIZE;
// initialize the log to all empty lines
_chars[0] = '\0';
_writePos = _chars;
_writeLineStartPos = _chars;
_lastLinePos = _lines;
_writtenInLine = 0;
memset(_lines, 0, LINE_BUFFER_SIZE * sizeof(char*));
setCharacterSize(DEFAULT_CHAR_WIDTH, DEFAULT_CHAR_HEIGHT);
}
LogDisplay::~LogDisplay() {
delete[] _chars;
delete[] _lines;
}
void LogDisplay::setStream(FILE* stream) {
pthread_mutex_lock(& _mutex);
_stream = stream;
pthread_mutex_unlock(& _mutex);
}
void LogDisplay::setLogWidth(unsigned pixels) {
pthread_mutex_lock(& _mutex);
_logWidth = pixels;
_lineLength = _logWidth / _charWidth;
pthread_mutex_unlock(& _mutex);
}
void LogDisplay::setCharacterSize(unsigned width, unsigned height) {
pthread_mutex_lock(& _mutex);
_charWidth = width;
_charHeight = height;
_lineLength = _logWidth / _charWidth;
pthread_mutex_unlock(& _mutex);
}
//
// Logging
//
void LogDisplay::addMessage(const char* ptr) {
pthread_mutex_lock(& _mutex);
emit logReceived(ptr);
// T-pipe, if requested
if (_stream != 0l) {
fprintf(_stream, "%s", ptr);
}
while (*ptr != '\0') {
// process the characters
char c = *ptr++;
if (c == '\t') {
// found TAB -> write SPACE
c = ' ';
} else if (c == '\n') {
// found LF -> write NUL (c == '\0' tells us to wrap, below)
c = '\0';
}
*_writePos++ = c;
if (_writePos == _charsEnd) {
// reached the end of the circular character buffer? -> start over
_writePos = _chars;
}
if (c == '\0') {
// new line? store its start to the line buffer and mark next line as empty
++_lastLinePos;
if (_lastLinePos == _linesEnd) {
_lastLinePos = _lines;
_lastLinePos[1] = 0l;
} else if (_lastLinePos + 1 != _linesEnd) {
_lastLinePos[1] = 0l;
} else {
_lines[0] = 0l;
}
*_lastLinePos = _writeLineStartPos;
// debug mode: make sure all line pointers we write here are valid
assert(! (_lastLinePos < _lines || _lastLinePos >= _linesEnd));
assert(! (*_lastLinePos < _chars || *_lastLinePos >= _charsEnd));
// terminate line, unless done already
if (c != '\0') {
*_writePos++ = '\0';
if (_writePos == _charsEnd) {
_writePos = _chars;
}
}
// remember start position in character buffer for next line and reset character count
_writeLineStartPos = _writePos;
}
}
pthread_mutex_unlock(& _mutex);
}
QStringList LogDisplay::getLogData() {
// wait for adding new log data whilr iterating over _lines
pthread_mutex_lock(& _mutex);
QStringList list;
int i = 0;
while (_lines[i] != *_lastLinePos) {
list.append(_lines[i++]);
}
pthread_mutex_unlock(& _mutex);
return list;
}
//
// Rendering
//
void LogDisplay::render(unsigned screenWidth, unsigned screenHeight) {
// rendering might take some time, so create a local copy of the portion we need
// instead of having to hold the mutex all the time
pthread_mutex_lock(& _mutex);
// determine number of visible lines (integer division rounded up)
unsigned showLines = (screenHeight + _charHeight - 1) / _charHeight;
char** lastLine = _lastLinePos;
char** firstLine = _lastLinePos;
if (! *lastLine) {
// empty log
pthread_mutex_unlock(& _mutex);
return;
}
// scan for first line
for (int n = 2; n <= showLines; ++n) {
char** prevFirstLine = firstLine;
--firstLine;
if (firstLine < _lines) {
firstLine = _linesEnd - 1;
}
if (! *firstLine) {
firstLine = prevFirstLine;
showLines = n - 1;
break;
}
// debug mode: make sure all line pointers we find here are valid
assert(! (firstLine < _lines || firstLine >= _linesEnd));
assert(! (*firstLine < _chars || *firstLine >= _charsEnd));
}
// copy the line buffer portion into a contiguous region at _linesEnd
if (firstLine <= lastLine) {
memcpy(_linesEnd, firstLine, showLines * sizeof(char*));
} else {
unsigned atEnd = _linesEnd - firstLine;
memcpy(_linesEnd, firstLine, atEnd * sizeof(char*));
memcpy(_linesEnd + atEnd, _lines, (showLines - atEnd) * sizeof(char*));
}
// copy relevant char buffer portion and determine information to remap the pointers
char* firstChar = *firstLine;
char* lastChar = *lastLine + strlen(*lastLine) + 1;
ptrdiff_t charOffset = _charsEnd - firstChar, charOffsetBeforeFirst = 0;
if (firstChar <= lastChar) {
memcpy(_charsEnd, firstChar, lastChar - firstChar + 1);
} else {
unsigned atEnd = _charsEnd - firstChar;
memcpy(_charsEnd, firstChar, atEnd);
memcpy(_charsEnd + atEnd, _chars, lastChar + 1 - _chars);
charOffsetBeforeFirst = _charsEnd + atEnd - _chars;
}
// determine geometry information from font metrics
QFontMetrics const& fontMetrics = _textRenderer.metrics();
int yStep = fontMetrics.lineSpacing();
// scale
float xScale = float(_charWidth) / fontMetrics.width('*');
float yScale = float(_charHeight) / yStep;
// scaled translation
int xStart = int((screenWidth - _logWidth) / xScale);
int yStart = screenHeight / yScale - fontMetrics.descent();
// first line to render
char** line = _linesEnd + showLines;
// ok, now the lock can be released - we have all we need
// and won't hold it while talking to OpenGL
pthread_mutex_unlock(& _mutex);
glPushMatrix();
glScalef(xScale, yScale, 1.0f);
glColor3ub(GLubyte(TEXT_COLOR >> 16),
GLubyte((TEXT_COLOR >> 8) & 0xff),
GLubyte(TEXT_COLOR & 0xff));
for (int y = yStart; y > 0; y -= yStep) {
// debug mode: check line pointer is valid
assert(! (line < _linesEnd || line >= _linesEnd + (_linesEnd - _lines)));
// get character pointer
if (--line < _linesEnd) {
break;
}
char* chars = *line;
// debug mode: check char pointer we find is valid
assert(! (chars < _chars || chars >= _charsEnd));
// remap character pointer it to copied buffer
chars += chars >= firstChar ? charOffset : charOffsetBeforeFirst;
// debug mode: check char pointer is still valid (in new range)
assert(! (chars < _charsEnd || chars >= _charsEnd + (_charsEnd - _chars)));
// render the string
_textRenderer.draw(xStart, y, chars);
//fprintf(stderr, "LogDisplay::render, message = \"%s\"\n", chars);
}
glPopMatrix();
}

View file

@ -1,82 +0,0 @@
//
// LogDisplay.h
// interface
//
// Created by Tobias Schwinger on 4/14/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__LogDisplay__
#define __interface__LogDisplay__
#include <stdarg.h>
#include <pthread.h>
#include "ui/TextRenderer.h"
class LogDisplay : public QObject {
Q_OBJECT
public:
static LogDisplay instance;
void render(unsigned screenWidth, unsigned screenHeight);
// log formatted message
void addMessage(const char* message);
// settings
static unsigned const TEXT_COLOR = 0xb299ff; // text foreground color (bytes, RGB)
static FILE* const DEFAULT_STREAM; // = stdout; // stream to also log to (defined in .cpp)
static unsigned const DEFAULT_CHAR_WIDTH = 5; // width of a single character
static unsigned const DEFAULT_CHAR_HEIGHT = 16; // height of a single character
static unsigned const DEFAULT_CONSOLE_WIDTH = 400; // width of the (right-aligned) log console
void setStream(FILE* stream);
void setLogWidth(unsigned pixels);
void setCharacterSize(unsigned width, unsigned height);
// limits
static unsigned const CHARACTER_BUFFER_SIZE = 16384; // number of character that are buffered
static unsigned const LINE_BUFFER_SIZE = 256; // number of lines that are buffered
static unsigned const MAX_MESSAGE_LENGTH = 512; // maximum number of characters for a message
QStringList getLogData();
signals:
void logReceived(QString message);
private:
// use static 'instance' to access the single instance
LogDisplay();
~LogDisplay();
// don't copy/assign
LogDisplay(LogDisplay const&); // = delete;
LogDisplay& operator=(LogDisplay const&); // = delete;
TextRenderer _textRenderer;
FILE* _stream; // FILE as secondary destination for log messages
char* _chars; // character buffer base address
char* _charsEnd; // character buffer, exclusive end
char** _lines; // line buffer base address
char** _linesEnd; // line buffer, exclusive end
char* _writePos; // character position to write to
char* _writeLineStartPos; // character position where line being written starts
char** _lastLinePos; // last line in the log
unsigned _writtenInLine; // character counter for line wrapping
unsigned _lineLength; // number of characters before line wrap
unsigned _logWidth; // width of the log in pixels
unsigned _charWidth; // width of a character in pixels
unsigned _charHeight; // height of a character in pixels
pthread_mutex_t _mutex;
};
#endif

View file

@ -499,8 +499,6 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio);
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio);
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::ExtraDebugging);
addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel,
Qt::CTRL | Qt::SHIFT | Qt::Key_V,
this,

View file

@ -184,7 +184,6 @@ namespace MenuOption {
const QString EchoServerAudio = "Echo Server Audio";
const QString EchoLocalAudio = "Echo Local Audio";
const QString ExportVoxels = "Export Voxels";
const QString ExtraDebugging = "Extra Debugging";
const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes";
const QString HeadMouse = "Head Mouse";
const QString FaceMode = "Cycle Face Mode";

View file

@ -13,7 +13,7 @@
#include <PerfStat.h>
#include <SharedUtil.h>
#include "Menu.h"
#include "Application.h"
#include "VoxelHideShowThread.h"
VoxelHideShowThread::VoxelHideShowThread(VoxelSystem* theSystem) :
@ -30,8 +30,8 @@ bool VoxelHideShowThread::process() {
_theSystem->checkForCulling();
uint64_t end = usecTimestampNow();
uint64_t elapsed = end - start;
bool showExtraDebugging = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging);
bool showExtraDebugging = Application::getInstance()->getLogger()->extraDebugging();
if (showExtraDebugging && elapsed > USECS_PER_FRAME) {
printf("VoxelHideShowThread::process()... checkForCulling took %llu\n", elapsed);
}

View file

@ -19,7 +19,8 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, uns
"VoxelPacketProcessor::processPacket()");
const int WAY_BEHIND = 300;
if (packetsToProcessCount() > WAY_BEHIND && Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) {
if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) {
qDebug("VoxelPacketProcessor::processPacket() packets to process=%d\n", packetsToProcessCount());
}
ssize_t messageLength = packetLength;

View file

@ -612,7 +612,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
lockTree();
VoxelPacketData packetData(packetIsCompressed);
packetData.loadFinalizedContent(dataAt, sectionLength);
if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) {
if (Application::getInstance()->getLogger()->extraDebugging()) {
qDebug("VoxelSystem::parseData() ... Got Packet Section"
" color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d"
" subsection:%d sectionLength:%d uncompressed:%d\n",
@ -973,7 +973,7 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo
// not render these Voxels. We need to think about ways to keep the entire scene intact but maybe lower quality
// possibly shifting down to lower LOD or something. This debug message is to help identify, if/when/how this
// state actually occurs.
if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) {
if (Application::getInstance()->getLogger()->extraDebugging()) {
qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n");
}
return 0;
@ -1964,7 +1964,7 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) {
setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY);
}
bool extraDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging);
bool extraDebugDetails = Application::getInstance()->getLogger()->extraDebugging();
if (extraDebugDetails) {
qDebug("hideOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld\n",
args.nodesScanned, args.nodesRemoved, args.nodesInside,

View file

@ -12,64 +12,158 @@
#include "SharedUtil.h"
#include "ui/LogDialog.h"
#include "LogDisplay.h"
const int INITIAL_WIDTH = 720;
const int TOP_BAR_HEIGHT = 46;
const int INITIAL_WIDTH = 720;
const int MINIMAL_WIDTH = 570;
const int ELEMENT_MARGIN = 7;
const int ELEMENT_HEIGHT = 32;
const int SEARCH_BUTTON_LEFT = 25;
const int SEARCH_BUTTON_WIDTH = 20;
const int SEARCH_TEXT_WIDTH = 240;
const int CHECKBOX_MARGIN = 12;
const int CHECKBOX_WIDTH = 140;
const int REVEAL_BUTTON_WIDTH = 122;
const float INITIAL_HEIGHT_RATIO = 0.6f;
const QString HIGHLIGHT_COLOR = "#3366CC";
int cursorMeta = qRegisterMetaType<QTextCursor>("QTextCursor");
int blockMeta = qRegisterMetaType<QTextBlock>("QTextBlock");
int qTextCursorMeta = qRegisterMetaType<QTextCursor>("QTextCursor");
int qTextBlockMeta = qRegisterMetaType<QTextBlock>("QTextBlock");
LogDialog::LogDialog(QWidget* parent) : QDialog(parent, Qt::Dialog) {
LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : QDialog(parent, Qt::Dialog) {
_logger = logger;
setWindowTitle("Log");
_logTextBox = new QPlainTextEdit(this);
_logTextBox->setReadOnly(true);
_logTextBox->show();
setAttribute(Qt::WA_DeleteOnClose);
switchToResourcesParentIfRequired();
QFile styleSheet("resources/styles/log_dialog.qss");
if (styleSheet.open(QIODevice::ReadOnly)) {
setStyleSheet(styleSheet.readAll());
}
initControls();
QDesktopWidget desktop;
QRect screen = desktop.screenGeometry();
resize(INITIAL_WIDTH, static_cast<int>(screen.height() * INITIAL_HEIGHT_RATIO));
move(screen.center() - rect().center());
setAttribute(Qt::WA_DeleteOnClose);
setMinimumWidth(MINIMAL_WIDTH);
}
LogDialog::~LogDialog() {
deleteLater();
}
void LogDialog::showEvent(QShowEvent *e) {
void LogDialog::initControls() {
int left;
_searchButton = new QPushButton(this);
// set object name for css styling
_searchButton->setObjectName("searchButton");
left = SEARCH_BUTTON_LEFT;
_searchButton->setGeometry(left, ELEMENT_MARGIN, SEARCH_BUTTON_WIDTH, ELEMENT_HEIGHT);
left += SEARCH_BUTTON_WIDTH;
_searchButton->show();
connect(_searchButton, SIGNAL(clicked()), SLOT(handleSearchButton()));
_searchTextBox = new QLineEdit(this);
// disable blue outline in Mac
_searchTextBox->setAttribute(Qt::WA_MacShowFocusRect, false);
_searchTextBox->setGeometry(left, ELEMENT_MARGIN, SEARCH_TEXT_WIDTH, ELEMENT_HEIGHT);
left += SEARCH_TEXT_WIDTH + CHECKBOX_MARGIN;
_searchTextBox->show();
connect(_searchTextBox, SIGNAL(textChanged(QString)), SLOT(handleSearchTextChanged(QString)));
_extraDebuggingBox = new QCheckBox("Extra debugging", this);
_extraDebuggingBox->setGeometry(left, ELEMENT_MARGIN, CHECKBOX_WIDTH, ELEMENT_HEIGHT);
if (_logger->extraDebugging()) {
_extraDebuggingBox->setCheckState(Qt::Checked);
}
_extraDebuggingBox->show();
connect(_extraDebuggingBox, SIGNAL(stateChanged(int)), SLOT(handleExtraDebuggingCheckbox(int)));
_revealLogButton = new QPushButton("Reveal log file", this);
// set object name for css styling
_revealLogButton->setObjectName("revealLogButton");
_revealLogButton->show();
connect(_revealLogButton, SIGNAL(clicked()), SLOT(handleRevealButton()));
_logTextBox = new QPlainTextEdit(this);
_logTextBox->setReadOnly(true);
_logTextBox->show();
_highlighter = new KeywordHighlighter(_logTextBox->document());
}
void LogDialog::showEvent(QShowEvent*) {
connect(_logger, SIGNAL(logReceived(QString)), this, SLOT(appendLogLine(QString)));
showLogData();
}
void LogDialog::resizeEvent(QResizeEvent*) {
_logTextBox->setGeometry(0, TOP_BAR_HEIGHT, width(), height() - TOP_BAR_HEIGHT);
_revealLogButton->setGeometry(width() - ELEMENT_MARGIN - REVEAL_BUTTON_WIDTH,
ELEMENT_MARGIN,
REVEAL_BUTTON_WIDTH,
ELEMENT_HEIGHT);
}
void LogDialog::appendLogLine(QString logLine) {
if (isVisible()) {
pthread_mutex_lock(& _mutex);
if (logLine.contains(_searchTerm, Qt::CaseInsensitive)) {
_logTextBox->appendPlainText(logLine.simplified());
}
pthread_mutex_unlock(& _mutex);
_logTextBox->ensureCursorVisible();
}
}
void LogDialog::handleSearchButton() {
_searchTextBox->setFocus();
}
void LogDialog::handleRevealButton() {
_logger->locateLog();
}
void LogDialog::handleExtraDebuggingCheckbox(const int state) {
_logger->setExtraDebugging(state != 0);
}
void LogDialog::handleSearchTextChanged(const QString searchText) {
_searchTerm = searchText;
_highlighter->keyword = searchText;
showLogData();
}
void LogDialog::showLogData() {
_logTextBox->clear();
pthread_mutex_lock(& _mutex);
QStringList _logData = LogDisplay::instance.getLogData();
connect(&LogDisplay::instance, &LogDisplay::logReceived, this, &LogDialog::appendLogLine);
for(int i = 0; i < _logData.size(); ++i) {
QStringList _logData = _logger->getLogData();
for (int i = 0; i < _logData.size(); ++i) {
appendLogLine(_logData[i]);
}
pthread_mutex_unlock(& _mutex);
}
void LogDialog::resizeEvent(QResizeEvent *e) {
_logTextBox->resize(width(), height());
KeywordHighlighter::KeywordHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent), keywordFormat() {
keywordFormat.setForeground(QColor(HIGHLIGHT_COLOR));
}
void LogDialog::appendLogLine(QString logLine) {
if (isVisible()) {
pthread_mutex_lock(& _mutex);
_logTextBox->appendPlainText(logLine.simplified());
pthread_mutex_unlock(& _mutex);
_logTextBox->ensureCursorVisible();
void KeywordHighlighter::highlightBlock(const QString &text) {
if (keyword.isNull() || keyword.isEmpty()) {
return;
}
int index = text.indexOf(keyword, 0, Qt::CaseInsensitive);
int length = keyword.length();
while (index >= 0) {
setFormat(index, length, keywordFormat);
index = text.indexOf(keyword, index + length, Qt::CaseInsensitive);
}
}

View file

@ -11,25 +11,62 @@
#include <QDialog>
#include <QPlainTextEdit>
#include <QLineEdit>
#include <QPushButton>
#include <QCheckBox>
#include <QSyntaxHighlighter>
#include "AbstractLoggerInterface.h"
class KeywordHighlighter : public QSyntaxHighlighter {
Q_OBJECT
public:
KeywordHighlighter(QTextDocument *parent = 0);
QString keyword;
protected:
void highlightBlock(const QString &text);
private:
QTextCharFormat keywordFormat;
};
class LogDialog : public QDialog {
Q_OBJECT
public:
LogDialog(QWidget* parent);
LogDialog(QWidget*, AbstractLoggerInterface*);
~LogDialog();
public slots:
void appendLogLine(QString logLine);
private slots:
void handleSearchButton();
void handleRevealButton();
void handleExtraDebuggingCheckbox(const int);
void handleSearchTextChanged(const QString);
protected:
void resizeEvent(QResizeEvent* e);
void showEvent(QShowEvent* e);
void resizeEvent(QResizeEvent*);
void showEvent(QShowEvent*);
private:
QPushButton* _searchButton;
QLineEdit* _searchTextBox;
QCheckBox* _extraDebuggingBox;
QPushButton* _revealLogButton;
QPlainTextEdit* _logTextBox;
pthread_mutex_t _mutex;
QString _searchTerm;
KeywordHighlighter* _highlighter;
AbstractLoggerInterface* _logger;
void initControls();
void showLogData();
};
#endif

View file

@ -0,0 +1,56 @@
//
// FileUtils.cpp
// hifi
//
// Created by Stojce Slavkovski on 12/23/13.
//
//
#include "FileUtils.h"
#include <QtCore>
#include <QDesktopServices>
void FileUtils::LocateFile(QString filePath) {
// adopted from
// http://stackoverflow.com/questions/3490336/how-to-reveal-in-finder-or-show-in-explorer-with-qt
// and
// http://lynxline.com/show-in-finder-show-in-explorer/
QFileInfo fileInfo(filePath);
if (!fileInfo.exists()) {
return;
}
bool success = false;
#ifdef Q_OS_MAC
QStringList args;
args << "-e";
args << "tell application \"Finder\"";
args << "-e";
args << "activate";
args << "-e";
args << "select POSIX file \"" + fileInfo.absoluteFilePath().toUtf8() + "\"";
args << "-e";
args << "end tell";
success = QProcess::startDetached("osascript", args);
#endif
#ifdef Q_OS_WIN
QStringList args;
// don't send `select` command switch if `filePath` is folder
if (!fileInfo.isDir()) {
args << "/select,";
}
args += QDir::toNativeSeparators(fileInfo.absoluteFilePath().toUtf8());
success = QProcess::startDetached("explorer", args);
#endif
// fallback, open enclosing folder
if (!success) {
const QString folder = fileInfo.path();
QDesktopServices::openUrl(QUrl::fromLocalFile(folder));
}
}

View file

@ -0,0 +1,21 @@
//
// FileUtils.h
// hifi
//
// Created by Stojce Slavkovski on 12/23/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef hifi_FileUtils_h
#define hifi_FileUtils_h
#include <QString>
class FileUtils {
public:
static void LocateFile(QString);
};
#endif