static gint nitrox_sort_func(GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer user_data) { int index_a, index_b; struct dive *a, *b; int a_o2, b_o2; int a_he, b_he; int a_o2low, b_o2low; gtk_tree_model_get(model, iter_a, DIVE_INDEX, &index_a, -1); gtk_tree_model_get(model, iter_b, DIVE_INDEX, &index_b, -1); a = get_dive(index_a); b = get_dive(index_b); get_dive_gas(a, &a_o2, &a_he, &a_o2low); get_dive_gas(b, &b_o2, &b_he, &b_o2low); /* Sort by Helium first, O2 second */ if (a_he == b_he) { if (a_o2 == b_o2) return a_o2low - b_o2low; return a_o2 - b_o2; } return a_he - b_he; }
/* * When adding dives to the dive table, we try to renumber * the new dives based on any old dives in the dive table. * * But we only do it if: * * - the last dive in the old dive table was numbered * * - all the new dives are strictly at the end (so the * "last dive" is at the same location in the dive table * after re-sorting the dives. * * - none of the new dives have any numbers * * This catches the common case of importing new dives from * a dive computer, and gives them proper numbers based on * your old dive list. But it tries to be very conservative * and not give numbers if there is *any* question about * what the numbers should be - in which case you need to do * a manual re-numbering. */ static void try_to_renumber(struct dive *last, int preexisting) { int i, nr; /* * If the new dives aren't all strictly at the end, * we're going to expect the user to do a manual * renumbering. */ if (get_dive(preexisting-1) != last) return; /* * If any of the new dives already had a number, * we'll have to do a manual renumbering. */ for (i = preexisting; i < dive_table.nr; i++) { struct dive *dive = get_dive(i); if (dive->number) return; } /* * Ok, renumber.. */ nr = last->number; for (i = preexisting; i < dive_table.nr; i++) { struct dive *dive = get_dive(i); dive->number = ++nr; } }
void DivePictureModel::updateDivePictures(int divenr) { if (numberOfPictures != 0) { beginRemoveRows(QModelIndex(), 0, numberOfPictures - 1); numberOfPictures = 0; endRemoveRows(); } struct dive *d = get_dive(divenr); numberOfPictures = dive_get_picture_count(d); if (!d || numberOfPictures == 0) { return; } stringPixmapCache.clear(); QStringList pictures; FOR_EACH_PICTURE (d) { stringPixmapCache[QString(picture->filename)].picture = picture; pictures.push_back(QString(picture->filename)); } SPixmapList retList = QtConcurrent::blockingMapped<SPixmapList>(pictures, scaleImages); Q_FOREACH (const SPixmap &pixmap, retList) stringPixmapCache[pixmap.first].image = pixmap.second; beginInsertRows(QModelIndex(), 0, numberOfPictures - 1); endInsertRows(); }
static void nitrox_data_func(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { int index, o2, he, o2low; char buffer[80]; struct dive *dive; gtk_tree_model_get(model, iter, DIVE_INDEX, &index, -1); dive = get_dive(index); get_dive_gas(dive, &o2, &he, &o2low); o2 = (o2 + 5) / 10; he = (he + 5) / 10; o2low = (o2low + 5) / 10; if (he) snprintf(buffer, sizeof(buffer), "%d/%d", o2, he); else if (o2) if (o2 == o2low) snprintf(buffer, sizeof(buffer), "%d", o2); else snprintf(buffer, sizeof(buffer), "%d" UTF8_ELLIPSIS "%d", o2low, o2); else strcpy(buffer, "air"); g_object_set(renderer, "text", buffer, NULL); }
void save_dives(const char *filename) { int i; GList *trip = NULL; FILE *f = fopen(filename, "w"); if (!f) return; /* Flush any edits of current dives back to the dives! */ update_dive(current_dive); fprintf(f, "<dives>\n<program name='subsurface' version='%d'></program>\n", VERSION); /* save the trips */ while ((trip = NEXT_TRIP(trip)) != NULL) save_trip(f, trip->data); /* save the dives */ for (i = 0; i < dive_table.nr; i++) save_dive(f, get_dive(i)); fprintf(f, "</dives>\n"); fclose(f); }
void save_dives(const char *filename) { int i; struct dive *dive; dive_trip_t *trip = NULL; FILE *f = g_fopen(filename, "w"); if (!f) return; /* Flush any edits of current dives back to the dives! */ update_dive(current_dive); fprintf(f, "<dives>\n<program name='subsurface' version='%d'></program>\n", VERSION); /* save the dives */ for_each_dive(i, dive) { dive_trip_t *thistrip = dive->divetrip; if (trip != thistrip) { /* Close the old trip? */ if (trip) fprintf(f, "</trip>\n"); /* Open the new one */ if (thistrip) save_trip(f, thistrip); trip = thistrip; } save_dive(f, get_dive(i)); }
void MainWindow::current_dive_changed(int divenr) { if (divenr >= 0) { select_dive(divenr); ui->globe->centerOn(get_dive(selected_dive)); redrawProfile(); } ui->InfoWidget->updateDiveInfo(divenr); }
void MainWindow::planCanceled() { // while planning we might have modified the displayed_dive // let's refresh what's shown on the profile showProfile(); ui.newProfile->replot(); refreshDisplay(false); ui.newProfile->plotDive(get_dive(selected_dive)); DivePictureModel::instance()->updateDivePictures(); }
void TestRenumber::testMergeAndAppend() { QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47c.xml"), 0); process_dives(true, false); QCOMPARE(dive_table.nr, 2); QCOMPARE(unsaved_changes(), 1); struct dive *d = get_dive(1); QVERIFY(d != NULL); if (d) QCOMPARE(d->number, 2); }
void ProfileGraphicsView::showEvent(QShowEvent* event) { // Program just opened, // but the dive was not ploted. // force a replot by modifying the dive // hold by the view, and issuing a plot. if (dive && !scene()->items().count()) { dive = 0; plot(get_dive(selected_dive)); } }
QList<int> getDivesInTrip(dive_trip_t *trip) { QList<int> ret; for (int i = 0; i < dive_table.nr; i++) { struct dive *d = get_dive(i); if (d->divetrip == trip) { ret.push_back(get_divenr(d)); } } return ret; }
void MainWindow::current_dive_changed(int divenr) { if (divenr >= 0) { select_dive(divenr); ui.globe->centerOn(get_dive(selected_dive)); } /* It looks like it's a bit too cumberstone to send *one* dive using a QList, * but this is just futureproofness, it's the best way in the future to show more than * a single profile plot on the canvas. I know that we are using only one right now, * but let's keep like this so it's easy to change when we need? :) */ ui.newProfile->plotDives(QList<dive *>() << (current_dive)); ui.InfoWidget->updateDiveInfo(divenr); }
// create a new dive. set the current time and add it to the end of the dive list QString DiveListModel::startAddDive() { struct dive *d; d = alloc_dive(); d->when = QDateTime::currentMSecsSinceEpoch() / 1000L + gettimezoneoffset(); struct dive *pd = get_dive(dive_table.nr - 1); int nr = 1; if (pd && pd->number > 0) nr = pd->number + 1; d->number = nr; d->dc.model = strdup("manually added dive"); add_single_dive(-1, d); addDive(d); return QString::number(d->id); }
int dive_nr_sort(int idx_a, int idx_b, timestamp_t when_a, timestamp_t when_b) { struct dive *a, *b; dive_trip_t *tripa = NULL, *tripb = NULL; if (idx_a < 0) { a = NULL; tripa = find_trip_by_idx(idx_a); } else { a = get_dive(idx_a); if (a) tripa = a->divetrip; } if (idx_b < 0) { b = NULL; tripb = find_trip_by_idx(idx_b); } else { b = get_dive(idx_b); if (b) tripb = b->divetrip; } /* * Compare dive dates within the same trip (or when there * are no trips involved at all). But if we have two * different trips use the trip dates for comparison */ if (tripa != tripb) { if (tripa) when_a = tripa->when; if (tripb) when_b = tripb->when; } return when_a - when_b; }
void DivePlannerPointsModel::setupStartTime() { // if the latest dive is in the future, then start an hour after it ends // otherwise start an hour from now startTime = QDateTime::currentDateTimeUtc().addSecs(3600 + gettimezoneoffset()); if (dive_table.nr) { struct dive *d = get_dive(dive_table.nr - 1); time_t ends = d->when + d->duration.seconds; time_t diff = ends - startTime.toTime_t(); if (diff > 0) { startTime = startTime.addSecs(diff + 3600); } } emit startTimeChanged(startTime); }
/* * This doesn't really report anything at all. We just sort the * dives, the GUI does the reporting */ void report_dives(gboolean imported) { int i; int preexisting = dive_table.preexisting; struct dive *last; /* This does the right thing for -1: NULL */ last = get_dive(preexisting-1); qsort(dive_table.dives, dive_table.nr, sizeof(struct dive *), sortfn); for (i = 1; i < dive_table.nr; i++) { struct dive **pp = &dive_table.dives[i-1]; struct dive *prev = pp[0]; struct dive *dive = pp[1]; struct dive *merged; if (prev->when + prev->duration.seconds < dive->when) continue; merged = try_to_merge(prev, dive); if (!merged) continue; free(prev); free(dive); *pp = merged; dive_table.nr--; memmove(pp+1, pp+2, sizeof(*pp)*(dive_table.nr - i)); /* Redo the new 'i'th dive */ i--; } if (imported) { /* Was the previous dive table state numbered? */ if (last && last->number) try_to_renumber(last, preexisting); /* did we have dives in the table and added more? */ if (last && preexisting != dive_table.nr) mark_divelist_changed(TRUE); } dive_table.preexisting = dive_table.nr; dive_list_update_dives(); }
void save_dives(const char *filename) { int i; FILE *f = fopen(filename, "w"); if (!f) return; /* Flush any edits of current dives back to the dives! */ update_dive(current_dive); fprintf(f, "<dives>\n<program name='subsurface' version='%d'></program>\n", VERSION); for (i = 0; i < dive_table.nr; i++) save_dive(f, get_dive(i)); fprintf(f, "</dives>\n"); fclose(f); }
void DiveTripModel::setupModelData() { int i = dive_table.nr; if (rowCount()){ beginRemoveRows(QModelIndex(), 0, rowCount()-1); endRemoveRows(); } if (autogroup) autogroup_dives(); dive_table.preexisting = dive_table.nr; while (--i >= 0) { struct dive* dive = get_dive(i); update_cylinder_related_info(dive); dive_trip_t* trip = dive->divetrip; DiveItem* diveItem = new DiveItem(); diveItem->dive = dive; if (!trip || currentLayout == LIST) { diveItem->parent = rootItem; rootItem->children.push_back(diveItem); continue; } if (currentLayout == LIST) continue; if (!trips.keys().contains(trip)) { TripItem* tripItem = new TripItem(); tripItem->trip = trip; tripItem->parent = rootItem; tripItem->children.push_back(diveItem); trips[trip] = tripItem; rootItem->children.push_back(tripItem); continue; } TripItem* tripItem = trips[trip]; tripItem->children.push_back(diveItem); } if (rowCount()){ beginInsertRows(QModelIndex(), 0, rowCount() - 1); endInsertRows(); } }
static gboolean set_one_dive(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GValue value = {0, }; struct dive *dive; /* Get the dive number */ gtk_tree_model_get_value(model, iter, DIVE_INDEX, &value); dive = get_dive(g_value_get_int(&value)); if (!dive) return TRUE; if (data && dive != data) return FALSE; fill_one_dive(dive, model, iter); return dive == data; }
/* this gets called when at least two but not all dives are selected */ static void get_ranges(char *buffer, int size) { int i, len; int first, last = -1; snprintf(buffer, size, _("for dives #")); for (i = 0; i < dive_table.nr; i++) { struct dive *dive = get_dive(i); if (! dive->selected) continue; if (dive->number < 1) { /* uhh - weird numbers - bail */ snprintf(buffer, size, _("for selected dives")); return; } len = strlen(buffer); if (last == -1) { snprintf(buffer + len, size - len, "%d", dive->number); first = last = dive->number; } else { if (dive->number == last + 1) { last++; continue; } else { if (first == last) snprintf(buffer + len, size - len, ", %d", dive->number); else if (first + 1 == last) snprintf(buffer + len, size - len, ", %d, %d", last, dive->number); else snprintf(buffer + len, size - len, "-%d, %d", last, dive->number); first = last = dive->number; } } } len = strlen(buffer); if (first != last) { if (first + 1 == last) snprintf(buffer + len, size - len, ", %d", last); else snprintf(buffer + len, size - len, "-%d", last); } }
static void renumber_dialog(GtkWidget *w, gpointer data) { int result; struct dive *dive; GtkWidget *dialog, *frame, *button, *vbox; dialog = gtk_dialog_new_with_buttons("Renumber", GTK_WINDOW(main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL); vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); frame = gtk_frame_new("New starting number"); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5); button = gtk_spin_button_new_with_range(1, 50000, 1); gtk_container_add(GTK_CONTAINER(frame), button); /* * Do we have a number for the first dive already? Use that * as the default. */ dive = get_dive(0); if (dive && dive->number) gtk_spin_button_set_value(GTK_SPIN_BUTTON(button), dive->number); gtk_widget_show_all(dialog); result = gtk_dialog_run(GTK_DIALOG(dialog)); if (result == GTK_RESPONSE_ACCEPT) { int nr = gtk_spin_button_get_value(GTK_SPIN_BUTTON(button)); renumber_dives(nr); repaint_dive(); } gtk_widget_destroy(dialog); }
void MainWindow::on_actionAddDive_triggered() { // clear the selection for (int i = 0; i < dive_table.nr; i++) { struct dive *d = get_dive(i); if (d && d->selected) deselect_dive(i); } disableDcShortcuts(); DivePlannerPointsModel::instance()->setPlanMode(false); // now cheat - create one dive that we use to store the info tab data in struct dive *dive = alloc_dive(); dive->when = QDateTime::currentMSecsSinceEpoch() / 1000L; const char* model = strdup(tr("manually added dive").toLocal8Bit().constData()); dive->dc.model = model; // do not use tr here since it expects a char*. record_dive(dive); select_dive(get_divenr(dive)); ui.InfoWidget->updateDiveInfo(selected_dive); ui.stackedWidget->setCurrentIndex(PLANNERPROFILE); // Planner. ui.infoPane->setCurrentIndex(MAINTAB); DivePlannerPointsModel::instance()->createSimpleDive(); refreshDisplay(); ui.InfoWidget->addDiveStarted(); }
/* * This doesn't really report anything at all. We just sort the * dives, the GUI does the reporting */ void report_dives(gboolean is_imported, gboolean prefer_imported) { int i; int preexisting = dive_table.preexisting; struct dive *last; /* check if we need a nickname for the divecomputer for newly downloaded dives; * since we know they all came from the same divecomputer we just check for the * first one */ if (preexisting < dive_table.nr && dive_table.dives[preexisting]->downloaded) set_dc_nickname(dive_table.dives[preexisting]); else /* they aren't downloaded, so record / check all new ones */ for (i = preexisting; i < dive_table.nr; i++) set_dc_nickname(dive_table.dives[i]); /* This does the right thing for -1: NULL */ last = get_dive(preexisting-1); sort_table(&dive_table); for (i = 1; i < dive_table.nr; i++) { struct dive **pp = &dive_table.dives[i-1]; struct dive *prev = pp[0]; struct dive *dive = pp[1]; struct dive *merged; /* only try to merge overlapping dives - or if one of the dives has * zero duration (that might be a gps marker from the webservice) */ if (prev->duration.seconds && dive->duration.seconds && prev->when + prev->duration.seconds < dive->when) continue; merged = try_to_merge(prev, dive, prefer_imported); if (!merged) continue; /* careful - we might free the dive that last points to. Oops... */ if (last == prev || last == dive) last = merged; /* Redo the new 'i'th dive */ i--; add_single_dive(i, merged); delete_single_dive(i+1); delete_single_dive(i+1); } /* make sure no dives are still marked as downloaded */ for (i = 1; i < dive_table.nr; i++) dive_table.dives[i]->downloaded = FALSE; if (is_imported) { /* If there are dives in the table, are they numbered */ if (!last || last->number) try_to_renumber(last, preexisting); /* did we add dives to the dive table? */ if (preexisting != dive_table.nr) mark_divelist_changed(TRUE); } dive_list_update_dives(); }
void Printer::render() { QPointer<ProfileWidget2> profile = MainWindow::instance()->graphics(); // keep original preferences int profileFrameStyle = profile->frameStyle(); int animationOriginal = prefs.animation_speed; double fontScale = profile->getFontPrintScale(); // apply printing settings to profile profile->setFrameStyle(QFrame::NoFrame); profile->setPrintMode(true, !printOptions->color_selected); profile->setFontPrintScale(0.6); profile->setToolTipVisibile(false); prefs.animation_speed = 0; // render the Qwebview QPainter painter; QRect viewPort(0, 0, pageSize.width(), pageSize.height()); painter.begin(printer); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); int divesPerPage; switch (printOptions->p_template) { case print_options::ONE_DIVE: divesPerPage = 1; break; case print_options::TWO_DIVE: divesPerPage = 2; break; } int Pages = ceil(getTotalWork() / (float)divesPerPage); // get all refereces to diveprofile class in the Html template QWebElementCollection collection = webView->page()->mainFrame()->findAllElements(".diveprofile"); QSize originalSize = profile->size(); if (collection.count() > 0) { profile->resize(collection.at(0).geometry().size()); } int elemNo = 0; for (int i = 0; i < Pages; i++) { // render the base Html template webView->page()->mainFrame()->render(&painter, QWebFrame::ContentsLayer); // render all the dive profiles in the current page while (elemNo < collection.count() && collection.at(elemNo).geometry().y() < viewPort.y() + viewPort.height()) { // dive id field should be dive_{{dive_no}} se we remove the first 5 characters int diveNo = collection.at(elemNo).attribute("id").remove(0, 5).toInt(0, 10); putProfileImage(collection.at(elemNo).geometry(), viewPort, &painter, get_dive(diveNo - 1), profile); elemNo++; } // scroll the webview to the next page webView->page()->mainFrame()->scroll(0, pageSize.height()); viewPort.adjust(0, pageSize.height(), 0, pageSize.height()); // rendering progress is 4/5 of total work emit(progessUpdated((i * 80.0 / Pages) + done)); if (i < Pages - 1) printer->newPage(); } painter.end(); // return profle settings profile->setFrameStyle(profileFrameStyle); profile->setPrintMode(false); profile->setFontPrintScale(fontScale); profile->setToolTipVisibile(true); profile->resize(originalSize); prefs.animation_speed = animationOriginal; //replot the dive after returning the settings profile->plotDive(0, true); }
void MainWindow::redrawProfile() { ui->ProfileWidget->plot(get_dive(selected_dive)); }
bool DivelogsDeWebServices::prepare_dives_for_divelogs(const QString &tempfile, const bool selected) { static const char errPrefix[] = "divelog.de-upload:"; if (!amount_selected) { report_error(tr("no dives were selected").toUtf8()); return false; } xsltStylesheetPtr xslt = NULL; struct zip *zip; xslt = get_stylesheet("divelogs-export.xslt"); if (!xslt) { qDebug() << errPrefix << "missing stylesheet"; return false; } int error_code; zip = zip_open(QFile::encodeName(tempfile), ZIP_CREATE, &error_code); if (!zip) { char buffer[1024]; zip_error_to_str(buffer, sizeof buffer, error_code, errno); report_error(tr("failed to create zip file for upload: %s").toUtf8(), buffer); return false; } /* walk the dive list in chronological order */ for (int i = 0; i < dive_table.nr; i++) { FILE *f; char filename[PATH_MAX]; int streamsize; char *membuf; xmlDoc *transformed; struct zip_source *s; /* * Get the i'th dive in XML format so we can process it. * We need to save to a file before we can reload it back into memory... */ struct dive *dive = get_dive(i); if (!dive) continue; if (selected && !dive->selected) continue; f = tmpfile(); if (!f) { report_error(tr("cannot create temporary file: %s").toUtf8(), qt_error_string().toUtf8().data()); goto error_close_zip; } save_dive(f, dive); fseek(f, 0, SEEK_END); streamsize = ftell(f); rewind(f); membuf = (char *)malloc(streamsize + 1); if (!membuf || (streamsize = fread(membuf, streamsize, 1, f)) == 0) { report_error(tr("internal error: %s").toUtf8(), qt_error_string().toUtf8().data()); fclose(f); free((void *)membuf); goto error_close_zip; } membuf[streamsize] = 0; fclose(f); /* * Parse the memory buffer into XML document and * transform it to divelogs.de format, finally dumping * the XML into a character buffer. */ xmlDoc *doc = xmlReadMemory(membuf, streamsize, "divelog", NULL, 0); if (!doc) { qWarning() << errPrefix << "could not parse back into memory the XML file we've just created!"; report_error(tr("internal error").toUtf8()); free((void *)membuf); goto error_close_zip; } free((void *)membuf); transformed = xsltApplyStylesheet(xslt, doc, NULL); xmlDocDumpMemory(transformed, (xmlChar **)&membuf, &streamsize); xmlFreeDoc(doc); xmlFreeDoc(transformed); /* * Save the XML document into a zip file. */ snprintf(filename, PATH_MAX, "%d.xml", i + 1); s = zip_source_buffer(zip, membuf, streamsize, 1); if (s) { int64_t ret = zip_add(zip, filename, s); if (ret == -1) qDebug() << errPrefix << "failed to include dive:" << i; } } zip_close(zip); xsltFreeStylesheet(xslt); return true; error_close_zip: zip_close(zip); QFile::remove(tempfile); xsltFreeStylesheet(xslt); return false; }