Improves gopher map rendering with icons and monospace font, adds status bar with more infos, fixes file dialog for older qt versions.
|
@ -11,6 +11,7 @@ Kristall Changelog
|
|||
- Added "go to home" menu icogin
|
||||
- Added support for video/* and audio/* via QMediaPlayer
|
||||
- Added support for file:// scheme
|
||||
- Added status bar with loading time, file size and mime type
|
||||
|
||||
== 0.1
|
||||
- Initial release
|
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 97 KiB |
|
@ -4,6 +4,8 @@
|
|||
#include "geminirenderer.hpp"
|
||||
#include "settingsdialog.hpp"
|
||||
#include "gophermaprenderer.hpp"
|
||||
#include "ioutil.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <QTabWidget>
|
||||
#include <QMenu>
|
||||
|
@ -67,6 +69,8 @@ void BrowserTab::navigateTo(const QUrl &url, PushToHistory mode)
|
|||
return;
|
||||
}
|
||||
|
||||
this->timer.start();
|
||||
|
||||
this->current_location = url;
|
||||
this->ui->url_bar->setText(url.toString());
|
||||
|
||||
|
@ -233,23 +237,6 @@ void BrowserTab::on_requestFailed(const QString &reason)
|
|||
this->setErrorMessage(QString("Request failed:\n%1").arg(reason));
|
||||
}
|
||||
|
||||
QString size_human(int size)
|
||||
{
|
||||
float num = size;
|
||||
QStringList list;
|
||||
list << "KB" << "MB" << "GB" << "TB";
|
||||
|
||||
QStringListIterator i(list);
|
||||
QString unit("bytes");
|
||||
|
||||
while(num >= 1024.0 && i.hasNext())
|
||||
{
|
||||
unit = i.next();
|
||||
num /= 1024.0;
|
||||
}
|
||||
return QString().setNum(num,'f',2)+" "+unit;
|
||||
}
|
||||
|
||||
void BrowserTab::on_requestComplete(const QByteArray &data, const QString &mime)
|
||||
{
|
||||
qDebug() << "Loaded" << data.length() << "bytes of type" << mime;
|
||||
|
@ -339,7 +326,7 @@ Use the *File* menu to save the file to your local disk or navigate somewhere el
|
|||
Info:
|
||||
MIME Type: %1
|
||||
File Size: %2
|
||||
)md").arg(mime).arg(size_human(data.size())));
|
||||
)md").arg(mime).arg(IoUtil::size_human(data.size())));
|
||||
}
|
||||
|
||||
assert((document != nullptr) == (doc_type == Text));
|
||||
|
@ -356,6 +343,8 @@ File Size: %2
|
|||
QString title = this->current_location.toString();
|
||||
emit this->titleChanged(title);
|
||||
|
||||
emit this->fileLoaded(data.size(), mime, this->timer.elapsed());
|
||||
|
||||
this->successfully_loaded = true;
|
||||
|
||||
if(this->push_to_history_after_load) {
|
||||
|
@ -520,10 +509,15 @@ void BrowserTab::on_text_browser_anchorClicked(const QUrl &url)
|
|||
|
||||
void BrowserTab::on_text_browser_highlighted(const QUrl &url)
|
||||
{
|
||||
QUrl real_url = url;
|
||||
if(real_url.isRelative())
|
||||
real_url = this->current_location.resolved(url);
|
||||
this->mainWindow->setUrlPreview(real_url);
|
||||
if(url.isValid()) {
|
||||
QUrl real_url = url;
|
||||
if(real_url.isRelative())
|
||||
real_url = this->current_location.resolved(url);
|
||||
this->mainWindow->setUrlPreview(real_url);
|
||||
}
|
||||
else {
|
||||
this->mainWindow->setUrlPreview(QUrl { });
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserTab::on_stop_button_clicked()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QGraphicsScene>
|
||||
#include <QTextDocument>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "geminiclient.hpp"
|
||||
#include "documentoutlinemodel.hpp"
|
||||
|
@ -54,6 +55,7 @@ public:
|
|||
signals:
|
||||
void titleChanged(QString const & title);
|
||||
void locationChanged(QUrl const & url);
|
||||
void fileLoaded(qint64 fileSize, QString const & mime, int msec);
|
||||
|
||||
private slots:
|
||||
void on_url_bar_returnPressed();
|
||||
|
@ -123,6 +125,7 @@ public:
|
|||
|
||||
QByteArray current_buffer;
|
||||
QString current_mime;
|
||||
QElapsedTimer timer;
|
||||
};
|
||||
|
||||
#endif // BROWSERTAB_HPP
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QTextImageFormat>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QImage>
|
||||
|
||||
//Canonical Types
|
||||
//0 Text File
|
||||
|
@ -31,11 +32,11 @@
|
|||
std::unique_ptr<QTextDocument> GophermapRenderer::render(const QByteArray &input, const QUrl &root_url, const DocumentStyle &themed_style)
|
||||
{
|
||||
QTextCharFormat standard;
|
||||
standard.setFont(themed_style.standard_font);
|
||||
standard.setForeground(themed_style.standard_color);
|
||||
standard.setFont(themed_style.preformatted_font);
|
||||
standard.setForeground(themed_style.preformatted_color);
|
||||
|
||||
QTextCharFormat standard_link;
|
||||
standard_link.setFont(themed_style.standard_font);
|
||||
standard_link.setFont(themed_style.preformatted_font);
|
||||
standard_link.setForeground(QBrush(themed_style.internal_link_color));
|
||||
|
||||
QTextCharFormat external_link;
|
||||
|
@ -45,21 +46,34 @@ std::unique_ptr<QTextDocument> GophermapRenderer::render(const QByteArray &input
|
|||
std::unique_ptr<QTextDocument> result = std::make_unique<QTextDocument>();
|
||||
result->setDocumentMargin(themed_style.margin);
|
||||
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/binary"), QVariant::fromValue(QImage(":/icons/gopher/binary.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/directory"), QVariant::fromValue(QImage(":/icons/gopher/directory.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/dns"), QVariant::fromValue(QImage(":/icons/gopher/dns.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/error"), QVariant::fromValue(QImage(":/icons/gopher/error.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/gif"), QVariant::fromValue(QImage(":/icons/gopher/gif.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/html"), QVariant::fromValue(QImage(":/icons/gopher/html.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/image"), QVariant::fromValue(QImage(":/icons/gopher/image.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/mirror"), QVariant::fromValue(QImage(":/icons/gopher/mirror.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/search"), QVariant::fromValue(QImage(":/icons/gopher/search.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/sound"), QVariant::fromValue(QImage(":/icons/gopher/sound.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/telnet"), QVariant::fromValue(QImage(":/icons/gopher/telnet.svg")));
|
||||
result->addResource(QTextDocument::ImageResource, QUrl("gopher/text"), QVariant::fromValue(QImage(":/icons/gopher/text.svg")));
|
||||
|
||||
QTextCursor cursor{result.get()};
|
||||
|
||||
QTextBlockFormat non_list_format = cursor.blockFormat();
|
||||
|
||||
QList<QByteArray> lines = input.split('\n');
|
||||
for (auto const & line : lines)
|
||||
for (auto const &line : lines)
|
||||
{
|
||||
if (line.length() < 2) // skip lines without
|
||||
continue;
|
||||
|
||||
if(line[line.size() - 1] != '\r')
|
||||
if (line[line.size() - 1] != '\r')
|
||||
continue;
|
||||
|
||||
auto items = line.mid(1, line.length() - 2).split('\t');
|
||||
if(items.size() < 2) // invalid
|
||||
if (items.size() < 2) // invalid
|
||||
continue;
|
||||
|
||||
QString icon;
|
||||
|
@ -72,22 +86,22 @@ std::unique_ptr<QTextDocument> GophermapRenderer::render(const QByteArray &input
|
|||
icon = "directory";
|
||||
break;
|
||||
case '2': // CCSO Nameserver
|
||||
icon = "ns";
|
||||
icon = "dns";
|
||||
break;
|
||||
case '3': // Error code returned by a Gopher server to indicate failure
|
||||
icon = "error";
|
||||
break;
|
||||
case '4': // BinHex-encoded file (primarily for Macintosh computers)
|
||||
icon = "binhex";
|
||||
icon = "binary";
|
||||
break;
|
||||
case '5': // DOS file
|
||||
icon = "dos";
|
||||
icon = "binary";
|
||||
break;
|
||||
case '6': // uuencoded file
|
||||
icon = "uuencoded";
|
||||
icon = "binary";
|
||||
break;
|
||||
case '7': // Gopher full-text search
|
||||
icon = "full-text";
|
||||
icon = "search";
|
||||
break;
|
||||
case '8': // Telnet
|
||||
icon = "telnet";
|
||||
|
@ -117,7 +131,7 @@ std::unique_ptr<QTextDocument> GophermapRenderer::render(const QByteArray &input
|
|||
case 's': // Sound file
|
||||
icon = "sound";
|
||||
break;
|
||||
default: // unknown
|
||||
default: // unknown
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -125,34 +139,46 @@ std::unique_ptr<QTextDocument> GophermapRenderer::render(const QByteArray &input
|
|||
|
||||
// 1Phlog /phlog octotherp.org 70 +
|
||||
|
||||
if(line.at(0) == 'i')
|
||||
if (line.at(0) == 'i')
|
||||
{
|
||||
cursor.insertText(title + "\n", standard);
|
||||
}
|
||||
else
|
||||
{
|
||||
QString dst_url;
|
||||
switch(items.size())
|
||||
switch (items.size())
|
||||
{
|
||||
case 0: assert(false);
|
||||
case 1: assert(false);
|
||||
case 0:
|
||||
assert(false);
|
||||
case 1:
|
||||
assert(false);
|
||||
case 2:
|
||||
dst_url = root_url.resolved(QUrl(items.at(1))).toString();
|
||||
break;
|
||||
case 3:
|
||||
dst_url = "gopher://" + items.at(2) + "/" + line.mid(0,1) + items.at(1);
|
||||
dst_url = "gopher://" + items.at(2) + "/" + line.mid(0, 1) + items.at(1);
|
||||
break;
|
||||
default:
|
||||
dst_url = "gopher://" + items.at(2) + ":" + items.at(3) + "/" + line.mid(0,1) + items.at(1);
|
||||
dst_url = "gopher://" + items.at(2) + ":" + items.at(3) + "/" + line.mid(0, 1) + items.at(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if(not QUrl(dst_url).isValid()) {
|
||||
if (not QUrl(dst_url).isValid())
|
||||
{
|
||||
// invlaid URL generated
|
||||
qDebug() << line << dst_url;
|
||||
}
|
||||
|
||||
cursor.insertText("[" + icon + "] ", standard);
|
||||
QTextImageFormat icon_fmt;
|
||||
icon_fmt.setName(QString("gopher/%1").arg(icon));
|
||||
icon_fmt.setVerticalAlignment(QTextImageFormat::AlignTop);
|
||||
|
||||
cursor.insertImage(icon_fmt);
|
||||
|
||||
// cursor.insertImage(QImage(QString(":/icons/gopher/%1.svg").arg(icon)));
|
||||
|
||||
cursor.insertText(" ");
|
||||
// cursor.insertText("[" + icon + "] ", standard);
|
||||
|
||||
QTextCharFormat fmt = standard_link;
|
||||
fmt.setAnchor(true);
|
||||
|
|
|
@ -21,5 +21,17 @@
|
|||
<file>icons/volume-off.svg</file>
|
||||
<file>icons/play.svg</file>
|
||||
<file>icons/pause.svg</file>
|
||||
<file>icons/gopher/binary.svg</file>
|
||||
<file>icons/gopher/directory.svg</file>
|
||||
<file>icons/gopher/dns.svg</file>
|
||||
<file>icons/gopher/error.svg</file>
|
||||
<file>icons/gopher/gif.svg</file>
|
||||
<file>icons/gopher/html.svg</file>
|
||||
<file>icons/gopher/image.svg</file>
|
||||
<file>icons/gopher/mirror.svg</file>
|
||||
<file>icons/gopher/search.svg</file>
|
||||
<file>icons/gopher/sound.svg</file>
|
||||
<file>icons/gopher/telnet.svg</file>
|
||||
<file>icons/gopher/text.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M5.12,5H18.87L17.93,4H5.93L5.12,5M20.54,5.23C20.83,5.57 21,6 21,6.5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V6.5C3,6 3.17,5.57 3.46,5.23L4.84,3.55C5.12,3.21 5.53,3 6,3H18C18.47,3 18.88,3.21 19.15,3.55L20.54,5.23M6,18H12V15H6V18Z" /></svg>
|
After Width: | Height: | Size: 518 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z" /></svg>
|
After Width: | Height: | Size: 431 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M7,9A2,2 0 0,1 5,7A2,2 0 0,1 7,5A2,2 0 0,1 9,7A2,2 0 0,1 7,9M20,3H4A1,1 0 0,0 3,4V10A1,1 0 0,0 4,11H20A1,1 0 0,0 21,10V4A1,1 0 0,0 20,3M7,19A2,2 0 0,1 5,17A2,2 0 0,1 7,15A2,2 0 0,1 9,17A2,2 0 0,1 7,19M20,13H4A1,1 0 0,0 3,14V20A1,1 0 0,0 4,21H20A1,1 0 0,0 21,20V14A1,1 0 0,0 20,13Z" /></svg>
|
After Width: | Height: | Size: 575 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" /></svg>
|
After Width: | Height: | Size: 400 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M11,8H13V16H11V8M7.67,8H4.33C3.53,8 3,8.67 3,9.33V14.67C3,15.33 3.53,16 4.33,16H7.67C8.47,16 9,15.33 9,14.67V12H7V14H5V10H9V9.33C9,8.67 8.47,8 7.67,8M21,10V8H15V16H17V14H19.5V12H17V10H21Z" /></svg>
|
After Width: | Height: | Size: 482 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M16.36,14C16.44,13.34 16.5,12.68 16.5,12C16.5,11.32 16.44,10.66 16.36,10H19.74C19.9,10.64 20,11.31 20,12C20,12.69 19.9,13.36 19.74,14M14.59,19.56C15.19,18.45 15.65,17.25 15.97,16H18.92C17.96,17.65 16.43,18.93 14.59,19.56M14.34,14H9.66C9.56,13.34 9.5,12.68 9.5,12C9.5,11.32 9.56,10.65 9.66,10H14.34C14.43,10.65 14.5,11.32 14.5,12C14.5,12.68 14.43,13.34 14.34,14M12,19.96C11.17,18.76 10.5,17.43 10.09,16H13.91C13.5,17.43 12.83,18.76 12,19.96M8,8H5.08C6.03,6.34 7.57,5.06 9.4,4.44C8.8,5.55 8.35,6.75 8,8M5.08,16H8C8.35,17.25 8.8,18.45 9.4,19.56C7.57,18.93 6.03,17.65 5.08,16M4.26,14C4.1,13.36 4,12.69 4,12C4,11.31 4.1,10.64 4.26,10H7.64C7.56,10.66 7.5,11.32 7.5,12C7.5,12.68 7.56,13.34 7.64,14M12,4.03C12.83,5.23 13.5,6.57 13.91,8H10.09C10.5,6.57 11.17,5.23 12,4.03M18.92,8H15.97C15.65,6.75 15.19,5.55 14.59,4.44C16.43,5.07 17.96,6.34 18.92,8M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" /></svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z" /></svg>
|
After Width: | Height: | Size: 410 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12 1C16.69 1 20.5 5.93 20.5 12C20.5 18.08 16.69 23 12 23C7.31 23 3.5 18.08 3.5 12C3.5 5.93 7.31 1 12 1M12 3C8.41 3 5.5 7.03 5.5 12C5.5 16.97 8.41 21 12 21C15.59 21 18.5 16.97 18.5 12C18.5 7.03 15.59 3 12 3M8.29 10.28L11.53 7.03L12.59 8.09L9.35 11.34L8.29 10.28M8.7 14.61L14.36 8.95L15.42 10L9.76 15.67L8.7 14.61Z" /></svg>
|
After Width: | Height: | Size: 608 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z" /></svg>
|
After Width: | Height: | Size: 552 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M21,3V15.5A3.5,3.5 0 0,1 17.5,19A3.5,3.5 0 0,1 14,15.5A3.5,3.5 0 0,1 17.5,12C18.04,12 18.55,12.12 19,12.34V6.47L9,8.6V17.5A3.5,3.5 0 0,1 5.5,21A3.5,3.5 0 0,1 2,17.5A3.5,3.5 0 0,1 5.5,14C6.04,14 6.55,14.12 7,14.34V6L21,3Z" /></svg>
|
After Width: | Height: | Size: 515 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M20,19V7H4V19H20M20,3A2,2 0 0,1 22,5V19A2,2 0 0,1 20,21H4A2,2 0 0,1 2,19V5C2,3.89 2.9,3 4,3H20M13,17V15H18V17H13M9.58,13L5.57,9H8.4L11.7,12.3C12.09,12.69 12.09,13.33 11.7,13.72L8.42,17H5.59L9.58,13Z" /></svg>
|
After Width: | Height: | Size: 493 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M15,18V16H6V18H15M18,14V12H6V14H18Z" /></svg>
|
After Width: | Height: | Size: 422 B |
|
@ -14,3 +14,23 @@ bool IoUtil::writeAll(QIODevice &dst, QByteArray const & src)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString IoUtil::size_human(qint64 size)
|
||||
{
|
||||
if(size < 1024)
|
||||
return QString("%1 B").arg(size);
|
||||
|
||||
float num = size;
|
||||
QStringList list;
|
||||
list << "KB" << "MB" << "GB" << "TB";
|
||||
|
||||
QStringListIterator i(list);
|
||||
QString unit("B");
|
||||
|
||||
while(num >= 1024.0 && i.hasNext())
|
||||
{
|
||||
unit = i.next();
|
||||
num /= 1024.0;
|
||||
}
|
||||
return QString().setNum(num,'f',2)+" "+unit;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
struct IoUtil
|
||||
{
|
||||
static bool writeAll(QIODevice & dst, QByteArray const & src);
|
||||
|
||||
static QString size_human(qint64 size);
|
||||
};
|
||||
|
||||
#endif // IOUTIL_HPP
|
||||
|
|
|
@ -10,13 +10,17 @@
|
|||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QFileDialog>
|
||||
#include "ioutil.hpp"
|
||||
|
||||
MainWindow::MainWindow(QApplication * app, QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
application(app),
|
||||
settings("xqTechnologies", "Kristall"),
|
||||
ui(new Ui::MainWindow),
|
||||
url_status(new QLabel())
|
||||
url_status(new QLabel(this)),
|
||||
file_size(new QLabel(this)),
|
||||
file_mime(new QLabel(this)),
|
||||
load_time(new QLabel(this))
|
||||
{
|
||||
if(not this->settings.contains("start_page")) {
|
||||
this->settings.setValue("start_page", "about:favourites");
|
||||
|
@ -25,6 +29,9 @@ MainWindow::MainWindow(QApplication * app, QWidget *parent) :
|
|||
ui->setupUi(this);
|
||||
|
||||
this->statusBar()->addWidget(this->url_status);
|
||||
this->statusBar()->addPermanentWidget(this->file_mime);
|
||||
this->statusBar()->addPermanentWidget(this->file_size);
|
||||
this->statusBar()->addPermanentWidget(this->load_time);
|
||||
|
||||
this->favourites.load(settings);
|
||||
this->current_style.load(settings);
|
||||
|
@ -87,6 +94,7 @@ BrowserTab * MainWindow::addEmptyTab(bool focus_new, bool load_default)
|
|||
BrowserTab * tab = new BrowserTab(this);
|
||||
|
||||
connect(tab, &BrowserTab::titleChanged, this, &MainWindow::on_tab_titleChanged);
|
||||
connect(tab, &BrowserTab::fileLoaded, this, &MainWindow::on_tab_fileLoaded);
|
||||
|
||||
int index = this->ui->browser_tabs->addTab(tab, "Page");
|
||||
|
||||
|
@ -322,15 +330,25 @@ void MainWindow::on_actionSave_as_triggered()
|
|||
{
|
||||
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
|
||||
if(tab != nullptr) {
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
QFileDialog::saveFileContent(
|
||||
tab->current_buffer,
|
||||
tab->current_location.fileName()
|
||||
);
|
||||
#else
|
||||
// TODO: Implement without saveFileContent
|
||||
QMessageBox::warning(this, "Kristall", "Not support in your Qt version.");
|
||||
#endif
|
||||
QFileDialog dialog { this };
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog.selectFile(tab->current_location.fileName());
|
||||
|
||||
if(dialog.exec() !=QFileDialog::Accepted)
|
||||
return;
|
||||
|
||||
QString fileName = dialog.selectedFiles().at(0);
|
||||
|
||||
QFile file { fileName };
|
||||
|
||||
if(file.open(QFile::WriteOnly))
|
||||
{
|
||||
IoUtil::writeAll(file, tab->current_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, "Kristall", QString("Could not save file:\r\n%1").arg(file.errorString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,3 +367,17 @@ void MainWindow::on_actionAdd_to_favourites_triggered()
|
|||
tab->toggleIsFavourite();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_tab_fileLoaded(qint64 fileSize, const QString &mime, int msec)
|
||||
{
|
||||
auto * tab = qobject_cast<BrowserTab*>(sender());
|
||||
if(tab != nullptr) {
|
||||
int index = this->ui->browser_tabs->indexOf(tab);
|
||||
assert(index >= 0);
|
||||
if(index == this->ui->browser_tabs->currentIndex()) {
|
||||
this->file_size->setText(IoUtil::size_human(fileSize));
|
||||
this->file_mime->setText(mime);
|
||||
this->load_time->setText(QString("%1 ms").arg(msec));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,8 @@ private slots:
|
|||
|
||||
void on_actionAdd_to_favourites_triggered();
|
||||
|
||||
void on_tab_fileLoaded(qint64 fileSize, QString const & mime, int msec);
|
||||
|
||||
private:
|
||||
void reloadTheme();
|
||||
|
||||
|
@ -86,5 +88,8 @@ private:
|
|||
Ui::MainWindow *ui;
|
||||
|
||||
QLabel * url_status;
|
||||
QLabel * file_size;
|
||||
QLabel * file_mime;
|
||||
QLabel * load_time;
|
||||
};
|
||||
#endif // MAINWINDOW_HPP
|
||||
|
|