void MangaListWidget::goToRead(QModelIndex modelIndex) { QStandardItem* currentItem = _model->itemFromIndex(modelIndex); QStandardItem* currentItemParent = currentItem->parent(); if (currentItemParent == nullptr) return; markRead(); emit chapterSelected(currentItemParent->text(), currentItem->text()); }
NewsItem::NewsItem(int idFeed, int idNews, int width, QWidget * parent) : QWidget(parent) , feedId_(idFeed) , newsId_(idNews) , read_(false) { setCursor(Qt::PointingHandCursor); setMinimumHeight(17); iconLabel_ = new QLabel(this); iconLabel_->setFixedWidth(19); textLabel_ = new QLabel(this); textLabel_->setFixedWidth(width); textLabel_->setStyleSheet("QLabel:hover {color: #1155CC;}"); readButton_ = new ToolButton(this); readButton_->setIcon(QIcon(":/images/bulletUnread")); readButton_->setToolTip(tr("Mark Read/Unread")); readButton_->setAutoRaise(true); openExternalBrowserButton_ = new ToolButton(this); openExternalBrowserButton_->setIcon(QIcon(":/images/openBrowser")); openExternalBrowserButton_->setAutoRaise(true); deleteButton_ = new ToolButton(this); deleteButton_->setIcon(QIcon(":/images/editClear")); deleteButton_->setToolTip(tr("Delete News")); deleteButton_->setAutoRaise(true); QHBoxLayout *mainLayout = new QHBoxLayout(); mainLayout->setMargin(0); mainLayout->setSpacing(1); mainLayout->addWidget(readButton_); mainLayout->addWidget(iconLabel_); mainLayout->addWidget(textLabel_, 1); mainLayout->addStretch(0); mainLayout->addWidget(openExternalBrowserButton_); mainLayout->addWidget(deleteButton_); setLayout(mainLayout); connect(readButton_, SIGNAL(clicked()), this, SLOT(markRead())); connect(openExternalBrowserButton_, SIGNAL(clicked()), this, SLOT(openExternalBrowser())); connect(deleteButton_, SIGNAL(clicked()), this, SLOT(deleteNews())); installEventFilter(this); }
void ChatChannel::doSetActive(bool active) { if (active) markRead(Q_UINT64_C(0xffffffffffffffff)); }
void LocalConnection_as::update() { // Check whether local connection is disabled(!): brilliant choice of // function name. if (rcfile.getLocalConnection()) { log_security("Attempting to write to disabled LocalConnection!"); movie_root& mr = getRoot(owner()); mr.removeAdvanceCallback(this); return; } // No-op if already attached. Nothing to do if it fails, but we // should probably stop trying. if (!_shm.attach()) { log_error("Failed to attach shared memory segment"); return; } // We need the lock to prevent simultaneous reads/writes from other // processes. SharedMem::Lock lock(_shm); if (!lock.locked()) { log_debug("Failed to get shm lock"); return; } SharedMem::iterator ptr = _shm.begin(); // First check timestamp data. // These are not network byte order by default, but not sure about // host byte order. const boost::uint32_t timestamp = readLong(ptr + 8); const boost::uint32_t size = readLong(ptr + 12); // As long as there is a timestamp in the shared memory, we mustn't // write anything. // // We check if this is data we are listening for. If it is, read it and // mark for overwriting. // // If not, we keep checking until the data has been overwritten by // another listener or until it's expired. If it's expired, we // mark for overwriting. if (timestamp) { // Start after 16-byte header. const boost::uint8_t* b = ptr + 16; // End at reported size of AMF sequence. const boost::uint8_t* end = b + size; amf::Reader rd(b, end, getGlobal(owner())); as_value a; // Get the connection name. That's all we need to remove expired // data. if (!rd(a)) { log_error("Invalid connection name data"); return; } const std::string& connection = a.to_string(); // Now check if data we wrote has expired. There's no really // reliable way of checking that we genuinely wrote it. if (_lastTime == timestamp) { const size_t timeout = 4 * 1000; VM& vm = getVM(owner()); const boost::uint32_t timeNow = getTimestamp(vm); if (timeNow - timestamp > timeout) { log_debug("Data %s expired at %s. Removing its target " "as a listener", timestamp, timeNow); removeListener(connection, _shm); markRead(_shm); _lastTime = 0; } } // If we are listening and the data is for us, get the rest of it // and call the method. if (_connected && connection == _domain + ":" + _name) { executeAMFFunction(owner(), rd); // Zero the timestamp bytes to signal that the shared memory // can be written again. markRead(_shm); } else { // The data has not expired and we didn't read it. Leave it // alone until it's expired or someone else has read it. return; } } // If we have no data to send, there's nothing more to do. if (_queue.empty()) { // ...except remove the callback if we aren't listening for anything. if (!_connected) { movie_root& mr = getRoot(owner()); mr.removeAdvanceCallback(this); } return; } // Get the first buffer. boost::shared_ptr<ConnectionData> cd = _queue.front(); _queue.pop_front(); // If the correct listener isn't there, iterate until we find one or // there aren't any left. while (!findListener(_domain + ":" + cd->name, _shm)) { if (_queue.empty()) { // Make sure we send the empty header later. cd->ts = 0; break; } cd = _queue.front(); _queue.pop_front(); } // Yes, there is data to send. const char i[] = { 1, 0, 0, 0, 1, 0, 0, 0 }; std::copy(i, i + arraySize(i), ptr); SimpleBuffer& buf = cd->data; SharedMem::iterator tmp = ptr + 8; writeLong(tmp, cd->ts); writeLong(tmp, cd->ts ? buf.size() : 0); std::copy(buf.data(), buf.data() + buf.size(), tmp); // Note the timestamp of our last send. We will keep calling update() // until the data has expired or been read. _lastTime = cd->ts; }
MangaListWidget::MangaListWidget(QWidget* parent): QWidget(parent), _scansDirectory(Utils::getScansDirectory()), _currentChaptersListOnWeb(), _chaptersToCheck(), _currentIndex(), _editOn(false), _coverHasToBeSet(false) { /// Available chapters process _checkAvailableChaptersProcess = new QProcess(this); connect(_checkAvailableChaptersProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(checkAvailableChapterIsDone(int,QProcess::ExitStatus))); connect(_checkAvailableChaptersProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput())); /// Top buttons _markReadButton = new QPushButton; _markReadButton->setIcon(QIcon(Utils::getIconsPath()+"/check.gif")); _markReadButton->setFixedWidth(37); connect(_markReadButton, SIGNAL(clicked()), this, SLOT(markRead())); _markUnreadButton = new QPushButton; _markUnreadButton->setIcon(QIcon(Utils::getIconsPath()+"/uncheck.gif")); _markUnreadButton->setFixedWidth(37); connect(_markUnreadButton, SIGNAL(clicked()), this, SLOT(markUnread())); _downloadButton = new QPushButton; _downloadButton->setIcon(QIcon(Utils::getIconsPath()+"/download.gif")); _downloadButton->setFixedWidth(37); connect(_downloadButton, SIGNAL(clicked()), this, SLOT(goToDownload())); _addMangaButton = new QPushButton; _addMangaButton->setIcon(QIcon(Utils::getIconsPath()+"/plus.png")); _addMangaButton->setFixedWidth(37); connect(_addMangaButton, SIGNAL(clicked()), this, SLOT(addManga())); _checkNewChaptersButton = new QPushButton; _checkNewChaptersButton->setIcon(QIcon(Utils::getIconsPath()+"/checkChapters.png")); _checkNewChaptersButton->setFixedWidth(37); connect(_checkNewChaptersButton, SIGNAL(clicked()), this, SLOT(decorateMangaNames())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(_markReadButton); buttonsLayout->addWidget(_markUnreadButton); buttonsLayout->addWidget(_downloadButton); buttonsLayout->addWidget(_addMangaButton); buttonsLayout->addWidget(_checkNewChaptersButton); buttonsLayout->setAlignment(Qt::AlignHCenter); /// Manga information QPixmap pixmap(Utils::getIconsPath()+"/setCover.png"); _mangaPreviewLabel = new QLabel; _mangaPreviewLabel->setFixedHeight(400); _mangaPreviewLabel->setAlignment(Qt::AlignTop | Qt::AlignHCenter); _mangaPreviewLabel->setStyleSheet("margin: 20px;"); _mangaPreviewLabel->setAttribute(Qt::WA_Hover); _mangaPreviewLabel->installEventFilter(this); _mangaPreviewLabel->setPixmap(pixmap); _genreLabel = new QLabel; _genreLabel->setFont(QFont("Monospace", 8)); _authorLabel = new QLabel; _authorLabel->setFont(QFont("Monospace", 8)); _artistLabel = new QLabel; _artistLabel->setFont(QFont("Monospace", 8)); _publisherLabel = new QLabel; _publisherLabel->setFont(QFont("Monospace", 8)); _magazineLabel = new QLabel; _magazineLabel->setFont(QFont("Monospace", 8)); _startDateLabel = new QLabel; _startDateLabel->setFont(QFont("Monospace", 8)); _editMangaInfoButton = new QPushButton("Edit"); _editMangaInfoButton->setCheckable(true); _editMangaInfoButton->setFixedWidth(100); connect(_editMangaInfoButton, SIGNAL(toggled(bool)), this, SLOT(toggleEditMangaInfo(bool))); QFormLayout* genreLayout = new QFormLayout; genreLayout->addRow("Genre:", _genreLabel); QFormLayout* authorLayout = new QFormLayout; authorLayout->addRow("Author:", _authorLabel); QFormLayout* artistLayout = new QFormLayout; artistLayout->addRow("Artist:", _artistLabel); QFormLayout* publisherLayout = new QFormLayout; publisherLayout->addRow("Publisher:", _publisherLabel); QFormLayout* magazineLayout = new QFormLayout; magazineLayout->addRow("Magazine:", _magazineLabel); QFormLayout* startDateLayout = new QFormLayout; startDateLayout->addRow("Start date:", _startDateLabel); QVBoxLayout* mangaInfoLayout = new QVBoxLayout; mangaInfoLayout->addWidget(_mangaPreviewLabel); mangaInfoLayout->addLayout(genreLayout); mangaInfoLayout->addLayout(authorLayout); mangaInfoLayout->addLayout(artistLayout); mangaInfoLayout->addLayout(publisherLayout); mangaInfoLayout->addLayout(magazineLayout); mangaInfoLayout->addLayout(startDateLayout); mangaInfoLayout->addWidget(_editMangaInfoButton); mangaInfoLayout->setAlignment(Qt::AlignTop); QGroupBox* mangaInfoGroupBox = new QGroupBox("Information"); mangaInfoGroupBox->setLayout(mangaInfoLayout); mangaInfoGroupBox->setFixedWidth(350); mangaInfoGroupBox->setAlignment(Qt::AlignLeft); /// Chapters model _model = new QStandardItemModel; initModel(); /// Chapters view _chapterInfoWidget = new ChapterInfoWidget; _view = new QColumnView; QList<int> widths; widths << 300 << 400 << 400; _view->setColumnWidths(widths); _view->setResizeGripsVisible(false); _view->setFixedWidth(1102); _view->setSelectionMode(QAbstractItemView::ExtendedSelection); _view->setModel(_model); _view->setPreviewWidget(_chapterInfoWidget); connect(_view, SIGNAL(updatePreviewWidget(QModelIndex)), this, SLOT(updateChaptersInfo(QModelIndex))); connect(_view, SIGNAL(clicked(QModelIndex)), this, SLOT(updateMangaInfo(QModelIndex))); connect(_view, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(goToRead(QModelIndex))); QHBoxLayout* listLayout = new QHBoxLayout; listLayout->addWidget(mangaInfoGroupBox); listLayout->addWidget(_view); QStringList headerLabels; headerLabels << "Manga"; _model->setHorizontalHeaderLabels(headerLabels); /// Set current index to first manga if any _view->setCurrentIndex(_model->index(0, 0)); updateMangaInfo(_model->index(0, 0)); /// Main layout QLabel* titleLabel = new QLabel("Manga List"); titleLabel->setFont(QFont("", 18, 99)); QVBoxLayout* mainLayout = new QVBoxLayout; mainLayout->addWidget(titleLabel); mainLayout->addLayout(buttonsLayout); mainLayout->addLayout(listLayout); setLayout(mainLayout); /// Schedule a new available manga check every thirty minutes QTimer* timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(decorateMangaNames())); timer->start(1000*60*30); }