diff options
79 files changed, 1844 insertions, 1790 deletions
diff --git a/.clang-format b/.clang-format index 6b75350e0..092136768 100644 --- a/.clang-format +++ b/.clang-format @@ -10,6 +10,7 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true ColumnLimit: 0 IndentFunctionDeclarationAfterType: false #personal taste, good for long methods IndentWidth: 8 +ContinuationIndentWidth: 8 MaxEmptyLinesToKeep: 2 NamespaceIndentation: All SpaceBeforeAssignmentOperators: true @@ -18,3 +19,4 @@ SpacesInParentheses: false SpacesBeforeTrailingComments: 1 UseTab: Always PointerBindsToType: false +# doesn't work, yet -> ForEachMacros: "Q_FOREACH" diff --git a/CMakeLists.txt b/CMakeLists.txt index 153f8d628..ef58bbf57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,7 @@ SET(SUBSURFACE_INTERFACE qt-ui/tagwidget.cpp qt-ui/groupedlineedit.cpp qt-ui/usermanual.cpp + qt-ui/divelogexportdialog.cpp ) #the profile widget diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index e85957012..00cd5faa8 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -43,7 +43,7 @@ New in version 4.1 (compared to Subsurface 4.0.3): - new and improved profile widget with animations, better info box, and a new toolbox to turn on and off many of the additional graphs and information displays -- improved CVS import and added CVS export +- improved CSV import and added CSV export - import of exported log files from Sensus (CSV) and Shearwater Desktop (XML) - improved UDDF and divelogs.de support diff --git a/android.cpp b/android.cpp index 15de9e65d..93f26730b 100644 --- a/android.cpp +++ b/android.cpp @@ -18,8 +18,8 @@ const char *system_default_filename(void) { /* Replace this when QtCore/QStandardPaths getExternalStorageDirectory landed */ QAndroidJniObject externalStorage = QAndroidJniObject::callStaticObjectMethod("android/os/Environment", "getExternalStorageDirectory", "()Ljava/io/File;"); - QAndroidJniObject externalStorageAbsolute = externalStorage.callObjectMethod( "getAbsolutePath", "()Ljava/lang/String;" ); - QString system_default_filename = externalStorageAbsolute.toString()+"/subsurface.xml"; + QAndroidJniObject externalStorageAbsolute = externalStorage.callObjectMethod("getAbsolutePath", "()Ljava/lang/String;"); + QString system_default_filename = externalStorageAbsolute.toString() + "/subsurface.xml"; QAndroidJniEnvironment env; if (env->ExceptionCheck()) { // FIXME: Handle exception here. @@ -29,7 +29,7 @@ const char *system_default_filename(void) return strdup(system_default_filename.toUtf8().data()); } -int enumerate_devices (device_callback_t callback, void *userdata) +int enumerate_devices(device_callback_t callback, void *userdata, int dc_type) { /* FIXME: we need to enumerate in some other way on android */ /* qtserialport maybee? */ @@ -77,5 +77,4 @@ void subsurface_console_exit(void) { /* NOP */ } - } @@ -55,7 +55,12 @@ extern int is_default_dive_computer_device(const char *); extern int is_default_dive_computer(const char *, const char *); typedef void (*device_callback_t)(const char *name, void *userdata); -int enumerate_devices(device_callback_t callback, void *userdata); + +#define DC_TYPE_SERIAL 1 +#define DC_TYPE_UEMIS 2 +#define DC_TYPE_OTHER 3 + +int enumerate_devices(device_callback_t callback, void *userdata, int dc_type); extern const char *default_dive_computer_vendor; extern const char *default_dive_computer_product; @@ -19,6 +19,26 @@ static const char *default_tags[] = { QT_TRANSLATE_NOOP("gettextFromC", "deco") }; +void make_first_dc() +{ + struct divecomputer *dc = ¤t_dive->dc; + struct divecomputer *newdc = malloc(sizeof(*newdc)); + struct divecomputer *cur_dc = current_dc; /* needs to be in a local variable so the macro isn't re-executed */ + + /* skip the current DC in the linked list */ + while (dc && dc->next != cur_dc) + dc = dc->next; + if (!dc) { + fprintf(stderr, "data inconsistent: can't find the current DC"); + return; + } + dc->next = cur_dc->next; + *newdc = current_dive->dc; + current_dive->dc = *cur_dc; + current_dive->dc.next = newdc; + free(cur_dc); +} + void add_event(struct divecomputer *dc, int time, int type, int flags, int value, const char *name) { struct event *ev, **p; @@ -45,6 +65,17 @@ void add_event(struct divecomputer *dc, int time, int type, int flags, int value remember_event(name); } +void remove_event(struct event* event) +{ + struct event **ep = ¤t_dc->events; + while (ep && *ep != event) + ep = &(*ep)->next; + if (ep) { + *ep = event->next; + free(event); + } +} + int get_pressure_units(unsigned int mb, const char **units) { int pressure; @@ -221,6 +252,7 @@ struct dive *alloc_dive(void) if (!dive) exit(1); memset(dive, 0, sizeof(*dive)); + dive->id = dive_getUniqID(dive); return dive; } @@ -955,7 +987,10 @@ struct dive *fixup_dive(struct dive *dive) weightsystem_t *ws = dive->weightsystem + i; add_weightsystem_description(ws); } - dive->id = dive_getUniqID(dive); + /* we should always have a uniq ID as that gets assigned during alloc_dive(), + * but we want to make sure... */ + if (!dive->id) + dive->id = dive_getUniqID(dive); return dive; } @@ -1296,11 +1331,8 @@ static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, int static void cylinder_renumber(struct dive *dive, int mapping[]) { struct divecomputer *dc; - - dc = &dive->dc; - do { + for_each_dc(dive, dc) dc_cylinder_renumber(dive, dc, mapping); - } while ((dc = dc->next) != NULL); } /* @@ -1905,6 +1937,9 @@ static void interleave_dive_computers(struct divecomputer *res, if (match) { merge_events(res, a, match, offset); merge_samples(res, a, match, offset); + /* Use the diveid of the later dive! */ + if (offset > 0) + res->diveid = match->diveid; } else { res->sample = a->sample; res->samples = a->samples; @@ -2135,7 +2170,7 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer if (dl) { /* If we prefer downloaded, do those first, and get rid of "might be same" computers */ join_dive_computers(&res->dc, &dl->dc, &a->dc, 1); - } else if (offset) + } else if (offset && might_be_same_device(&a->dc, &b->dc)) interleave_dive_computers(&res->dc, &a->dc, &b->dc, offset); else join_dive_computers(&res->dc, &a->dc, &b->dc, 0); @@ -26,7 +26,7 @@ static inline int same_string(const char *a, const char *b) { - return !strcmp(a ? : "", b ? : ""); + return !strcmp(a ?: "", b ?: ""); } #include <libxml/tree.h> @@ -107,6 +107,12 @@ static inline int interpolate(int a, int b, int part, int whole) return rint(x / whole); } +static inline depth_t gas_mod(struct gasmix *mix, pressure_t po2_limit) { + depth_t depth; + depth.mm = po2_limit.mbar * 1000 / get_o2(mix) * 10 - 10000; + return depth; +} + struct sample { duration_t time; depth_t depth; @@ -364,6 +370,7 @@ struct dive_table { extern struct dive_table dive_table; extern int selected_dive; +extern unsigned int dc_number; #define current_dive (get_dive(selected_dive)) #define current_dc (get_dive_dc(current_dive, dc_number)) @@ -408,6 +415,8 @@ static inline struct divecomputer *get_dive_dc(struct dive *dive, int nr) return dc; } +extern void make_first_dc(void); + /* * Iterate over each dive, with the first parameter being the index * iterator variable, and the second one being the dive one. @@ -429,7 +438,7 @@ static inline struct dive *get_dive_by_uemis_diveid(uint32_t diveid, uint32_t de int i; struct dive *dive; - for_each_dive(i, dive) { + for_each_dive (i, dive) { struct divecomputer *dc = &dive->dc; do { if (dc->diveid == diveid && dc->deviceid == deviceid) @@ -439,17 +448,17 @@ static inline struct dive *get_dive_by_uemis_diveid(uint32_t diveid, uint32_t de return NULL; } -static inline struct dive *get_dive_by_diveid(int id) +static inline struct dive *get_dive_by_uniq_id(int id) { int i; struct dive *dive = NULL; - for_each_dive(i, dive) { + for_each_dive (i, dive) { if (dive->id == id) break; } #ifdef DEBUG - if(dive == NULL){ + if (dive == NULL) { fprintf(stderr, "Invalid id %x passed to get_dive_by_diveid, try to fix the code\n", id); exit(1); } @@ -457,6 +466,24 @@ static inline struct dive *get_dive_by_diveid(int id) return dive; } +static inline int get_idx_by_uniq_id(int id) +{ + int i; + struct dive *dive = NULL; + + for_each_dive (i, dive) { + if (dive->id == id) + break; + } +#ifdef DEBUG + if (dive == NULL) { + fprintf(stderr, "Invalid id %x passed to get_dive_by_diveid, try to fix the code\n", id); + exit(1); + } +#endif + return i; +} + #ifdef __cplusplus extern "C" { #endif @@ -490,7 +517,7 @@ extern int export_dives_xslt(const char *filename, const bool selected, const ch struct git_oid; struct git_repository; -#define dummy_git_repository ((git_repository *) 3ul) /* Random bogus pointer, not NULL */ +#define dummy_git_repository ((git_repository *)3ul) /* Random bogus pointer, not NULL */ extern struct git_repository *is_git_repository(const char *filename, const char **branchp); extern int git_save_dives(struct git_repository *, const char *, bool select_only); extern int git_load_dives(struct git_repository *, const char *); @@ -536,7 +563,7 @@ extern unsigned int dc_airtemp(struct divecomputer *dc); extern unsigned int dc_watertemp(struct divecomputer *dc); extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded); extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded); -extern void renumber_dives(int nr); +extern void renumber_dives(int start_nr, bool selected_only); extern void copy_events(struct dive *s, struct dive *d); extern void copy_cylinders(struct dive *s, struct dive *d); extern void copy_samples(struct dive *s, struct dive *d); @@ -544,6 +571,7 @@ extern void copy_samples(struct dive *s, struct dive *d); extern void fill_default_cylinder(cylinder_t *cyl); extern void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int time, int idx); extern void add_event(struct divecomputer *dc, int time, int type, int flags, int value, const char *name); +extern void remove_event(struct event *event); extern void per_cylinder_mean_depth(struct dive *dive, struct divecomputer *dc, int *mean, int *duration); extern int get_cylinder_index(struct dive *dive, struct event *ev); extern int nr_cylinders(struct dive *dive); @@ -674,7 +702,7 @@ extern double strtod_flags(const char *str, const char **ptr, unsigned int flags #define ascii_strtod(str, ptr) strtod_flags(str, ptr, STRTOD_ASCII) extern void set_save_userid_local(short value); -extern void set_userid(char* user_id); +extern void set_userid(char *user_id); #ifdef __cplusplus } diff --git a/divecomputer.cpp b/divecomputer.cpp index 6044f1aa6..f427bd42c 100644 --- a/divecomputer.cpp +++ b/divecomputer.cpp @@ -41,7 +41,7 @@ bool DiveComputerNode::changesValues(const DiveComputerNode &b) const (nickName != b.nickName); } -const DiveComputerNode *DiveComputerList::getExact(const QString& m, uint32_t d) +const DiveComputerNode *DiveComputerList::getExact(const QString &m, uint32_t d) { for (QMap<QString, DiveComputerNode>::iterator it = dcMap.find(m); it != dcMap.end() && it.key() == m; ++it) if (it->deviceId == d) @@ -49,7 +49,7 @@ const DiveComputerNode *DiveComputerList::getExact(const QString& m, uint32_t d) return NULL; } -const DiveComputerNode *DiveComputerList::get(const QString& m) +const DiveComputerNode *DiveComputerList::get(const QString &m) { QMap<QString, DiveComputerNode>::iterator it = dcMap.find(m); if (it != dcMap.end()) @@ -57,7 +57,7 @@ const DiveComputerNode *DiveComputerList::get(const QString& m) return NULL; } -void DiveComputerList::addDC(const QString& m, uint32_t d, const QString& n, const QString& s,const QString& f) +void DiveComputerList::addDC(const QString &m, uint32_t d, const QString &n, const QString &s, const QString &f) { if (m.isEmpty() || d == 0) return; @@ -79,7 +79,7 @@ void DiveComputerList::addDC(const QString& m, uint32_t d, const QString& n, con dcMap.insert(m, newNode); } -void DiveComputerList::rmDC(const QString& m, uint32_t d) +void DiveComputerList::rmDC(const QString &m, uint32_t d) { const DiveComputerNode *existNode = this->getExact(m, d); dcMap.remove(m, *existNode); @@ -96,8 +96,8 @@ extern "C" bool compareDC(const DiveComputerNode &a, const DiveComputerNode &b) return a.deviceId < b.deviceId; } -extern "C" void call_for_each_dc(void *f, void (*callback)(void *, const char *, uint32_t, - const char *, const char *, const char *)) +extern "C" void call_for_each_dc (void *f, void (*callback)(void *, const char *, uint32_t, + const char *, const char *, const char *)) { QList<DiveComputerNode> values = dcList.dcMap.values(); qSort(values.begin(), values.end(), compareDC); @@ -162,9 +162,9 @@ extern "C" void set_dc_nickname(struct dive *dive) if (!dive) return; - struct divecomputer *dc = &dive->dc; + struct divecomputer *dc; - while (dc) { + for_each_dc (dive, dc) { if (dc->model && *dc->model && dc->deviceid && !dcList.getExact(dc->model, dc->deviceid)) { // we don't have this one, yet @@ -181,6 +181,5 @@ extern "C" void set_dc_nickname(struct dive *dive) dcList.addDC(dc->model, dc->deviceid); } } - dc = dc->next; } } diff --git a/divecomputer.h b/divecomputer.h index e515a6b06..54752abf7 100644 --- a/divecomputer.h +++ b/divecomputer.h @@ -23,12 +23,12 @@ class DiveComputerList { public: DiveComputerList(); ~DiveComputerList(); - const DiveComputerNode *getExact(const QString& m, uint32_t d); - const DiveComputerNode *get(const QString& m); - void addDC(const QString& m, uint32_t d,const QString& n = QString(),const QString& s = QString(), const QString& f = QString()); - void rmDC(const QString& m, uint32_t d); - DiveComputerNode matchDC(const QString& m, uint32_t d); - DiveComputerNode matchModel(const QString& m); + const DiveComputerNode *getExact(const QString &m, uint32_t d); + const DiveComputerNode *get(const QString &m); + void addDC(const QString &m, uint32_t d, const QString &n = QString(), const QString &s = QString(), const QString &f = QString()); + void rmDC(const QString &m, uint32_t d); + DiveComputerNode matchDC(const QString &m, uint32_t d); + DiveComputerNode matchModel(const QString &m); QMultiMap<QString, DiveComputerNode> dcMap; QMultiMap<QString, DiveComputerNode> dcWorkingMap; }; diff --git a/divelist.c b/divelist.c index b19971087..ca2e9827f 100644 --- a/divelist.c +++ b/divelist.c @@ -115,8 +115,6 @@ void get_dive_gas(struct dive *dive, int *o2_p, int *he_p, int *o2low_p) cylinder_t *cyl = dive->cylinder + i; int o2 = get_o2(&cyl->gasmix); int he = get_he(&cyl->gasmix); - int used = 0; - int first_gas_explicit = 0; if (!cyl->used) continue; @@ -154,12 +152,9 @@ int total_weight(struct dive *dive) static int active_o2(struct dive *dive, struct divecomputer *dc, duration_t time) { - int o2permille = dive->cylinder[0].gasmix.o2.permille; + int o2permille = get_o2(&dive->cylinder[0].gasmix); struct event *event; - if (!o2permille) - o2permille = O2_IN_AIR; - for (event = dc->events; event; event = event->next) { if (event->time.seconds > time.seconds) break; @@ -583,6 +578,44 @@ void find_new_trip_start_time(dive_trip_t *trip) trip->when = when; } +/* check if we have a trip right before / after this dive */ +bool is_trip_before_after(struct dive *dive, bool before) +{ + int idx = get_idx_by_uniq_id(dive->id); + if (before) { + if (idx > 0 && get_dive(idx - 1)->divetrip) + return true; + } else { + if (idx < dive_table.nr - 1 && get_dive(idx + 1)->divetrip) + return true; + } + return false; +} + +struct dive *first_selected_dive() +{ + int idx; + struct dive *d; + + for_each_dive (idx, d) { + if (d->selected) + return d; + } + return NULL; +} + +struct dive *last_selected_dive() +{ + int idx; + struct dive *d, *ret = NULL; + + for_each_dive (idx, d) { + if (d->selected) + ret = d; + } + return ret; +} + void remove_dive_from_trip(struct dive *dive, short was_autogen) { struct dive *next, **pprev; @@ -813,6 +846,43 @@ void deselect_dive(int idx) } } +void deselect_dives_in_trip(struct dive_trip *trip) +{ + struct dive *dive; + if (!trip) + return; + for (dive = trip->dives; dive; dive = dive->next) + deselect_dive(get_divenr(dive)); +} + +void select_dives_in_trip(struct dive_trip *trip) +{ + struct dive *dive; + if (!trip) + return; + for (dive = trip->dives; dive; dive = dive->next) + select_dive(get_divenr(dive)); +} + +/* This only gets called with non-NULL trips. + * It does not combine notes or location, just picks the first one + * (or the second one if the first one is empty */ +void combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b) +{ + if (same_string(trip_a->location, "") && trip_b->location) { + free(trip_a->location); + trip_a->location = strdup(trip_b->location); + } + if (same_string(trip_a->notes, "") && trip_b->notes) { + free(trip_a->notes); + trip_a->notes = strdup(trip_b->notes); + } + /* this also removes the dives from trip_b and eventually + * calls delete_trip(trip_b) when the last dive has been moved */ + while (trip_b->dives) + add_dive_to_trip(trip_b->dives, trip_a); +} + void mark_divelist_changed(int changed) { dive_list_changed = changed; @@ -912,6 +982,9 @@ void process_dives(bool is_imported, bool prefer_imported) for (i = preexisting; i < dive_table.nr; i++) set_dc_nickname(dive_table.dives[i]); + for (i = preexisting; i < dive_table.nr; i++) + dive_table.dives[i]->downloaded = true; + /* This does the right thing for -1: NULL */ last = get_dive(preexisting - 1); diff --git a/divelist.h b/divelist.h index ade4ce9a6..4eafd5dd4 100644 --- a/divelist.h +++ b/divelist.h @@ -30,7 +30,13 @@ extern struct dive *merge_two_dives(struct dive *a, struct dive *b); extern bool consecutive_selected(); extern void select_dive(int idx); extern void deselect_dive(int idx); -void find_new_trip_start_time(dive_trip_t *trip); +extern void select_dives_in_trip(struct dive_trip *trip); +extern void deselect_dives_in_trip(struct dive_trip *trip); +extern void combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b); +extern void find_new_trip_start_time(dive_trip_t *trip); +extern struct dive *first_selected_dive(); +extern struct dive *last_selected_dive(); +extern bool is_trip_before_after(struct dive *dive, bool before); #ifdef DEBUG_TRIP extern void dump_selection(void); @@ -49,78 +49,84 @@ const char *system_default_filename(void) return buffer; } -int enumerate_devices(device_callback_t callback, void *userdata) +int enumerate_devices(device_callback_t callback, void *userdata, int dc_type) { - int index = -1; + int index = -1, entries = 0; DIR *dp = NULL; struct dirent *ep = NULL; size_t i; - const char *dirname = "/dev"; - const char *patterns[] = { - "ttyUSB*", - "ttyS*", - "ttyACM*", - "rfcomm*", - NULL - }; FILE *file; char *line = NULL; char *fname; size_t len; + if (dc_type != DC_TYPE_UEMIS) { + const char *dirname = "/dev"; + const char *patterns[] = { + "ttyUSB*", + "ttyS*", + "ttyACM*", + "rfcomm*", + NULL + }; + + dp = opendir(dirname); + if (dp == NULL) { + return -1; + } - dp = opendir(dirname); - if (dp == NULL) { - return -1; - } - - while ((ep = readdir(dp)) != NULL) { - for (i = 0; patterns[i] != NULL; ++i) { - if (fnmatch(patterns[i], ep->d_name, 0) == 0) { - char filename[1024]; - int n = snprintf(filename, sizeof(filename), "%s/%s", dirname, ep->d_name); - if (n >= sizeof(filename)) { - closedir(dp); - return -1; + while ((ep = readdir(dp)) != NULL) { + for (i = 0; patterns[i] != NULL; ++i) { + if (fnmatch(patterns[i], ep->d_name, 0) == 0) { + char filename[1024]; + int n = snprintf(filename, sizeof(filename), "%s/%s", dirname, ep->d_name); + if (n >= sizeof(filename)) { + closedir(dp); + return -1; + } + callback(filename, userdata); + if (is_default_dive_computer_device(filename)) + index = entries; + entries++; + break; } - callback(filename, userdata); - if (is_default_dive_computer_device(filename)) - index = i; - break; } } + closedir(dp); } - closedir(dp); - - file = fopen("/proc/mounts", "r"); - if (file == NULL) - return index; - - while ((getline(&line, &len, file)) != -1) { - char *ptr = strstr(line, "UEMISSDA"); - if (ptr) { - char *end = ptr, *start = ptr; - while (start > line && *start != ' ') - start--; - if (*start == ' ') - start++; - while (*end != ' ' && *end != '\0') - end++; - - *end = '\0'; - fname = strdup(start); - - callback(fname, userdata); - - if (is_default_dive_computer_device(fname)) - index = i; - i++; - free((void *)fname); + if (dc_type != DC_TYPE_SERIAL) { + int num_uemis = 0; + file = fopen("/proc/mounts", "r"); + if (file == NULL) + return index; + + while ((getline(&line, &len, file)) != -1) { + char *ptr = strstr(line, "UEMISSDA"); + if (ptr) { + char *end = ptr, *start = ptr; + while (start > line && *start != ' ') + start--; + if (*start == ' ') + start++; + while (*end != ' ' && *end != '\0') + end++; + + *end = '\0'; + fname = strdup(start); + + callback(fname, userdata); + + if (is_default_dive_computer_device(fname)) + index = entries; + entries++; + num_uemis++; + free((void *)fname); + } } + free(line); + fclose(file); + if (num_uemis == 1 && entries == 1) /* if we found only one and it's a mounted Uemis, pick it */ + index = 0; } - - free(line); - fclose(file); - return index; } diff --git a/load-git.c b/load-git.c index c1007358c..acfdd2527 100644 --- a/load-git.c +++ b/load-git.c @@ -1115,11 +1115,13 @@ static struct divecomputer *create_new_dc(struct dive *dive) /* Did we already fill that in? */ if (dc->samples || dc->model || dc->when) { struct divecomputer *newdc = calloc(1, sizeof(*newdc)); - if (newdc) { - dc->next = newdc; - dc = newdc; - } + if (!newdc) + return NULL; + dc->next = newdc; + dc = newdc; } + dc->when = dive->when; + dc->duration = dive->duration; return dc; } @@ -45,27 +45,54 @@ const char *system_default_filename(void) return buffer; } -int enumerate_devices(device_callback_t callback, void *userdata) +int enumerate_devices(device_callback_t callback, void *userdata, int dc_type) { - int index = -1; + int index = -1, entries = 0; DIR *dp = NULL; struct dirent *ep = NULL; size_t i; - const char *dirname = "/dev"; - const char *patterns[] = { - "tty.*", - "usbserial", - NULL - }; - - dp = opendir(dirname); - if (dp == NULL) { - return -1; + if (dc_type != DC_TYPE_UEMIS) { + const char *dirname = "/dev"; + const char *patterns[] = { + "tty.*", + "usbserial", + NULL + }; + + dp = opendir(dirname); + if (dp == NULL) { + return -1; + } + + while ((ep = readdir(dp)) != NULL) { + for (i = 0; patterns[i] != NULL; ++i) { + if (fnmatch(patterns[i], ep->d_name, 0) == 0) { + char filename[1024]; + int n = snprintf(filename, sizeof(filename), "%s/%s", dirname, ep->d_name); + if (n >= sizeof(filename)) { + closedir(dp); + return -1; + } + callback(filename, userdata); + if (is_default_dive_computer_device(filename)) + index = entries; + entries++; + break; + } + } + } + closedir(dp); } + if (dc_type != DC_TYPE_SERIAL) { + const char *dirname = "/Volumes"; + int num_uemis = 0; + dp = opendir(dirname); + if (dp == NULL) { + return -1; + } - while ((ep = readdir(dp)) != NULL) { - for (i = 0; patterns[i] != NULL; ++i) { - if (fnmatch(patterns[i], ep->d_name, 0) == 0) { + while ((ep = readdir(dp)) != NULL) { + if (fnmatch("UEMISSDA", ep->d_name, 0) == 0) { char filename[1024]; int n = snprintf(filename, sizeof(filename), "%s/%s", dirname, ep->d_name); if (n >= sizeof(filename)) { @@ -74,14 +101,16 @@ int enumerate_devices(device_callback_t callback, void *userdata) } callback(filename, userdata); if (is_default_dive_computer_device(filename)) - index = i; + index = entries; + entries++; + num_uemis++; break; } } + closedir(dp); + if (num_uemis == 1 && entries == 1) /* if we find exactly one entry and that's a Uemis, select it */ + index = 0; } - // TODO: list UEMIS mount point from /proc/mounts - - closedir(dp); return index; } @@ -26,7 +26,7 @@ int main(int argc, char **argv) QStringList arguments = QCoreApplication::arguments(); bool dedicated_console = arguments.length() > 1 && - (arguments.at(1) == QString("--win32console")); + (arguments.at(1) == QString("--win32console")); subsurface_console_init(dedicated_console); for (i = 1; i < arguments.length(); i++) { @@ -1155,7 +1155,8 @@ static void calculate_gas_information_new(struct dive *dive, struct plot_info *p * so there is no difference in calculating between OC and CC * END takes O2 + N2 (air) into account ("Narcotic" for trimix dives) * EAD just uses N2 ("Air" for nitrox dives) */ - entry->mod = (prefs.modppO2 / fo2 * 1000 - 1) * 10000; + pressure_t modppO2 = { .mbar = (int) (prefs.modppO2 * 1000) }; + entry->mod = (double) gas_mod(&dive->cylinder[cylinderindex].gasmix, modppO2).mm; entry->end = (entry->depth + 10000) * (1000 - fhe) / 1000.0 - 10000; entry->ead = (entry->depth + 10000) * (1000 - fo2 - fhe) / (double)N2_IN_AIR - 10000; entry->eadd = (entry->depth + 10000) * @@ -80,7 +80,6 @@ int get_maxtime(struct plot_info *pi); int get_maxdepth(struct plot_info *pi); - #define SENSOR_PR 0 #define INTERPOLATED_PR 1 #define SENSOR_PRESSURE(_entry) (_entry)->pressure[SENSOR_PR] diff --git a/qt-gui.cpp b/qt-gui.cpp index 9d6dde45f..f342e20e1 100644 --- a/qt-gui.cpp +++ b/qt-gui.cpp @@ -391,12 +391,12 @@ QString get_dive_date_string(timestamp_t when) struct tm tm; utc_mkdate(when, &tm); return translate("gettextFromC", "%1, %2 %3, %4 %5:%6") - .arg(weekday(tm.tm_wday)) - .arg(monthname(tm.tm_mon)) - .arg(tm.tm_mday) - .arg(tm.tm_year + 1900) - .arg(tm.tm_hour, 2, 10, QChar('0')) - .arg(tm.tm_min, 2, 10, QChar('0')); + .arg(weekday(tm.tm_wday)) + .arg(monthname(tm.tm_mon)) + .arg(tm.tm_mday) + .arg(tm.tm_year + 1900) + .arg(tm.tm_hour, 2, 10, QChar('0')) + .arg(tm.tm_min, 2, 10, QChar('0')); } QString get_short_dive_date_string(timestamp_t when) @@ -404,11 +404,11 @@ QString get_short_dive_date_string(timestamp_t when) struct tm tm; utc_mkdate(when, &tm); return translate("gettextFromC", "%1 %2, %3\n%4:%5") - .arg(monthname(tm.tm_mon)) - .arg(tm.tm_mday) - .arg(tm.tm_year + 1900) - .arg(tm.tm_hour, 2, 10, QChar('0')) - .arg(tm.tm_min, 2, 10, QChar('0')); + .arg(monthname(tm.tm_mon)) + .arg(tm.tm_mday) + .arg(tm.tm_year + 1900) + .arg(tm.tm_hour, 2, 10, QChar('0')) + .arg(tm.tm_min, 2, 10, QChar('0')); } QString get_trip_date_string(timestamp_t when, int nr) @@ -417,11 +417,11 @@ QString get_trip_date_string(timestamp_t when, int nr) utc_mkdate(when, &tm); if (nr != 1) return translate("gettextFromC", "%1 %2 (%3 dives)") - .arg(monthname(tm.tm_mon)) - .arg(tm.tm_year + 1900) - .arg(nr); + .arg(monthname(tm.tm_mon)) + .arg(tm.tm_year + 1900) + .arg(nr); else return translate("gettextFromC", "%1 %2 (1 dive)") - .arg(monthname(tm.tm_mon)) - .arg(tm.tm_year + 1900); + .arg(monthname(tm.tm_mon)) + .arg(tm.tm_year + 1900); } diff --git a/qt-ui/completionmodels.cpp b/qt-ui/completionmodels.cpp index 30e69d26a..7d7f7cd2b 100644 --- a/qt-ui/completionmodels.cpp +++ b/qt-ui/completionmodels.cpp @@ -8,7 +8,7 @@ QStringList list; \ struct dive *dive; \ int i = 0; \ - for_each_dive(i, dive) \ + for_each_dive (i, dive) \ { \ QString buddy(dive->diveStructMember); \ if (!list.contains(buddy)) { \ @@ -24,10 +24,10 @@ QSet<QString> set; \ struct dive *dive; \ int i = 0; \ - for_each_dive(i, dive) \ + for_each_dive (i, dive) \ { \ QString buddy(dive->diveStructMember); \ - foreach(const QString &value, buddy.split(",", QString::SkipEmptyParts)) \ + foreach (const QString &value, buddy.split(",", QString::SkipEmptyParts)) \ { \ set.insert(value.trimmed()); \ } \ diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp index 6fd5dee10..cbb75c102 100644 --- a/qt-ui/divelistview.cpp +++ b/qt-ui/divelistview.cpp @@ -9,6 +9,7 @@ #include "modeldelegates.h" #include "mainwindow.h" #include "subsurfacewebservices.h" +#include "divelogexportdialog.h" #include "../display.h" #include "exif.h" #include "../file.h" @@ -27,7 +28,8 @@ #include <iostream> #include "../qthelper.h" -DiveListView::DiveListView(QWidget *parent) : QTreeView(parent), mouseClickSelection(false), sortColumn(0), currentOrder(Qt::DescendingOrder), searchBox(this) +DiveListView::DiveListView(QWidget *parent) : QTreeView(parent), mouseClickSelection(false), sortColumn(0) + , currentOrder(Qt::DescendingOrder), searchBox(this), dontEmitDiveChangedSignal(false) { setItemDelegate(new DiveListDelegate(this)); setUniformRowHeights(true); @@ -57,7 +59,8 @@ DiveListView::DiveListView(QWidget *parent) : QTreeView(parent), mouseClickSelec searchBox.hide(); connect(showSearchBox, SIGNAL(triggered(bool)), this, SLOT(showSearchEdit())); connect(&searchBox, SIGNAL(textChanged(QString)), model, SLOT(setFilterFixedString(QString))); - setupUi(); + // calling setupUi() here appears to be too early; it does NOT correctly set the column widths + // setupUi(); } DiveListView::~DiveListView() @@ -122,7 +125,7 @@ void DiveListView::backupExpandedRows() void DiveListView::restoreExpandedRows() { setAnimated(false); - Q_FOREACH(const int & i, expandedRows) + Q_FOREACH (const int &i, expandedRows) setExpanded(model()->index(i, 0), true); setAnimated(true); } @@ -139,7 +142,7 @@ void DiveListView::rememberSelection() { selectedDives.clear(); QItemSelection selection = selectionModel()->selection(); - Q_FOREACH(const QModelIndex & index, selection.indexes()) { + Q_FOREACH (const QModelIndex &index, selection.indexes()) { if (index.column() != 0) // We only care about the dives, so, let's stick to rows and discard columns. continue; struct dive *d = (struct dive *)index.data(DiveTripModel::DIVE_ROLE).value<void *>(); @@ -151,18 +154,18 @@ void DiveListView::rememberSelection() void DiveListView::restoreSelection() { unselectDives(); - Q_FOREACH(dive_trip_t * trip, selectedDives.keys()) { + Q_FOREACH (dive_trip_t *trip, selectedDives.keys()) { QList<int> divesOnTrip = getDivesInTrip(trip); QList<int> selectedDivesOnTrip = selectedDives.values(trip); // Trip was not selected, let's select single-dives. if (trip == NULL || divesOnTrip.count() != selectedDivesOnTrip.count()) { - Q_FOREACH(int i, selectedDivesOnTrip) { + Q_FOREACH (int i, selectedDivesOnTrip) { selectDive(i); } } else { selectTrip(trip); - Q_FOREACH(int i, selectedDivesOnTrip) { + Q_FOREACH (int i, selectedDivesOnTrip) { selectDive(i); } } @@ -189,13 +192,20 @@ void DiveListView::selectTrip(dive_trip_t *trip) void DiveListView::unselectDives() { selectionModel()->clearSelection(); + // clearSelection should emit selectionChanged() but sometimes that + // appears not to happen + int i; + struct dive *dive; + for_each_dive(i, dive) { + deselect_dive(i); + } } QList<dive_trip_t *> DiveListView::selectedTrips() { QModelIndexList indexes = selectionModel()->selectedRows(); QList<dive_trip_t *> ret; - Q_FOREACH(const QModelIndex & index, indexes) { + Q_FOREACH (const QModelIndex &index, indexes) { dive_trip_t *trip = static_cast<dive_trip_t *>(index.data(DiveTripModel::TRIP_ROLE).value<void *>()); if (!trip) continue; @@ -211,6 +221,8 @@ void DiveListView::selectDive(int i, bool scrollto, bool toggle) QSortFilterProxyModel *m = qobject_cast<QSortFilterProxyModel *>(model()); QModelIndexList match = m->match(m->index(0, 0), DiveTripModel::DIVE_IDX, i, 2, Qt::MatchRecursive); QItemSelectionModel::SelectionFlags flags; + if (match.isEmpty()) + return; QModelIndex idx = match.first(); flags = toggle ? QItemSelectionModel::Toggle : QItemSelectionModel::Select; flags |= QItemSelectionModel::Rows; @@ -231,54 +243,24 @@ void DiveListView::selectDives(const QList<int> &newDiveSelection) if (!newDiveSelection.count()) return; - disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(selectionChanged(QItemSelection, QItemSelection))); - disconnect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), - this, SLOT(currentChanged(QModelIndex, QModelIndex))); + dontEmitDiveChangedSignal = true; + // select the dives, highest index first - this way the oldest of the dives + // becomes the selected_dive that we scroll to + QList<int> sortedSelection = newDiveSelection; + qSort(sortedSelection.begin(), sortedSelection.end()); + while (!sortedSelection.isEmpty()) + selectDive(sortedSelection.takeLast()); - setAnimated(false); - collapseAll(); QSortFilterProxyModel *m = qobject_cast<QSortFilterProxyModel *>(model()); - QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::Select | QItemSelectionModel::Rows; - - QItemSelection newDeselected = selectionModel()->selection(); - QModelIndexList diveList; - - //TODO: This should be called find_first_selected_dive and be ported to C code. - int firstSelectedDive = -1; - /* context for temp. variables. */ { - int i = 0; - struct dive *dive; - for_each_dive(i, dive) { - dive->selected = newDiveSelection.contains(i) == true; - if (firstSelectedDive == -1 && dive->selected) { - firstSelectedDive = i; - break; - } - } - } - select_dive(firstSelectedDive); - Q_FOREACH(int i, newDiveSelection) { - diveList.append(m->match(m->index(0, 0), DiveTripModel::DIVE_IDX, - i, 2, Qt::MatchRecursive).first()); - } - Q_FOREACH(const QModelIndex & idx, diveList) { - selectionModel()->select(idx, flags); - if (idx.parent().isValid() && !isExpanded(idx.parent())) { - expand(idx.parent()); - } - } - setAnimated(true); - QTreeView::selectionChanged(selectionModel()->selection(), newDeselected); - connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(selectionChanged(QItemSelection, QItemSelection))); - connect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), - this, SLOT(currentChanged(QModelIndex, QModelIndex))); - Q_EMIT currentDiveChanged(selected_dive); QModelIndex idx = m->match(m->index(0, 0), DiveTripModel::DIVE_IDX, selected_dive, 2, Qt::MatchRecursive).first(); if (idx.parent().isValid()) scrollTo(idx.parent()); scrollTo(idx); + + // now that everything is up to date, update the widgets + Q_EMIT currentDiveChanged(selected_dive); + dontEmitDiveChangedSignal = false; + return; } void DiveListView::showSearchEdit() @@ -328,10 +310,19 @@ void DiveListView::headerClicked(int i) } } restoreSelection(); + // remember the new sort column + sortColumn = i; } void DiveListView::reload(DiveTripModel::Layout layout, bool forceSort) { + // we want to run setupUi() once we actually are displaying something + // in the widget + static bool first = true; + if (first && dive_table.nr > 0) { + setupUi(); + first = false; + } if (layout == DiveTripModel::CURRENT) layout = currentLayout; else @@ -368,7 +359,6 @@ void DiveListView::reload(DiveTripModel::Layout layout, bool forceSort) setCurrentIndex(firstDiveOrTrip); } } - setupUi(); if (selectedIndexes().count()) { QModelIndex curr = selectedIndexes().first(); curr = curr.parent().isValid() ? curr.parent() : curr; @@ -396,7 +386,7 @@ void DiveListView::reloadHeaderActions() QString settingName = QString("showColumn%1").arg(i); QAction *a = new QAction(title, header()); bool showHeaderFirstRun = !( - i == DiveTripModel::MAXCNS || i == DiveTripModel::NITROX || i == DiveTripModel::OTU || i == DiveTripModel::TEMPERATURE || i == DiveTripModel::TOTALWEIGHT || i == DiveTripModel::SUIT || i == DiveTripModel::CYLINDER || i == DiveTripModel::SAC); + i == DiveTripModel::MAXCNS || i == DiveTripModel::NITROX || i == DiveTripModel::OTU || i == DiveTripModel::TEMPERATURE || i == DiveTripModel::TOTALWEIGHT || i == DiveTripModel::SUIT || i == DiveTripModel::CYLINDER || i == DiveTripModel::SAC); bool shown = s.value(settingName, showHeaderFirstRun).toBool(); a->setCheckable(true); a->setChecked(shown); @@ -445,39 +435,26 @@ void DiveListView::selectionChanged(const QItemSelection &selected, const QItemS disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChanged(QItemSelection, QItemSelection))); disconnect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentChanged(QModelIndex, QModelIndex))); - Q_FOREACH(const QModelIndex & index, newDeselected.indexes()) { + Q_FOREACH (const QModelIndex &index, newDeselected.indexes()) { if (index.column() != 0) continue; const QAbstractItemModel *model = index.model(); struct dive *dive = (struct dive *)model->data(index, DiveTripModel::DIVE_ROLE).value<void *>(); - if (!dive) { // it's a trip! - //TODO: deselect_trip_dives on c-code? - if (model->rowCount(index)) { - struct dive *child = (struct dive *)model->data(index.child(0, 0), DiveTripModel::DIVE_ROLE).value<void *>(); - while (child) { - deselect_dive(get_divenr(child)); - child = child->next; - } - } - } else { + if (!dive) // it's a trip! + deselect_dives_in_trip((dive_trip_t *)model->data(index, DiveTripModel::TRIP_ROLE).value<void *>()); + else deselect_dive(get_divenr(dive)); - } } - Q_FOREACH(const QModelIndex & index, newSelected.indexes()) { + Q_FOREACH (const QModelIndex &index, newSelected.indexes()) { if (index.column() != 0) continue; const QAbstractItemModel *model = index.model(); struct dive *dive = (struct dive *)model->data(index, DiveTripModel::DIVE_ROLE).value<void *>(); if (!dive) { // it's a trip! - //TODO: select_trip_dives on C code? if (model->rowCount(index)) { QItemSelection selection; - struct dive *child = (struct dive *)model->data(index.child(0, 0), DiveTripModel::DIVE_ROLE).value<void *>(); - while (child) { - select_dive(get_divenr(child)); - child = child->next; - } + select_dives_in_trip((dive_trip_t *)model->data(index, DiveTripModel::TRIP_ROLE).value<void *>()); selection.select(index.child(0, 0), index.child(model->rowCount(index) - 1, 0)); selectionModel()->select(selection, QItemSelectionModel::Select | QItemSelectionModel::Rows); selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select | QItemSelectionModel::NoUpdate); @@ -491,8 +468,8 @@ void DiveListView::selectionChanged(const QItemSelection &selected, const QItemS QTreeView::selectionChanged(selectionModel()->selection(), newDeselected); connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChanged(QItemSelection, QItemSelection))); connect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentChanged(QModelIndex, QModelIndex))); - // now that everything is up to date, update the widgets - Q_EMIT currentDiveChanged(selected_dive); + if(!dontEmitDiveChangedSignal) + Q_EMIT currentDiveChanged(selected_dive); } static bool can_merge(const struct dive *a, const struct dive *b) @@ -512,7 +489,7 @@ void DiveListView::mergeDives() int i; struct dive *dive, *maindive = NULL; - for_each_dive(i, dive) { + for_each_dive (i, dive) { if (dive->selected) { if (!can_merge(maindive, dive)) { maindive = dive; @@ -525,6 +502,12 @@ void DiveListView::mergeDives() MainWindow::instance()->refreshDisplay(); } +void DiveListView::renumberDives() +{ + RenumberDialog::instance()->renumberOnlySelected(); + RenumberDialog::instance()->show(); +} + void DiveListView::merge_trip(const QModelIndex &a, int offset) { int i = a.row() + offset; @@ -532,17 +515,9 @@ void DiveListView::merge_trip(const QModelIndex &a, int offset) dive_trip_t *trip_a = (dive_trip_t *)a.data(DiveTripModel::TRIP_ROLE).value<void *>(); dive_trip_t *trip_b = (dive_trip_t *)b.data(DiveTripModel::TRIP_ROLE).value<void *>(); - // TODO: merge_trip on the C code? some part of this needs to stay ( getting the trips from the model, - // but not the algorithm. if (trip_a == trip_b || !trip_a || !trip_b) return; - - if (!trip_a->location && trip_b->location) - trip_a->location = strdup(trip_b->location); - if (!trip_a->notes && trip_b->notes) - trip_a->notes = strdup(trip_b->notes); - while (trip_b->dives) - add_dive_to_trip(trip_b->dives, trip_a); + combine_trips(trip_a, trip_b); rememberSelection(); reload(currentLayout, false); fixMessyQtModelBehaviour(); @@ -566,7 +541,7 @@ void DiveListView::removeFromTrip() //TODO: move this to C-code. int i; struct dive *d; - for_each_dive(i, d) { + for_each_dive (i, d) { if (d->selected) remove_dive_from_trip(d, false); } @@ -587,7 +562,7 @@ void DiveListView::newTripAbove() int idx; rememberSelection(); trip = create_and_hookup_trip_from_dive(d); - for_each_dive(idx, d) { + for_each_dive (idx, d) { if (d->selected) add_dive_to_trip(d, trip); } @@ -610,7 +585,7 @@ void DiveListView::addToTripAbove() void DiveListView::addToTrip(bool below) { - int delta = (currentOrder == Qt::AscendingOrder) ? -1 : +1; + int delta = (currentOrder == Qt::AscendingOrder) ? -1 : +1; struct dive *d = (struct dive *)contextMenuIndex.data(DiveTripModel::DIVE_ROLE).value<void *>(); rememberSelection(); @@ -623,18 +598,10 @@ void DiveListView::addToTrip(bool below) if (d->selected) { // we are right-clicking on one of possibly many selected dive(s) // find the top selected dive, depending on the list order - if (delta == 1) { - for_each_dive(idx, d) { - if (d->selected) - pd = d; - } - d = pd; // this way we have the chronologically last - } else { - for_each_dive(idx, d) { - if (d->selected) - break; // now that's the chronologically first - } - } + if (delta == 1) + d = last_selected_dive(); + else + d = first_selected_dive(); } // now find the trip "above" in the dive list if ((pd = get_dive(get_divenr(d) + delta)) != NULL) { @@ -645,7 +612,7 @@ void DiveListView::addToTrip(bool below) return; add_dive_to_trip(d, trip); if (d->selected) { // there are possibly other selected dives that we should add - for_each_dive(idx, d) { + for_each_dive (idx, d) { if (d->selected) add_dive_to_trip(d, trip); } @@ -664,7 +631,7 @@ void DiveListView::markDiveInvalid() struct dive *d = (struct dive *)contextMenuIndex.data(DiveTripModel::DIVE_ROLE).value<void *>(); if (!d) return; - for_each_dive(i, d) { + for_each_dive (i, d) { if (!d->selected) continue; //TODO: this should be done in the future @@ -696,8 +663,7 @@ void DiveListView::deleteDive() // so instead of using the for_each_dive macro I'm using an explicit for loop // to make this easier to understand int lastDiveNr = -1; - for (i = 0; i < dive_table.nr; i++) { - d = get_dive(i); + for_each_dive (i, d) { if (!d->selected) continue; delete_single_dive(i); @@ -747,8 +713,23 @@ void DiveListView::contextMenuEvent(QContextMenuEvent *event) if (d) { popup.addAction(tr("remove dive(s) from trip"), this, SLOT(removeFromTrip())); popup.addAction(tr("create new trip above"), this, SLOT(newTripAbove())); - popup.addAction(tr("add dive(s) to trip immediately above"), this, SLOT(addToTripAbove())); - popup.addAction(tr("add dive(s) to trip immediately below"), this, SLOT(addToTripBelow())); + if (!d->divetrip) { + struct dive *top = d; + struct dive *bottom = d; + if (d->selected) { + if (currentOrder == Qt::AscendingOrder) { + top = first_selected_dive(); + bottom = last_selected_dive(); + } else { + top = last_selected_dive(); + bottom = first_selected_dive(); + } + } + if (is_trip_before_after(top, (currentOrder == Qt::AscendingOrder))) + popup.addAction(tr("add dive(s) to trip immediately above"), this, SLOT(addToTripAbove())); + if (is_trip_before_after(bottom, (currentOrder == Qt::DescendingOrder))) + popup.addAction(tr("add dive(s) to trip immediately below"), this, SLOT(addToTripBelow())); + } } if (trip) { popup.addAction(tr("merge trip with trip above"), this, SLOT(mergeTripAbove())); @@ -764,14 +745,10 @@ void DiveListView::contextMenuEvent(QContextMenuEvent *event) if (amount_selected > 1 && consecutive_selected()) popup.addAction(tr("merge selected dives"), this, SLOT(mergeDives())); if (amount_selected >= 1) { - popup.addAction(tr("save As"), this, SLOT(saveSelectedDivesAs())); - popup.addAction(tr("export As UDDF"), this, SLOT(exportSelectedDivesAsUDDF())); - popup.addAction(tr("export As CSV"), this, SLOT(exportSelectedDivesAsCSV())); + popup.addAction(tr("renumber dive(s)"), this, SLOT(renumberDives())); popup.addAction(tr("shift times"), this, SLOT(shiftTimes())); popup.addAction(tr("load images"), this, SLOT(loadImages())); } - if (d) - popup.addAction(tr("upload dive(s) to divelogs.de"), this, SLOT(uploadToDivelogsDE())); // "collapse all" really closes all trips, // "collapse" keeps the trip with the selected dive open QAction *actionTaken = popup.exec(event->globalPos()); @@ -784,56 +761,6 @@ void DiveListView::contextMenuEvent(QContextMenuEvent *event) event->accept(); } -void DiveListView::saveSelectedDivesAs() -{ - QSettings settings; - QString lastDir = QDir::homePath(); - - settings.beginGroup("FileDialog"); - if (settings.contains("LastDir")) { - if (QDir::setCurrent(settings.value("LastDir").toString())) { - lastDir = settings.value("LastDir").toString(); - } - } - settings.endGroup(); - - QString fileName = QFileDialog::getSaveFileName(MainWindow::instance(), tr("Save Dives As..."), QDir::homePath()); - if (fileName.isEmpty()) - return; - - // Keep last open dir - QFileInfo fileInfo(fileName); - settings.beginGroup("FileDialog"); - settings.setValue("LastDir", fileInfo.dir().path()); - settings.endGroup(); - - QByteArray bt = QFile::encodeName(fileName); - save_dives_logic(bt.data(), true); -} - -void DiveListView::exportSelectedDivesAsUDDF() -{ - QString filename; - QFileInfo fi(system_default_filename()); - - filename = QFileDialog::getSaveFileName(this, tr("Export UDDF File as"), fi.absolutePath(), - tr("UDDF files (*.uddf *.UDDF)")); - if (!filename.isNull() && !filename.isEmpty()) - export_dives_xslt(filename.toUtf8(), true, "uddf-export.xslt"); -} - -void DiveListView::exportSelectedDivesAsCSV() -{ - QString filename; - QFileInfo fi(system_default_filename()); - - filename = QFileDialog::getSaveFileName(this, tr("Export CSV File as"), fi.absolutePath(), - tr("CSV files (*.csv *.CSV)")); - if (!filename.isNull() && !filename.isEmpty()) - export_dives_xslt(filename.toUtf8(), true, "xml2csv.xslt"); -} - - void DiveListView::shiftTimes() { ShiftTimesDialog::instance()->show(); @@ -874,11 +801,10 @@ void DiveListView::loadImages() imagetime += shiftDialog.amount(); // TODO: this should be cached and passed to the C-function int j = 0; struct dive *dive; - for_each_dive(j, dive) { + for_each_dive (j, dive) { if (!dive->selected) continue; - dc = &(dive->dc); - while (dc) { + for_each_dc (dive, dc) { when = dc->when ? dc->when : dive->when; duration_s = dc->duration.seconds ? dc->duration.seconds : dive->duration.seconds; if (when - 3600 < imagetime && when + duration_s + 3600 > imagetime) { @@ -899,17 +825,11 @@ void DiveListView::loadImages() MainWindow::instance()->refreshDisplay(); MainWindow::instance()->graphics()->replot(); } - dc = dc->next; } } } } -void DiveListView::uploadToDivelogsDE() -{ - DivelogsDeWebServices::instance()->prepareDivesForUpload(); -} - QString DiveListView::lastUsedImageDir() { QSettings settings; diff --git a/qt-ui/divelistview.h b/qt-ui/divelistview.h index d946b1854..23ca1cc42 100644 --- a/qt-ui/divelistview.h +++ b/qt-ui/divelistview.h @@ -48,12 +48,9 @@ slots: void addToTripAbove(); void addToTripBelow(); void mergeDives(); - void saveSelectedDivesAs(); - void exportSelectedDivesAsUDDF(); - void exportSelectedDivesAsCSV(); + void renumberDives(); void shiftTimes(); void loadImages(); - void uploadToDivelogsDE(); static QString lastUsedImageDir(); signals: @@ -67,6 +64,7 @@ private: DiveTripModel::Layout currentLayout; QLineEdit searchBox; QModelIndex contextMenuIndex; + bool dontEmitDiveChangedSignal; /* if dive_trip_t is null, there's no problem. */ QMultiHash<dive_trip_t *, int> selectedDives; diff --git a/qt-ui/divelogexportdialog.cpp b/qt-ui/divelogexportdialog.cpp new file mode 100644 index 000000000..28f343257 --- /dev/null +++ b/qt-ui/divelogexportdialog.cpp @@ -0,0 +1,98 @@ +#include <QFileDialog> +#include <QString> +#include <QShortcut> +#include <QAbstractButton> +#include <QDebug> +#include <QSettings> + +#include "mainwindow.h" +#include "divelogexportdialog.h" +#include "ui_divelogexportdialog.h" +#include "subsurfacewebservices.h" +#include "worldmap-save.h" + +DiveLogExportDialog::DiveLogExportDialog(QWidget *parent) : QDialog(parent), + ui(new Ui::DiveLogExportDialog) +{ + ui->setupUi(this); + showExplanation(); + QShortcut *quit = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this); + connect(quit, SIGNAL(activated()), parent, SLOT(close())); + QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this); + connect(close, SIGNAL(activated()), this, SLOT(close())); +} + +DiveLogExportDialog::~DiveLogExportDialog() +{ + delete ui; +} + +void DiveLogExportDialog::showExplanation() +{ + if (ui->exportUDDF->isChecked()) { + ui->description->setText("Generic format that is used for data exchange between a variety of diving related programs."); + } else if (ui->exportCSV->isChecked()) { + ui->description->setText("Comma separated values that include the most relevant information of the dive profile."); + } else if (ui->exportDivelogs->isChecked()) { + ui->description->setText("Send the dive data to Divelogs.de website."); + } else if (ui->exportWorldMap->isChecked()) { + ui->description->setText("HTML export of the dive locations, visualized on a world map."); + } else if (ui->exportSubsurfaceXML->isChecked()) { + ui->description->setText("Subsurface native XML format."); + } +} + +void DiveLogExportDialog::on_exportGroup_buttonClicked(QAbstractButton *button) +{ + showExplanation(); +} + +void DiveLogExportDialog::on_buttonBox_accepted() +{ + QString filename; + QString stylesheet; + QSettings settings; + QString lastDir = QDir::homePath(); + + settings.beginGroup("FileDialog"); + if (settings.contains("LastDir")) { + if (QDir::setCurrent(settings.value("LastDir").toString())) { + lastDir = settings.value("LastDir").toString(); + } + } + settings.endGroup(); + + if (ui->exportUDDF->isChecked()) { + stylesheet = "uddf-export.xslt"; + filename = QFileDialog::getSaveFileName(this, tr("Export UDDF File as"), lastDir, + tr("UDDF files (*.uddf *.UDDF)")); + } else if (ui->exportCSV->isChecked()) { + stylesheet = "xml2csv.xslt"; + filename = QFileDialog::getSaveFileName(this, tr("Export CSV File as"), lastDir, + tr("CSV files (*.csv *.CSV)")); + } else if (ui->exportDivelogs->isChecked()) { + DivelogsDeWebServices::instance()->prepareDivesForUpload(ui->exportSelected->isChecked()); + } else if (ui->exportWorldMap->isChecked()) { + filename = QFileDialog::getSaveFileName(this, tr("Export World Map"), lastDir, + tr("HTML files (*.html)")); + if (!filename.isNull() && !filename.isEmpty()) + export_worldmap_HTML(filename.toUtf8().data(), ui->exportSelected->isChecked()); + } else if (ui->exportSubsurfaceXML->isChecked()) { + filename = QFileDialog::getSaveFileName(this, tr("Export Subsurface XML"), lastDir, + tr("XML files (*.xml *.ssrf)")); + if (!filename.isNull() && !filename.isEmpty()) { + QByteArray bt = QFile::encodeName(filename); + save_dives_logic(bt.data(), true); + } + } + if (!filename.isNull() && !filename.isEmpty()) { + // remember the last export path + QFileInfo fileInfo(filename); + settings.beginGroup("FileDialog"); + settings.setValue("LastDir", fileInfo.dir().path()); + settings.endGroup(); + // the non XSLT exports are called directly above, the XSLT based ons are called here + if (!stylesheet.isEmpty()) + export_dives_xslt(filename.toUtf8(), ui->exportSelected->isChecked(), stylesheet.toStdString().c_str()); + } +} diff --git a/qt-ui/divelogexportdialog.h b/qt-ui/divelogexportdialog.h new file mode 100644 index 000000000..92510a7aa --- /dev/null +++ b/qt-ui/divelogexportdialog.h @@ -0,0 +1,28 @@ +#ifndef DIVELOGEXPORTDIALOG_H +#define DIVELOGEXPORTDIALOG_H + +#include <QDialog> +#include <QAbstractButton> + +namespace Ui { + class DiveLogExportDialog; +} + +class DiveLogExportDialog : public QDialog { + Q_OBJECT + +public: + explicit DiveLogExportDialog(QWidget *parent = 0); + ~DiveLogExportDialog(); + +private +slots: + void on_buttonBox_accepted(); + void on_exportGroup_buttonClicked(QAbstractButton *); + +private: + Ui::DiveLogExportDialog *ui; + void showExplanation(); +}; + +#endif // DIVELOGEXPORTDIALOG_H diff --git a/qt-ui/divelogexportdialog.ui b/qt-ui/divelogexportdialog.ui new file mode 100644 index 000000000..72e373127 --- /dev/null +++ b/qt-ui/divelogexportdialog.ui @@ -0,0 +1,283 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>DiveLogExportDialog</class> + <widget class="QDialog" name="DiveLogExportDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>448</width> + <height>473</height> + </rect> + </property> + <property name="windowTitle"> + <string>Export Dive Log Files</string> + </property> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="geometry"> + <rect> + <x>20</x> + <y>420</y> + <width>341</width> + <height>32</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + <widget class="QLabel" name="label_3"> + <property name="geometry"> + <rect> + <x>-50</x> + <y>10</y> + <width>497</width> + <height>24</height> + </rect> + </property> + <property name="font"> + <font> + <family>Droid Sans [unknown]</family> + <pointsize>14</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="text"> + <string>Export Dive Log Files</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QGroupBox" name="exportFormat"> + <property name="geometry"> + <rect> + <x>20</x> + <y>70</y> + <width>201</width> + <height>211</height> + </rect> + </property> + <property name="title"> + <string>Export format</string> + </property> + <widget class="QRadioButton" name="exportUDDF"> + <property name="geometry"> + <rect> + <x>10</x> + <y>70</y> + <width>110</width> + <height>24</height> + </rect> + </property> + <property name="maximumSize"> + <size> + <width>110</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>UDDF</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <attribute name="buttonGroup"> + <string notr="true">exportGroup</string> + </attribute> + </widget> + <widget class="QRadioButton" name="exportDivelogs"> + <property name="geometry"> + <rect> + <x>10</x> + <y>100</y> + <width>131</width> + <height>24</height> + </rect> + </property> + <property name="text"> + <string>divelogs.de</string> + </property> + <attribute name="buttonGroup"> + <string notr="true">exportGroup</string> + </attribute> + </widget> + <widget class="QRadioButton" name="exportCSV"> + <property name="geometry"> + <rect> + <x>10</x> + <y>130</y> + <width>110</width> + <height>24</height> + </rect> + </property> + <property name="text"> + <string>CSV</string> + </property> + <attribute name="buttonGroup"> + <string notr="true">exportGroup</string> + </attribute> + </widget> + <widget class="QRadioButton" name="exportWorldMap"> + <property name="geometry"> + <rect> + <x>10</x> + <y>160</y> + <width>171</width> + <height>24</height> + </rect> + </property> + <property name="text"> + <string>Worldmap</string> + </property> + <attribute name="buttonGroup"> + <string notr="true">exportGroup</string> + </attribute> + </widget> + <widget class="QRadioButton" name="exportSubsurfaceXML"> + <property name="geometry"> + <rect> + <x>10</x> + <y>40</y> + <width>171</width> + <height>21</height> + </rect> + </property> + <property name="maximumSize"> + <size> + <width>171</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Subsurface XML</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <attribute name="buttonGroup"> + <string notr="true">exportGroup</string> + </attribute> + </widget> + </widget> + <widget class="QGroupBox" name="exportSelection"> + <property name="geometry"> + <rect> + <x>240</x> + <y>70</y> + <width>191</width> + <height>141</height> + </rect> + </property> + <property name="title"> + <string>Selection</string> + </property> + <widget class="QRadioButton" name="exportSelected"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="geometry"> + <rect> + <x>10</x> + <y>30</y> + <width>151</width> + <height>24</height> + </rect> + </property> + <property name="text"> + <string>Selected dives</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton" name="exportAll"> + <property name="geometry"> + <rect> + <x>10</x> + <y>60</y> + <width>110</width> + <height>24</height> + </rect> + </property> + <property name="text"> + <string>All dives</string> + </property> + </widget> + </widget> + <widget class="Line" name="line"> + <property name="geometry"> + <rect> + <x>60</x> + <y>280</y> + <width>231</width> + <height>16</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + <widget class="QLabel" name="description"> + <property name="geometry"> + <rect> + <x>30</x> + <y>310</y> + <width>341</width> + <height>91</height> + </rect> + </property> + <property name="text"> + <string/> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>DiveLogExportDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>DiveLogExportDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> + <buttongroups> + <buttongroup name="exportGroup"/> + </buttongroups> +</ui> diff --git a/qt-ui/divelogimportdialog.h b/qt-ui/divelogimportdialog.h index 4c499b03e..fb44faa94 100644 --- a/qt-ui/divelogimportdialog.h +++ b/qt-ui/divelogimportdialog.h @@ -6,8 +6,7 @@ #include "../dive.h" #include "../divelist.h" -namespace Ui -{ +namespace Ui { class DiveLogImportDialog; } diff --git a/qt-ui/diveplanner.cpp b/qt-ui/diveplanner.cpp index 24aa7f697..ada2b4e73 100644 --- a/qt-ui/diveplanner.cpp +++ b/qt-ui/diveplanner.cpp @@ -43,264 +43,6 @@ QString dpGasToStr(const divedatapoint &p) static DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); -DivePlannerGraphics::DivePlannerGraphics(QWidget *parent) : QGraphicsView(parent), - verticalLine(new QGraphicsLineItem(fromPercent(0, Qt::Horizontal), fromPercent(0, Qt::Vertical), fromPercent(0, Qt::Horizontal), fromPercent(100, Qt::Vertical))), - horizontalLine(new QGraphicsLineItem(fromPercent(0, Qt::Horizontal), fromPercent(0, Qt::Vertical), fromPercent(100, Qt::Horizontal), fromPercent(0, Qt::Vertical))), - activeDraggedHandler(0), - diveBg(new QGraphicsPolygonItem()), - timeLine(new Ruler()), - timeString(new QGraphicsSimpleTextItem()), - depthString(new QGraphicsSimpleTextItem()), - depthHandler(new ExpanderGraphics()), - timeHandler(new ExpanderGraphics()), - minMinutes(TIME_INITIAL_MAX), - minDepth(M_OR_FT(40, 120)), - dpMaxTime(0) -{ - setBackgroundBrush(profile_color[BACKGROUND].at(0)); - setMouseTracking(true); - setScene(new QGraphicsScene()); - scene()->setSceneRect(0, 0, 1920, 1080); - - verticalLine->setPen(QPen(Qt::DotLine)); - scene()->addItem(verticalLine); - - horizontalLine->setPen(QPen(Qt::DotLine)); - scene()->addItem(horizontalLine); - - timeLine->setMinimum(0); - timeLine->setMaximum(TIME_INITIAL_MAX); - timeLine->setTickInterval(10); - timeLine->setColor(getColor(TIME_GRID)); - timeLine->setLine(fromPercent(10, Qt::Horizontal), - fromPercent(85, Qt::Vertical), - fromPercent(90, Qt::Horizontal), - fromPercent(85, Qt::Vertical)); - timeLine->setOrientation(Qt::Horizontal); - timeLine->setTickSize(fromPercent(1, Qt::Vertical)); - timeLine->setTextColor(getColor(TIME_TEXT)); - timeLine->updateTicks(); - scene()->addItem(timeLine); - - depthLine = new Ruler(); - depthLine->setMinimum(0); - depthLine->setMaximum(M_OR_FT(40, 120)); - depthLine->setTickInterval(M_OR_FT(10, 30)); - depthLine->setLine(fromPercent(10, Qt::Horizontal), - fromPercent(10, Qt::Vertical), - fromPercent(10, Qt::Horizontal), - fromPercent(85, Qt::Vertical)); - depthLine->setOrientation(Qt::Vertical); - depthLine->setTickSize(fromPercent(1, Qt::Horizontal)); - depthLine->setColor(getColor(DEPTH_GRID)); - depthLine->setTextColor(getColor(SAMPLE_DEEP)); - depthLine->updateTicks(); - depthLine->unitSystem = prefs.units.length; - scene()->addItem(depthLine); - - timeString->setFlag(QGraphicsItem::ItemIgnoresTransformations); - timeString->setBrush(profile_color[TIME_TEXT].at(0)); - scene()->addItem(timeString); - - depthString->setFlag(QGraphicsItem::ItemIgnoresTransformations); - depthString->setBrush(profile_color[SAMPLE_DEEP].at(0)); - scene()->addItem(depthString); - - diveBg->setPen(QPen(QBrush(), 0)); - scene()->addItem(diveBg); - - QString incrText; - if (prefs.units.length == units::METERS) - incrText = tr("10m"); - else - incrText = tr("30ft"); - - timeHandler->increaseBtn->setPixmap(QString(":plan_plus")); - timeHandler->decreaseBtn->setPixmap(QString(":plan_minus")); - timeHandler->icon->setPixmap(QString(":icon_time")); - connect(timeHandler->increaseBtn, SIGNAL(clicked()), this, SLOT(increaseTime())); - connect(timeHandler->decreaseBtn, SIGNAL(clicked()), this, SLOT(decreaseTime())); - timeHandler->setPos(fromPercent(83, Qt::Horizontal), fromPercent(100, Qt::Vertical)); - timeHandler->setZValue(-2); - scene()->addItem(timeHandler); - - depthHandler->increaseBtn->setPixmap(QString(":arrow_down")); - depthHandler->decreaseBtn->setPixmap(QString(":arrow_up")); - depthHandler->icon->setPixmap(QString(":icon_depth")); - connect(depthHandler->decreaseBtn, SIGNAL(clicked()), this, SLOT(decreaseDepth())); - connect(depthHandler->increaseBtn, SIGNAL(clicked()), this, SLOT(increaseDepth())); - depthHandler->setPos(fromPercent(0, Qt::Horizontal), fromPercent(100, Qt::Vertical)); - depthHandler->setZValue(-2); - scene()->addItem(depthHandler); - - QAction *action = NULL; - -#define ADD_ACTION(SHORTCUT, Slot) \ - action = new QAction(this); \ - action->setShortcut(SHORTCUT); \ - action->setShortcutContext(Qt::WindowShortcut); \ - addAction(action); \ - connect(action, SIGNAL(triggered(bool)), this, SLOT(Slot)) - - ADD_ACTION(Qt::Key_Escape, keyEscAction()); - ADD_ACTION(Qt::Key_Delete, keyDeleteAction()); - ADD_ACTION(Qt::Key_Up, keyUpAction()); - ADD_ACTION(Qt::Key_Down, keyDownAction()); - ADD_ACTION(Qt::Key_Left, keyLeftAction()); - ADD_ACTION(Qt::Key_Right, keyRightAction()); -#undef ADD_ACTION - - connect(plannerModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(drawProfile())); - connect(plannerModel, SIGNAL(cylinderModelEdited()), this, SLOT(drawProfile())); - - connect(plannerModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), - this, SLOT(pointInserted(const QModelIndex &, int, int))); - connect(plannerModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), - this, SLOT(pointsRemoved(const QModelIndex &, int, int))); - setRenderHint(QPainter::Antialiasing); -} - -void DivePlannerGraphics::settingsChanged() -{ - if (depthLine->unitSystem == prefs.units.length) - return; - - depthLine->setTickInterval(M_OR_FT(10, 30)); - depthLine->updateTicks(); - depthLine->unitSystem = prefs.units.length; -} - -void DivePlannerGraphics::pointInserted(const QModelIndex &parent, int start, int end) -{ - DiveHandler *item = new DiveHandler(); - scene()->addItem(item); - handles << item; - - QGraphicsSimpleTextItem *gasChooseBtn = new QGraphicsSimpleTextItem(); - scene()->addItem(gasChooseBtn); - gasChooseBtn->setZValue(10); - gasChooseBtn->setFlag(QGraphicsItem::ItemIgnoresTransformations); - gases << gasChooseBtn; - if (plannerModel->recalcQ()) - drawProfile(); -} - -void DivePlannerGraphics::keyDownAction() -{ - Q_FOREACH(QGraphicsItem * i, scene()->selectedItems()) { - if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { - int row = handles.indexOf(handler); - divedatapoint dp = plannerModel->at(row); - if (dp.depth >= depthLine->maximum()) - continue; - - dp.depth += M_OR_FT(1, 5); - plannerModel->editStop(row, dp); - } - } -} - -void DivePlannerGraphics::keyUpAction() -{ - Q_FOREACH(QGraphicsItem * i, scene()->selectedItems()) { - if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { - int row = handles.indexOf(handler); - divedatapoint dp = plannerModel->at(row); - - if (dp.depth <= 0) - continue; - - dp.depth -= M_OR_FT(1, 5); - plannerModel->editStop(row, dp); - } - } - drawProfile(); -} - -void DivePlannerGraphics::keyLeftAction() -{ - Q_FOREACH(QGraphicsItem * i, scene()->selectedItems()) { - if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { - int row = handles.indexOf(handler); - divedatapoint dp = plannerModel->at(row); - - if (dp.time / 60 <= 0) - continue; - - // don't overlap positions. - // maybe this is a good place for a 'goto'? - double xpos = timeLine->posAtValue((dp.time - 60) / 60); - bool nextStep = false; - Q_FOREACH(DiveHandler * h, handles) { - if (IS_FP_SAME(h->pos().x(), xpos)) { - nextStep = true; - break; - } - } - if (nextStep) - continue; - - dp.time -= 60; - plannerModel->editStop(row, dp); - } - } -} - -void DivePlannerGraphics::keyRightAction() -{ - Q_FOREACH(QGraphicsItem * i, scene()->selectedItems()) { - if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { - int row = handles.indexOf(handler); - divedatapoint dp = plannerModel->at(row); - if (dp.time / 60 >= timeLine->maximum()) - continue; - - // don't overlap positions. - // maybe this is a good place for a 'goto'? - double xpos = timeLine->posAtValue((dp.time + 60) / 60); - bool nextStep = false; - Q_FOREACH(DiveHandler * h, handles) { - if (IS_FP_SAME(h->pos().x(), xpos)) { - nextStep = true; - break; - } - } - if (nextStep) - continue; - - dp.time += 60; - plannerModel->editStop(row, dp); - } - } -} - -void DivePlannerGraphics::keyDeleteAction() -{ - int selCount = scene()->selectedItems().count(); - if (selCount) { - QVector<int> selectedIndexes; - Q_FOREACH(QGraphicsItem * i, scene()->selectedItems()) { - if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { - selectedIndexes.push_back(handles.indexOf(handler)); - } - } - plannerModel->removeSelectedPoints(selectedIndexes); - } -} - -void DivePlannerGraphics::pointsRemoved(const QModelIndex &, int start, int end) -{ // start and end are inclusive. - int num = (end - start) + 1; - for (int i = num; i != 0; i--) { - delete handles.back(); - handles.pop_back(); - delete gases.back(); - gases.pop_back(); - } - scene()->clearSelection(); - drawProfile(); -} - bool intLessThan(int a, int b) { return a <= b; @@ -317,83 +59,6 @@ void DivePlannerPointsModel::removeSelectedPoints(const QVector<int> &rows) endRemoveRows(); } -void DivePlannerGraphics::keyEscAction() -{ - if (scene()->selectedItems().count()) { - scene()->clearSelection(); - return; - } - if (DivePlannerPointsModel::instance()->isPlanner()) - plannerModel->cancelPlan(); -} - -qreal DivePlannerGraphics::fromPercent(qreal percent, Qt::Orientation orientation) -{ - qreal total = orientation == Qt::Horizontal ? sceneRect().width() : sceneRect().height(); - qreal result = (total * percent) / 100; - return result; -} - -void DivePlannerGraphics::increaseDepth() -{ - if (depthLine->maximum() + M_OR_FT(10, 30) > MAX_DEPTH) - return; - minDepth += M_OR_FT(10, 30); - depthLine->setMaximum(minDepth); - depthLine->updateTicks(); - drawProfile(); -} - -void DivePlannerGraphics::increaseTime() -{ - minMinutes += 10; - timeLine->setMaximum(minMinutes); - timeLine->updateTicks(); - drawProfile(); -} - -void DivePlannerGraphics::decreaseDepth() -{ - if (depthLine->maximum() - M_OR_FT(10, 30) < MIN_DEPTH) - return; - - Q_FOREACH(DiveHandler * d, handles) { - if (depthLine->valueAt(d->pos()) > depthLine->maximum() - M_OR_FT(10, 30)) { - QMessageBox::warning(MainWindow::instance(), - tr("Handler Position Error"), - tr("One or more of your stops will be lost with this operations, \n" - "Please, remove them first.")); - return; - } - } - minDepth -= M_OR_FT(10, 30); - depthLine->setMaximum(minDepth); - depthLine->updateTicks(); - drawProfile(); -} - -void DivePlannerGraphics::decreaseTime() -{ - if (timeLine->maximum() - 10 < TIME_INITIAL_MAX || timeLine->maximum() - 10 < dpMaxTime) - return; - - minMinutes -= 10; - timeLine->setMaximum(timeLine->maximum() - 10); - timeLine->updateTicks(); - drawProfile(); -} - -void DivePlannerGraphics::mouseDoubleClickEvent(QMouseEvent *event) -{ - QPointF mappedPos = mapToScene(event->pos()); - if (isPointOutOfBoundaries(mappedPos)) - return; - - int minutes = rint(timeLine->valueAt(mappedPos)); - int milimeters = rint(depthLine->valueAt(mappedPos) / M_OR_FT(1, 1)) * M_OR_FT(1, 1); - plannerModel->addStop(milimeters, minutes * 60, -1, 0, 0, true); -} - void DivePlannerPointsModel::createSimpleDive() { // plannerModel->addStop(0, 0, O2_IN_AIR, 0, 0); @@ -470,252 +135,31 @@ void DivePlannerPointsModel::removeDeco() setRecalc(oldrec); } +#if 0 void DivePlannerGraphics::drawProfile() { - if (!plannerModel->recalcQ()) - return; - qDeleteAll(lines); - lines.clear(); - - plannerModel->createTemporaryPlan(); - struct diveplan diveplan = plannerModel->getDiveplan(); - struct divedatapoint *dp = diveplan.dp; - unsigned int max_depth = 0; - - if (!dp) { - plannerModel->deleteTemporaryPlan(); - return; - } - //TODO: divedatapoint_list_get_max_depth on C - code? - while (dp->next) { - if (dp->time && dp->depth > max_depth) - max_depth = dp->depth; - dp = dp->next; - } - - if (!activeDraggedHandler && (timeLine->maximum() < dp->time / 60.0 + 5 || dp->time / 60.0 + 15 < timeLine->maximum())) { - minMinutes = fmax(dp->time / 60.0 + 5, minMinutes); - timeLine->setMaximum(minMinutes); - timeLine->updateTicks(); - } - if (!activeDraggedHandler && (depthLine->maximum() < max_depth + M_OR_FT(10, 30) || max_depth + M_OR_FT(10, 30) < depthLine->maximum())) { - minDepth = fmax(max_depth + M_OR_FT(10, 30), minDepth); - depthLine->setMaximum(minDepth); - depthLine->updateTicks(); - } - - // Re-position the user generated dive handlers - int last = 0; - for (int i = 0; i < plannerModel->rowCount(); i++) { - struct divedatapoint datapoint = plannerModel->at(i); - if (datapoint.time == 0) // those are the magic entries for tanks - continue; - DiveHandler *h = handles.at(i); - h->setPos(timeLine->posAtValue(datapoint.time / 60), depthLine->posAtValue(datapoint.depth)); - QPointF p1 = (last == i) ? QPointF(timeLine->posAtValue(0), depthLine->posAtValue(0)) : handles[last]->pos(); - QPointF p2 = handles[i]->pos(); - QLineF line(p1, p2); - QPointF pos = line.pointAt(0.5); - gases[i]->setPos(pos); - gases[i]->setText(dpGasToStr(plannerModel->at(i))); - last = i; - } - - // (re-) create the profile with different colors for segments that were - // entered vs. segments that were calculated - double lastx = timeLine->posAtValue(0); - double lasty = depthLine->posAtValue(0); - - QPolygonF poly; - poly.append(QPointF(lastx, lasty)); - + // Code ported to the new profile is deleted. This part that I left here + // is because I didn't fully understood the reason of the magic with + // the plannerModel. bool oldRecalc = plannerModel->setRecalc(false); plannerModel->removeDeco(); - - unsigned int lastdepth = 0; - for (dp = diveplan.dp; dp != NULL; dp = dp->next) { - if (dp->time == 0) // magic entry for available tank - continue; - double xpos = timeLine->posAtValue(dp->time / 60.0); - double ypos = depthLine->posAtValue(dp->depth); - if (!dp->entered) { - QGraphicsLineItem *item = new QGraphicsLineItem(lastx, lasty, xpos, ypos); - item->setPen(QPen(QBrush(Qt::red), 0)); - - scene()->addItem(item); - lines << item; - if (dp->depth) { - if (dp->depth == lastdepth || dp->o2 != dp->next->o2 || dp->he != dp->next->he) - plannerModel->addStop(dp->depth, dp->time, dp->next->o2, dp->next->he, 0, false); - lastdepth = dp->depth; - } - } - lastx = xpos; - lasty = ypos; - poly.append(QPointF(lastx, lasty)); - } + // Here we plotted the old planner profile. why there's the magic with the plannerModel here? plannerModel->setRecalc(oldRecalc); - - diveBg->setPolygon(poly); - QRectF b = poly.boundingRect(); - QLinearGradient pat( - b.x(), - b.y(), - b.x(), - b.height() + b.y()); - - pat.setColorAt(1, profile_color[DEPTH_BOTTOM].first()); - pat.setColorAt(0, profile_color[DEPTH_TOP].first()); - diveBg->setBrush(pat); - plannerModel->deleteTemporaryPlan(); } - -void DivePlannerGraphics::resizeEvent(QResizeEvent *event) -{ - QGraphicsView::resizeEvent(event); - fitInView(sceneRect(), Qt::IgnoreAspectRatio); -} - -void DivePlannerGraphics::showEvent(QShowEvent *event) -{ - QGraphicsView::showEvent(event); - fitInView(sceneRect(), Qt::IgnoreAspectRatio); -} - -void DivePlannerGraphics::mouseMoveEvent(QMouseEvent *event) -{ - QPointF mappedPos = mapToScene(event->pos()); - - - double xpos = timeLine->valueAt(mappedPos); - double ypos = depthLine->valueAt(mappedPos); - - xpos = (xpos > timeLine->maximum()) ? timeLine->posAtValue(timeLine->maximum()) : (xpos < timeLine->minimum()) ? timeLine->posAtValue(timeLine->minimum()) : timeLine->posAtValue(xpos); - - ypos = (ypos > depthLine->maximum()) ? depthLine->posAtValue(depthLine->maximum()) : (ypos < depthLine->minimum()) ? depthLine->posAtValue(depthLine->minimum()) : depthLine->posAtValue(ypos); - - verticalLine->setPos(xpos, fromPercent(0, Qt::Vertical)); - horizontalLine->setPos(fromPercent(0, Qt::Horizontal), ypos); - - depthString->setPos(fromPercent(1, Qt::Horizontal), ypos); - timeString->setPos(xpos + 1, fromPercent(95, Qt::Vertical)); - - if (isPointOutOfBoundaries(mappedPos)) - return; - - depthString->setText(get_depth_string(depthLine->valueAt(mappedPos), true, false)); - timeString->setText(QString::number(rint(timeLine->valueAt(mappedPos))) + "min"); - - // calculate the correct color for the depthString. - // QGradient doesn't returns it's interpolation, meh. - double percent = depthLine->percentAt(mappedPos); - QColor &startColor = profile_color[SAMPLE_SHALLOW].first(); - QColor &endColor = profile_color[SAMPLE_DEEP].first(); - short redDelta = (endColor.red() - startColor.red()) * percent + startColor.red(); - short greenDelta = (endColor.green() - startColor.green()) * percent + startColor.green(); - short blueDelta = (endColor.blue() - startColor.blue()) * percent + startColor.blue(); - depthString->setBrush(QColor(redDelta, greenDelta, blueDelta)); - - if (activeDraggedHandler) - moveActiveHandler(mappedPos, handles.indexOf(activeDraggedHandler)); - if (!handles.count()) - return; - - if (handles.last()->x() > mappedPos.x()) { - verticalLine->setPen(QPen(QBrush(Qt::red), 0, Qt::SolidLine)); - horizontalLine->setPen(QPen(QBrush(Qt::red), 0, Qt::SolidLine)); - } else { - verticalLine->setPen(QPen(Qt::DotLine)); - horizontalLine->setPen(QPen(Qt::DotLine)); - } -} - -void DivePlannerGraphics::moveActiveHandler(const QPointF &mappedPos, const int pos) -{ - divedatapoint data = plannerModel->at(pos); - int mintime = 0, maxtime = (timeLine->maximum() + 10) * 60; - if (pos > 0) - mintime = plannerModel->at(pos - 1).time; - if (pos < plannerModel->size() - 1) - maxtime = plannerModel->at(pos + 1).time; - - int minutes = rint(timeLine->valueAt(mappedPos)); - if (minutes * 60 <= mintime || minutes * 60 >= maxtime) - return; - - int milimeters = rint(depthLine->valueAt(mappedPos) / M_OR_FT(1, 1)) * M_OR_FT(1, 1); - double xpos = timeLine->posAtValue(minutes); - double ypos = depthLine->posAtValue(milimeters); - - data.depth = milimeters; - data.time = rint(timeLine->valueAt(mappedPos)) * 60; - - plannerModel->editStop(pos, data); - - activeDraggedHandler->setPos(QPointF(xpos, ypos)); - qDeleteAll(lines); - lines.clear(); - drawProfile(); -} - -bool DivePlannerGraphics::isPointOutOfBoundaries(const QPointF &point) -{ - double xpos = timeLine->valueAt(point); - double ypos = depthLine->valueAt(point); - - if (xpos > timeLine->maximum() || - xpos < timeLine->minimum() || - ypos > depthLine->maximum() || - ypos < depthLine->minimum()) { - return true; - } - return false; -} - -void DivePlannerGraphics::mousePressEvent(QMouseEvent *event) -{ - if (event->modifiers()) { - QGraphicsView::mousePressEvent(event); - return; - } - - QPointF mappedPos = mapToScene(event->pos()); - if (event->button() == Qt::LeftButton) { - Q_FOREACH(QGraphicsItem * item, scene()->items(mappedPos, Qt::IntersectsItemBoundingRect, Qt::AscendingOrder, transform())) { - if (DiveHandler *h = qgraphicsitem_cast<DiveHandler *>(item)) { - activeDraggedHandler = h; - activeDraggedHandler->setBrush(Qt::red); - originalHandlerPos = activeDraggedHandler->pos(); - } - } - } - QGraphicsView::mousePressEvent(event); -} - -void DivePlannerGraphics::mouseReleaseEvent(QMouseEvent *event) -{ - if (activeDraggedHandler) { - /* we already deal with all the positioning in the life update, - * so all we need to do here is change the color of the handler */ - activeDraggedHandler->setBrush(QBrush(Qt::white)); - activeDraggedHandler = 0; - drawProfile(); - } -} +#endif DiveHandler::DiveHandler() : QGraphicsEllipseItem() { setRect(-5, -5, 10, 10); - setFlag(QGraphicsItem::ItemIgnoresTransformations); - setFlag(QGraphicsItem::ItemIsSelectable); + setFlags(ItemIgnoresTransformations | ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges); setBrush(Qt::white); setZValue(2); } int DiveHandler::parentIndex() { - DivePlannerGraphics *view = qobject_cast<DivePlannerGraphics *>(scene()->views().first()); + ProfileWidget2 *view = qobject_cast<ProfileWidget2 *>(scene()->views().first()); return view->handles.indexOf(this); } @@ -739,7 +183,7 @@ void DiveHandler::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) void DiveHandler::selfRemove() { setSelected(true); - DivePlannerGraphics *view = qobject_cast<DivePlannerGraphics *>(scene()->views().first()); + ProfileWidget2 *view = qobject_cast<ProfileWidget2 *>(scene()->views().first()); view->keyDeleteAction(); } @@ -750,210 +194,13 @@ void DiveHandler::changeGas() plannerModel->setData(index, action->text()); } -void DiveHandler::mousePressEvent(QGraphicsSceneMouseEvent *event) +void DiveHandler::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { - if (event->button() != Qt::LeftButton) + ProfileWidget2 *view = qobject_cast<ProfileWidget2*>(scene()->views().first()); + if(view->isPointOutOfBoundaries(event->scenePos())) return; - - if (event->modifiers().testFlag(Qt::ControlModifier)) { - setSelected(true); - } - // mousePressEvent 'grabs' the mouse and keyboard, annoying. - ungrabMouse(); - - /* hack. Sometimes the keyboard is grabbed, sometime it's not, - so, let's force a grab and release, to get rid of a warning. */ - grabKeyboard(); - ungrabKeyboard(); -} - -void Ruler::setMaximum(double maximum) -{ - max = maximum; -} - -void Ruler::setMinimum(double minimum) -{ - min = minimum; -} - -void Ruler::setTextColor(const QColor &color) -{ - textColor = color; -} - -void Ruler::eraseAll() -{ - qDeleteAll(ticks); - ticks.clear(); - qDeleteAll(labels); - labels.clear(); -} - -Ruler::Ruler() : unitSystem(0), - orientation(Qt::Horizontal), - min(0), - max(0), - interval(0), - tickSize(0) -{ -} - -Ruler::~Ruler() -{ - eraseAll(); -} - -void Ruler::setOrientation(Qt::Orientation o) -{ - orientation = o; - // position the elements on the screen. - setMinimum(minimum()); - setMaximum(maximum()); -} - -void Ruler::updateTicks() -{ - eraseAll(); - - QLineF m = line(); - QGraphicsLineItem *item = NULL; - QGraphicsSimpleTextItem *label = NULL; - - double steps = (max - min) / interval; - qreal pos; - double currValue = min; - - if (orientation == Qt::Horizontal) { - double stepSize = (m.x2() - m.x1()) / steps; - for (pos = m.x1(); pos <= m.x2(); pos += stepSize, currValue += interval) { - item = new QGraphicsLineItem(pos, m.y1(), pos, m.y1() + tickSize, this); - item->setPen(pen()); - ticks.push_back(item); - - label = new QGraphicsSimpleTextItem(QString::number(currValue), this); - label->setBrush(QBrush(textColor)); - label->setFlag(ItemIgnoresTransformations); - label->setPos(pos - label->boundingRect().width() / 2, m.y1() + tickSize + 5); - labels.push_back(label); - } - } else { - double stepSize = (m.y2() - m.y1()) / steps; - for (pos = m.y1(); pos <= m.y2(); pos += stepSize, currValue += interval) { - item = new QGraphicsLineItem(m.x1(), pos, m.x1() - tickSize, pos, this); - item->setPen(pen()); - ticks.push_back(item); - - label = new QGraphicsSimpleTextItem(get_depth_string(currValue, false, false), this); - label->setBrush(QBrush(textColor)); - label->setFlag(ItemIgnoresTransformations); - label->setPos(m.x2() - 80, pos); - labels.push_back(label); - } - } -} - -void Ruler::setTickSize(qreal size) -{ - tickSize = size; -} - -void Ruler::setTickInterval(double i) -{ - interval = i; -} - -qreal Ruler::valueAt(const QPointF &p) -{ - QLineF m = line(); - double retValue = orientation == Qt::Horizontal ? - max * (p.x() - m.x1()) / (m.x2() - m.x1()) : - max * (p.y() - m.y1()) / (m.y2() - m.y1()); - return retValue; -} - -qreal Ruler::posAtValue(qreal value) -{ - QLineF m = line(); - double size = max - min; - double percent = value / size; - double realSize = orientation == Qt::Horizontal ? - m.x2() - m.x1() : - m.y2() - m.y1(); - double retValue = realSize * percent; - retValue = (orientation == Qt::Horizontal) ? - retValue + m.x1() : - retValue + m.y1(); - return retValue; -} - -qreal Ruler::percentAt(const QPointF &p) -{ - qreal value = valueAt(p); - double size = max - min; - double percent = value / size; - return percent; -} - -double Ruler::maximum() const -{ - return max; -} - -double Ruler::minimum() const -{ - return min; -} - -void Ruler::setColor(const QColor &color) -{ - QPen defaultPen(color); - defaultPen.setJoinStyle(Qt::RoundJoin); - defaultPen.setCapStyle(Qt::RoundCap); - defaultPen.setWidth(2); - defaultPen.setCosmetic(true); - setPen(defaultPen); -} - -Button::Button(QObject *parent, QGraphicsItem *itemParent) : QObject(parent), - QGraphicsRectItem(itemParent), - icon(new QGraphicsPixmapItem(this)), - text(new QGraphicsSimpleTextItem(this)) -{ - icon->setPos(0, 0); - text->setPos(0, 0); - setFlag(ItemIgnoresTransformations); - setPen(QPen(QBrush(), 0)); -} - -void Button::setPixmap(const QPixmap &pixmap) -{ - icon->setPixmap(pixmap); - if (pixmap.isNull()) - icon->hide(); - else - icon->show(); - - setRect(childrenBoundingRect()); -} - -void Button::setText(const QString &t) -{ - text->setText(t); - if (icon->pixmap().isNull()) { - icon->hide(); - text->setPos(0, 0); - } else { - icon->show(); - text->setPos(22, 0); - } - setRect(childrenBoundingRect()); -} - -void Button::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - event->ignore(); - emit clicked(); + QGraphicsEllipseItem::mouseMoveEvent(event); + emit moved(); } DivePlannerWidget::DivePlannerWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) @@ -982,11 +229,11 @@ DivePlannerWidget::DivePlannerWidget(QWidget *parent, Qt::WindowFlags f) : QWidg connect(CylindersModel::instance(), SIGNAL(rowsRemoved(QModelIndex, int, int)), GasSelectionModel::instance(), SLOT(repopulate())); connect(CylindersModel::instance(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), - plannerModel, SLOT(emitCylinderModelEdited())); + plannerModel, SIGNAL(cylinderModelEdited())); connect(CylindersModel::instance(), SIGNAL(rowsInserted(QModelIndex, int, int)), - plannerModel, SLOT(emitCylinderModelEdited())); + plannerModel, SIGNAL(cylinderModelEdited())); connect(CylindersModel::instance(), SIGNAL(rowsRemoved(QModelIndex, int, int)), - plannerModel, SLOT(emitCylinderModelEdited())); + plannerModel, SIGNAL(cylinderModelEdited())); ui.tableWidget->setBtnToolTip(tr("add dive data point")); connect(ui.startTime, SIGNAL(timeChanged(QTime)), plannerModel, SLOT(setStartTime(QTime))); @@ -1067,11 +314,6 @@ bool DivePlannerPointsModel::recalcQ() return recalc; } -void DivePlannerPointsModel::emitCylinderModelEdited() -{ - cylinderModelEdited(); -} - int DivePlannerPointsModel::columnCount(const QModelIndex &parent) const { return COLUMNS; @@ -1264,7 +506,9 @@ bool DivePlannerPointsModel::addGas(int o2, int he) sanitize_gasmix(&cyl->gasmix); /* The depth to change to that gas is given by the depth where its pO2 is 1.6 bar. * The user should be able to change this depth manually. */ - cyl->depth.mm = 1600 * 1000 / get_o2(&mix) * 10 - 10000; + pressure_t modppO2; + modppO2.mbar = 1600; + cyl->depth = gas_mod(&cyl->gasmix, modppO2); CylindersModel::instance()->setDive(stagingDive); return true; } @@ -1388,7 +632,7 @@ void DivePlannerPointsModel::remove(const QModelIndex &index) endRemoveRows(); } -struct diveplan DivePlannerPointsModel::getDiveplan() +struct diveplan &DivePlannerPointsModel::getDiveplan() { return diveplan; } @@ -1619,46 +863,3 @@ void DivePlannerPointsModel::createPlan() CylindersModel::instance()->update(); plannerModel->setRecalc(oldRecalc); } - -ExpanderGraphics::ExpanderGraphics(QGraphicsItem *parent) : QGraphicsRectItem(parent), - icon(new QGraphicsPixmapItem(this)), - increaseBtn(new Button(0, this)), - decreaseBtn(new Button(0, this)), - bg(new QGraphicsPixmapItem(this)), - leftWing(new QGraphicsPixmapItem(this)), - rightWing(new QGraphicsPixmapItem(this)) -{ - QPixmap p; -#define CREATE(item, pixmap) \ - p = QPixmap(QString(pixmap)); \ - item->setPixmap(p); - - CREATE(icon, ":icon_time"); - CREATE(bg, ":round_base"); - CREATE(leftWing, ":left_wing"); - CREATE(rightWing, ":right_wing"); -#undef CREATE - - decreaseBtn->setPixmap(QPixmap(":arrow_down")); - increaseBtn->setPixmap(QPixmap(":arrow_up")); - - setFlag(ItemIgnoresTransformations); - leftWing->setZValue(-2); - rightWing->setZValue(-2); - bg->setZValue(-1); - - leftWing->setPos(0, 0); - bg->setPos(leftWing->pos().x() + leftWing->boundingRect().width() - 60, 5); - rightWing->setPos(leftWing->pos().x() + leftWing->boundingRect().width() - 20, 0); - decreaseBtn->setPos(leftWing->pos().x(), leftWing->pos().y()); - increaseBtn->setPos(rightWing->pos().x(), rightWing->pos().y()); - icon->setPos(bg->pos().x(), bg->pos().y() - 5); - - //I need to bottom align the items, I need to make the 0,0 ( orgin ) to be - // the bottom of this item, so shift everything up. - QRectF r = childrenBoundingRect(); - Q_FOREACH(QGraphicsItem * i, childItems()) { - i->setPos(i->pos().x(), i->pos().y() - r.height()); - } - setScale(0.7); -} diff --git a/qt-ui/diveplanner.h b/qt-ui/diveplanner.h index 506953275..4aa5f0094 100644 --- a/qt-ui/diveplanner.h +++ b/qt-ui/diveplanner.h @@ -55,7 +55,7 @@ public: void editStop(int row, divedatapoint newData); divedatapoint at(int row); int size(); - struct diveplan getDiveplan(); + struct diveplan &getDiveplan(); QStringList &getGasList(); QVector<QPair<int, int> > collectGases(dive *d); int lastEnteredPoint(); @@ -80,7 +80,6 @@ slots: void deleteTemporaryPlan(); void loadFromDive(dive *d); void restoreBackupDive(); - void emitCylinderModelEdited(); signals: void planCreated(); @@ -102,47 +101,16 @@ private: QVector<QPair<int, int> > oldGases; }; -class Button : public QObject, public QGraphicsRectItem { - Q_OBJECT -public: - Button(QObject *parent = 0, QGraphicsItem *itemParent = 0); - void setText(const QString &text); - void setPixmap(const QPixmap &pixmap); - -protected: - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); -signals: - void clicked(); - -private: - QGraphicsPixmapItem *icon; - QGraphicsSimpleTextItem *text; -}; - - -class ExpanderGraphics : public QGraphicsRectItem { -public: - ExpanderGraphics(QGraphicsItem *parent = 0); - - QGraphicsPixmapItem *icon; - Button *increaseBtn; - Button *decreaseBtn; - -private: - QGraphicsPixmapItem *bg; - QGraphicsPixmapItem *leftWing; - QGraphicsPixmapItem *rightWing; -}; - class DiveHandler : public QObject, public QGraphicsEllipseItem { Q_OBJECT public: DiveHandler(); protected: - void mousePressEvent(QGraphicsSceneMouseEvent *event); void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); - + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); +signals: + void moved(); private: int parentIndex(); public @@ -151,114 +119,6 @@ slots: void changeGas(); }; -class Ruler : public QGraphicsLineItem { -public: - Ruler(); - ~Ruler(); - void setMinimum(double minimum); - void setMaximum(double maximum); - void setTickInterval(double interval); - void setOrientation(Qt::Orientation orientation); - void setTickSize(qreal size); - void updateTicks(); - double minimum() const; - double maximum() const; - qreal valueAt(const QPointF &p); - qreal percentAt(const QPointF &p); - qreal posAtValue(qreal value); - void setColor(const QColor &color); - void setTextColor(const QColor &color); - int unitSystem; - -private: - void eraseAll(); - - Qt::Orientation orientation; - QList<QGraphicsLineItem *> ticks; - QList<QGraphicsSimpleTextItem *> labels; - double min; - double max; - double interval; - double tickSize; - QColor textColor; -}; - -class DivePlannerGraphics : public QGraphicsView { - Q_OBJECT -public: - DivePlannerGraphics(QWidget *parent = 0); - -protected: - virtual void mouseDoubleClickEvent(QMouseEvent *event); - virtual void showEvent(QShowEvent *event); - virtual void resizeEvent(QResizeEvent *event); - virtual void mouseMoveEvent(QMouseEvent *event); - virtual void mousePressEvent(QMouseEvent *event); - virtual void mouseReleaseEvent(QMouseEvent *event); - bool isPointOutOfBoundaries(const QPointF &point); - qreal fromPercent(qreal percent, Qt::Orientation orientation); -public -slots: - void settingsChanged(); -private -slots: - void keyEscAction(); - void keyDeleteAction(); - void keyUpAction(); - void keyDownAction(); - void keyLeftAction(); - void keyRightAction(); - void increaseTime(); - void increaseDepth(); - void decreaseTime(); - void decreaseDepth(); - void drawProfile(); - void pointInserted(const QModelIndex &, int start, int end); - void pointsRemoved(const QModelIndex &, int start, int end); - -private: - void moveActiveHandler(const QPointF &MappedPos, const int pos); - - /* This are the lines of the plotted dive. */ - QList<QGraphicsLineItem *> lines; - - /* This is the user-entered handles. */ - QList<DiveHandler *> handles; - QList<QGraphicsSimpleTextItem *> gases; - - /* those are the lines that follows the mouse. */ - QGraphicsLineItem *verticalLine; - QGraphicsLineItem *horizontalLine; - - /* This is the handler that's being dragged. */ - DiveHandler *activeDraggedHandler; - - // When we start to move the handler, this pos is saved. - // so we can revert it later. - QPointF originalHandlerPos; - - /* this is the background of the dive, the blue-gradient. */ - QGraphicsPolygonItem *diveBg; - - /* This is the bottom ruler - the x axis, and it's associated text */ - Ruler *timeLine; - QGraphicsSimpleTextItem *timeString; - - /* this is the left ruler, the y axis, and it's associated text. */ - Ruler *depthLine; - QGraphicsSimpleTextItem *depthString; - - /* Buttons */ - ExpanderGraphics *depthHandler; - ExpanderGraphics *timeHandler; - - int minMinutes; // this holds the minimum requested window time - int minDepth; // this holds the minimum requested window depth - int dpMaxTime; // this is the time of the dive calculated by the deco. - - friend class DiveHandler; -}; - #include "ui_diveplanner.h" class DivePlannerWidget : public QWidget { @@ -277,4 +137,7 @@ private: Ui::DivePlanner ui; }; +QString gasToStr(const int o2Permille, const int hePermille); +QString dpGasToStr(const divedatapoint &p); + #endif // DIVEPLANNER_H diff --git a/qt-ui/downloadfromdivecomputer.cpp b/qt-ui/downloadfromdivecomputer.cpp index 17c2a4eaa..71f428b14 100644 --- a/qt-ui/downloadfromdivecomputer.cpp +++ b/qt-ui/downloadfromdivecomputer.cpp @@ -34,8 +34,7 @@ struct mydescriptor { unsigned int model; }; -namespace DownloadFromDcGlobal -{ +namespace DownloadFromDcGlobal { const char *err_string; }; @@ -56,7 +55,6 @@ DownloadFromDCWidget::DownloadFromDCWidget(QWidget *parent, Qt::WindowFlags f) : progress_bar_text = ""; - fill_device_list(); fill_computer_list(); ui.chooseDumpFile->setEnabled(ui.dumpToFile->isChecked()); @@ -74,7 +72,6 @@ DownloadFromDCWidget::DownloadFromDCWidget(QWidget *parent, Qt::WindowFlags f) : if (default_dive_computer_product) ui.product->setCurrentIndex(ui.product->findText(default_dive_computer_product)); } - connect(ui.product, SIGNAL(currentIndexChanged(int)), this, SLOT(on_product_currentIndexChanged()), Qt::UniqueConnection); if (default_dive_computer_device) ui.device->setEditText(default_dive_computer_device); @@ -104,7 +101,7 @@ void DownloadFromDCWidget::updateState(states state) return; if (state == INITIAL) { - fill_device_list(); + fill_device_list(DC_TYPE_OTHER); ui.progressBar->hide(); markChildrenAsEnabled(); timer->stop(); @@ -176,6 +173,7 @@ void DownloadFromDCWidget::updateState(states state) void DownloadFromDCWidget::on_vendor_currentIndexChanged(const QString &vendor) { + int dcType = DC_TYPE_SERIAL; QAbstractItemModel *currentModel = ui.product->model(); if (!currentModel) return; @@ -183,15 +181,19 @@ void DownloadFromDCWidget::on_vendor_currentIndexChanged(const QString &vendor) productModel = new QStringListModel(productList[vendor]); ui.product->setModel(productModel); + if (vendor == QString("Uemis")) + dcType = DC_TYPE_UEMIS; + fill_device_list(dcType); + // Memleak - but deleting gives me a crash. //currentModel->deleteLater(); } -void DownloadFromDCWidget::on_product_currentIndexChanged() +void DownloadFromDCWidget::on_product_currentIndexChanged(const QString &product) { // Set up the DC descriptor dc_descriptor_t *descriptor = NULL; - descriptor = descriptorLookup[ui.vendor->currentText() + ui.product->currentText()]; + descriptor = descriptorLookup[ui.vendor->currentText() + product]; // call dc_descriptor_get_transport to see if the dc_transport_t is DC_TRANSPORT_SERIAL if (dc_descriptor_get_transport(descriptor) == DC_TRANSPORT_SERIAL) { @@ -378,10 +380,20 @@ void DownloadFromDCWidget::onDownloadThreadFinished() // down in the dive_table for (int i = dive_table.nr - 1; i >= previousLast; i--) delete_single_dive(i); - } else { + } else if (dive_table.nr) { + int uniqId, idx; + // remember the last downloaded dive (on most dive computers this will be the chronologically + // first new dive) and select it again after processing all the dives + MainWindow::instance()->dive_list()->unselectDives(); + uniqId = get_dive(dive_table.nr - 1)->id; process_dives(true, preferDownloaded()); + // after process_dives does any merging or resorting needed, we need + // to recreate the model for the dive list so we can select the newest dive + MainWindow::instance()->recreateDiveList(); + idx = get_idx_by_uniq_id(uniqId); + MainWindow::instance()->dive_list()->selectDive(idx, true); } - } else if (currentState == CANCELLING || currentState == CANCELLED){ + } else if (currentState == CANCELLING || currentState == CANCELLED) { if (import_thread_cancelled) { // walk backwards so we don't keep moving the dives // down in the dive_table @@ -429,11 +441,11 @@ static void fillDeviceList(const char *name, void *data) comboBox->addItem(name); } -void DownloadFromDCWidget::fill_device_list() +void DownloadFromDCWidget::fill_device_list(int dc_type) { int deviceIndex; ui.device->clear(); - deviceIndex = enumerate_devices(fillDeviceList, ui.device); + deviceIndex = enumerate_devices(fillDeviceList, ui.device, dc_type); if (deviceIndex >= 0) ui.device->setCurrentIndex(deviceIndex); } diff --git a/qt-ui/downloadfromdivecomputer.h b/qt-ui/downloadfromdivecomputer.h index e20ba3051..3de102bfd 100644 --- a/qt-ui/downloadfromdivecomputer.h +++ b/qt-ui/downloadfromdivecomputer.h @@ -42,7 +42,7 @@ slots: void on_cancel_clicked(); void on_search_clicked(); void on_vendor_currentIndexChanged(const QString &vendor); - void on_product_currentIndexChanged(); + void on_product_currentIndexChanged(const QString &product); void onDownloadThreadFinished(); void updateProgressBar(); @@ -68,7 +68,7 @@ private: QStringListModel *vendorModel; QStringListModel *productModel; void fill_computer_list(); - void fill_device_list(); + void fill_device_list(int dc_type); QString logFile; QString dumpFile; QTimer *timer; diff --git a/qt-ui/exif.cpp b/qt-ui/exif.cpp index 82601577f..1aee47acb 100644 --- a/qt-ui/exif.cpp +++ b/qt-ui/exif.cpp @@ -34,8 +34,7 @@ using std::string; -namespace -{ +namespace { // IF Entry struct IFEntry { // Raw fields @@ -459,15 +458,15 @@ int EXIFInfo::parseFromEXIFSegment(const unsigned char *buf, unsigned len) // GPS latitude if (format == 5 && length == 3) { this->GeoLocation.LatComponents.degrees = - parseEXIFRational(buf + data + tiff_header_start, alignIntel); + parseEXIFRational(buf + data + tiff_header_start, alignIntel); this->GeoLocation.LatComponents.minutes = - parseEXIFRational(buf + data + tiff_header_start + 8, alignIntel); + parseEXIFRational(buf + data + tiff_header_start + 8, alignIntel); this->GeoLocation.LatComponents.seconds = - parseEXIFRational(buf + data + tiff_header_start + 16, alignIntel); + parseEXIFRational(buf + data + tiff_header_start + 16, alignIntel); this->GeoLocation.Latitude = - this->GeoLocation.LatComponents.degrees + - this->GeoLocation.LatComponents.minutes / 60 + - this->GeoLocation.LatComponents.seconds / 3600; + this->GeoLocation.LatComponents.degrees + + this->GeoLocation.LatComponents.minutes / 60 + + this->GeoLocation.LatComponents.seconds / 3600; if ('S' == this->GeoLocation.LatComponents.direction) this->GeoLocation.Latitude = -this->GeoLocation.Latitude; } @@ -484,15 +483,15 @@ int EXIFInfo::parseFromEXIFSegment(const unsigned char *buf, unsigned len) // GPS longitude if (format == 5 && length == 3) { this->GeoLocation.LonComponents.degrees = - parseEXIFRational(buf + data + tiff_header_start, alignIntel); + parseEXIFRational(buf + data + tiff_header_start, alignIntel); this->GeoLocation.LonComponents.minutes = - parseEXIFRational(buf + data + tiff_header_start + 8, alignIntel); + parseEXIFRational(buf + data + tiff_header_start + 8, alignIntel); this->GeoLocation.LonComponents.seconds = - parseEXIFRational(buf + data + tiff_header_start + 16, alignIntel); + parseEXIFRational(buf + data + tiff_header_start + 16, alignIntel); this->GeoLocation.Longitude = - this->GeoLocation.LonComponents.degrees + - this->GeoLocation.LonComponents.minutes / 60 + - this->GeoLocation.LonComponents.seconds / 3600; + this->GeoLocation.LonComponents.degrees + + this->GeoLocation.LonComponents.minutes / 60 + + this->GeoLocation.LonComponents.seconds / 3600; if ('W' == this->GeoLocation.LonComponents.direction) this->GeoLocation.Longitude = -this->GeoLocation.Longitude; } @@ -509,7 +508,7 @@ int EXIFInfo::parseFromEXIFSegment(const unsigned char *buf, unsigned len) // GPS altitude reference if (format == 5) { this->GeoLocation.Altitude = - parseEXIFRational(buf + data + tiff_header_start, alignIntel); + parseEXIFRational(buf + data + tiff_header_start, alignIntel); if (1 == this->GeoLocation.AltitudeRef) this->GeoLocation.Altitude = -this->GeoLocation.Altitude; } diff --git a/qt-ui/globe.cpp b/qt-ui/globe.cpp index 1101500d3..8d234194e 100644 --- a/qt-ui/globe.cpp +++ b/qt-ui/globe.cpp @@ -64,7 +64,7 @@ GlobeGPS::GlobeGPS(QWidget *parent) : MarbleWidget(parent), setProjection(Marble::Spherical); setAnimationsEnabled(true); - Q_FOREACH(AbstractFloatItem * i, floatItems()) { + Q_FOREACH (AbstractFloatItem *i, floatItems()) { i->setVisible(false); } @@ -142,7 +142,7 @@ void GlobeGPS::mouseClicked(qreal lon, qreal lat, GeoDataCoordinates::Unit unit) struct dive *dive; bool clear = !(QApplication::keyboardModifiers() & Qt::ControlModifier); QList<int> selectedDiveIds; - for_each_dive(idx, dive) { + for_each_dive (idx, dive) { long lat_diff, lon_diff; if (!dive_has_gps_location(dive)) continue; @@ -175,7 +175,7 @@ void GlobeGPS::repopulateLabels() int idx = 0; struct dive *dive; - for_each_dive(idx, dive) { + for_each_dive (idx, dive) { if (dive_has_gps_location(dive)) { GeoDataPlacemark *place = new GeoDataPlacemark(dive->location); place->setCoordinate(dive->longitude.udeg / 1000000.0, dive->latitude.udeg / 1000000.0, 0, GeoDataCoordinates::Degree); @@ -211,8 +211,7 @@ void GlobeGPS::centerOnCurrentDive() { struct dive *dive = current_dive; // dive has changed, if we had the 'editingDive', hide it. - if (messageWidget->isVisible() - && (!dive || dive_has_gps_location(dive) || amount_selected != 1 )) + if (messageWidget->isVisible() && (!dive || dive_has_gps_location(dive) || amount_selected != 1)) messageWidget->hide(); editingDiveLocation = false; @@ -222,8 +221,7 @@ void GlobeGPS::centerOnCurrentDive() qreal longitude = dive->longitude.udeg / 1000000.0; qreal latitude = dive->latitude.udeg / 1000000.0; - if ((!dive_has_gps_location(dive) || MainWindow::instance()->information()->isEditing()) - && amount_selected == 1) { + if ((!dive_has_gps_location(dive) || MainWindow::instance()->information()->isEditing()) && amount_selected == 1) { prepareForGetDiveCoordinates(); return; } @@ -261,7 +259,7 @@ void GlobeGPS::zoomOutForNoGPS() // this is called if the dive has no GPS location. // zoom out quite a bit to show the globe and remember that the next time // we show a dive with GPS location we need to zoom in again - if(fixZoomTimer->isActive()) + if (fixZoomTimer->isActive()) fixZoomTimer->stop(); setZoom(1200, Marble::Automatic); if (!needResetZoom) { @@ -300,7 +298,7 @@ void GlobeGPS::changeDiveGeoPosition(qreal lon, qreal lat, GeoDataCoordinates::U // but we keep the code here that changes the coordinates for each selected dive int i; struct dive *dive; - for_each_dive(i, dive) { + for_each_dive (i, dive) { if (!dive->selected) continue; dive->latitude.udeg = lrint(lat * 1000000.0); @@ -341,10 +339,23 @@ void GlobeGPS::resizeEvent(QResizeEvent *event) } #else -GlobeGPS::GlobeGPS(QWidget* parent) { setText("MARBLE DISABLED AT BUILD TIME"); } -void GlobeGPS::repopulateLabels() {} -void GlobeGPS::centerOn(dive* dive) {} -bool GlobeGPS::eventFilter(QObject *obj, QEvent *ev) {} -void GlobeGPS::prepareForGetDiveCoordinates(struct dive *dive) {} -void GlobeGPS::reload() {} +GlobeGPS::GlobeGPS(QWidget *parent) +{ + setText("MARBLE DISABLED AT BUILD TIME"); +} +void GlobeGPS::repopulateLabels() +{ +} +void GlobeGPS::centerOnCurrentDive() +{ +} +bool GlobeGPS::eventFilter(QObject *obj, QEvent *ev) +{ +} +void GlobeGPS::prepareForGetDiveCoordinates() +{ +} +void GlobeGPS::reload() +{ +} #endif diff --git a/qt-ui/globe.h b/qt-ui/globe.h index add04ede4..c40eefc46 100644 --- a/qt-ui/globe.h +++ b/qt-ui/globe.h @@ -54,10 +54,11 @@ public: GlobeGPS(QWidget *parent); void reload(); void repopulateLabels(); - void centerOn(struct dive* dive); - bool eventFilter(QObject*, QEvent*); -public slots: - void prepareForGetDiveCoordinates(struct dive *dive); + void centerOnCurrentDive(); + bool eventFilter(QObject *, QEvent *); +public +slots: + void prepareForGetDiveCoordinates(); }; #endif // NO_MARBLE diff --git a/qt-ui/groupedlineedit.cpp b/qt-ui/groupedlineedit.cpp index 517623119..4ba6621e6 100644 --- a/qt-ui/groupedlineedit.cpp +++ b/qt-ui/groupedlineedit.cpp @@ -108,7 +108,7 @@ QStringList GroupedLineEdit::getBlockStringList() { QStringList retList; Private::Block block; - foreach(block, d->blocks) + foreach (block, d->blocks) retList.append(block.text); return retList; } @@ -149,10 +149,10 @@ void GroupedLineEdit::removeAllBlocks() QSize GroupedLineEdit::sizeHint() const { QSize rs( - 40, - document()->findBlock(0).layout()->lineAt(0).height() + - document()->documentMargin() * 2 + - frameWidth() * 2); + 40, + document()->findBlock(0).layout()->lineAt(0).height() + + document()->documentMargin() * 2 + + frameWidth() * 2); return rs; } @@ -189,15 +189,15 @@ void GroupedLineEdit::paintEvent(QPaintEvent *e) QVectorIterator<QColor> i(d->colors); i.toFront(); - foreach(const Private::Block & block, d->blocks) { + foreach (const Private::Block &block, d->blocks) { qreal start_x = line.cursorToX(block.start, QTextLine::Trailing); qreal end_x = line.cursorToX(block.end + 1, QTextLine::Leading); QPainterPath path; QRectF rectangle( - start_x - 1.0 - double(horizontalScrollBar()->value()), - 1.0, - end_x - start_x + 2.0, - double(viewport()->height() - 2)); + start_x - 1.0 - double(horizontalScrollBar()->value()), + 1.0, + end_x - start_x + 2.0, + double(viewport()->height() - 2)); if (!i.hasNext()) i.toFront(); path.addRoundedRect(rectangle, 5.0, 5.0); diff --git a/qt-ui/kmessagewidget.cpp b/qt-ui/kmessagewidget.cpp index c21dea867..2f9ac6870 100644 --- a/qt-ui/kmessagewidget.cpp +++ b/qt-ui/kmessagewidget.cpp @@ -74,7 +74,7 @@ void KMessageWidgetPrivate::createLayout() qDeleteAll(buttons); buttons.clear(); - Q_FOREACH(QAction * action, q->actions()) { + Q_FOREACH (QAction *action, q->actions()) { QToolButton *button = new QToolButton(content); button->setDefaultAction(action); button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); @@ -94,7 +94,7 @@ void KMessageWidgetPrivate::createLayout() QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addStretch(); - Q_FOREACH(QToolButton * button, buttons) { + Q_FOREACH (QToolButton *button, buttons) { // For some reason, calling show() is necessary if wordwrap is true, // otherwise the buttons do not show up. It is not needed if // wordwrap is false. @@ -108,7 +108,7 @@ void KMessageWidgetPrivate::createLayout() layout->addWidget(iconLabel); layout->addWidget(textLabel); - Q_FOREACH(QToolButton * button, buttons) { + Q_FOREACH (QToolButton *button, buttons) { layout->addWidget(button); } @@ -238,7 +238,7 @@ void KMessageWidget::setMessageType(KMessageWidget::MessageType type) bg2 = bg1.darker(110); border = bg2.darker(110); d->content->setStyleSheet( - QString(".QFrame {" + QString(".QFrame {" "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1," " stop: 0 %1," " stop: 0.1 %2," @@ -248,16 +248,16 @@ void KMessageWidget::setMessageType(KMessageWidget::MessageType type) "margin: %5px;" "}" ".QLabel { color: %6; }").arg(bg0.name()) - .arg(bg1.name()) - .arg(bg2.name()) - .arg(border.name()) - /* + .arg(bg1.name()) + .arg(bg2.name()) + .arg(border.name()) + /* DefaultFrameWidth returns the size of the external margin + border width. We know our border is 1px, so we subtract this from the frame normal QStyle FrameWidth to get our margin */ - .arg(style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this) - 1) - .arg(fg.name())); + .arg(style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this) - 1) + .arg(fg.name())); } QSize KMessageWidget::sizeHint() const diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp index 172e4e2d7..2bb261448 100644 --- a/qt-ui/maintab.cpp +++ b/qt-ui/maintab.cpp @@ -70,7 +70,7 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), ui.tagWidget->installEventFilter(this); QList<QObject *> statisticsTabWidgets = ui.statisticsTab->children(); - Q_FOREACH(QObject * obj, statisticsTabWidgets) { + Q_FOREACH (QObject *obj, statisticsTabWidgets) { QLabel *label = qobject_cast<QLabel *>(obj); if (label) label->setAlignment(Qt::AlignHCenter); @@ -136,7 +136,7 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), " background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1," " stop: 0 #E0E0E0, stop: 1 #FFFFFF);" "}"); - Q_FOREACH(QGroupBox * box, findChildren<QGroupBox *>()) { + Q_FOREACH (QGroupBox *box, findChildren<QGroupBox *>()) { box->setStyleSheet(gnomeCss); } } @@ -270,10 +270,8 @@ void MainTab::enableEdition(EditMode newEditMode) // We may be editing one or more dives here. backup everything. struct dive *mydive; - for (int i = 0; i < dive_table.nr; i++) { - mydive = get_dive(i); - if (!mydive) - continue; + int i; + for_each_dive (i, mydive) { if (!mydive->selected) continue; @@ -335,6 +333,11 @@ void MainTab::clearEquipment() weightModel->clear(); } +void MainTab::nextInputField(QKeyEvent *event) +{ + keyPressEvent(event); +} + void MainTab::clearInfo() { ui.sacText->clear(); @@ -591,14 +594,12 @@ void MainTab::reload() #define EDIT_SELECTED_DIVES(WHAT) \ do { \ struct dive *mydive = NULL; \ + int _i; \ if (editMode == NONE) \ return; \ \ - for (int _i = 0; _i < dive_table.nr; _i++) { \ - mydive = get_dive(_i); \ - if (!mydive || mydive == current_dive)\ - continue; \ - if (!mydive->selected) \ + for_each_dive (_i, mydive) { \ + if (!mydive->selected || mydive == current_dive) \ continue; \ \ WHAT; \ @@ -666,7 +667,7 @@ void MainTab::acceptChanges() ui.coordinates->text().trimmed().isEmpty())) { struct dive *dive; int i = 0; - for_each_dive(i, dive) { + for_each_dive (i, dive) { QString location(dive->location); if (location == ui.location->text() && (dive->latitude.udeg || dive->longitude.udeg)) { @@ -690,7 +691,7 @@ void MainTab::acceptChanges() DivePlannerPointsModel::instance()->copyCylinders(curr); } else if (editMode != ADD && cylindersModel->changed) { mark_divelist_changed(true); - Q_FOREACH(dive * d, notesBackup.keys()) { + Q_FOREACH (dive *d, notesBackup.keys()) { for (int i = 0; i < MAX_CYLINDERS; i++) { if (notesBackup.keys().count() > 1) // only copy the cylinder type, none of the other values @@ -704,7 +705,7 @@ void MainTab::acceptChanges() if (weightModel->changed) { mark_divelist_changed(true); - Q_FOREACH(dive * d, notesBackup.keys()) { + Q_FOREACH (dive *d, notesBackup.keys()) { for (int i = 0; i < MAX_WEIGHTSYSTEMS; i++) { d->weightsystem[i] = multiEditEquipmentPlaceholder.weightsystem[i]; } @@ -729,7 +730,7 @@ void MainTab::acceptChanges() } // each dive that was selected might have had the temperatures in its active divecomputer changed // so re-populate the temperatures - easiest way to do this is by calling fixup_dive - Q_FOREACH(dive * d, notesBackup.keys()) { + Q_FOREACH (dive *d, notesBackup.keys()) { if (d) fixup_dive(d); } @@ -746,7 +747,7 @@ void MainTab::acceptChanges() // and then clear that flag out on the other side of the sort_table() d->selected = true; sort_table(&dive_table); - for_each_dive(rememberSelected, d) { + for_each_dive (rememberSelected, d) { if (d->selected) { d->selected = false; break; @@ -760,6 +761,7 @@ void MainTab::acceptChanges() editMode = NONE; MainWindow::instance()->refreshDisplay(); MainWindow::instance()->graphics()->replot(); + emit addDiveFinished(); } else { editMode = NONE; MainWindow::instance()->dive_list()->rememberSelection(); @@ -831,10 +833,8 @@ void MainTab::rejectChanges() } struct dive *mydive; - for (int i = 0; i < dive_table.nr; i++) { - mydive = get_dive(i); - if (!mydive) - continue; + int i; + for_each_dive (i, mydive) { if (!mydive->selected) continue; @@ -862,6 +862,7 @@ void MainTab::rejectChanges() delete_single_dive(selected_dive); MainWindow::instance()->dive_list()->reload(DiveTripModel::CURRENT); MainWindow::instance()->dive_list()->restoreSelection(); + emit addDiveFinished(); } if (selected_dive >= 0) { multiEditEquipmentPlaceholder = *get_dive(selected_dive); @@ -938,7 +939,7 @@ void MainTab::on_watertemp_textChanged(const QString &text) validate_temp_field(ui.watertemp, text); } -void MainTab::validate_temp_field(QLineEdit *tempField,const QString &text) +void MainTab::validate_temp_field(QLineEdit *tempField, const QString &text) { static bool missing_unit = false; static bool missing_precision = false; @@ -980,11 +981,11 @@ void MainTab::on_dateTimeEdit_dateTimeChanged(const QDateTime &datetime) void MainTab::saveTags() { EDIT_SELECTED_DIVES( - QString tag; - taglist_free(mydive->tag_list); - mydive->tag_list = NULL; - foreach(tag, ui.tagWidget->getBlockStringList()) - taglist_add_tag(&mydive->tag_list, tag.toUtf8().data());); + QString tag; + taglist_free(mydive->tag_list); + mydive->tag_list = NULL; + foreach (tag, ui.tagWidget->getBlockStringList()) + taglist_add_tag(&mydive->tag_list, tag.toUtf8().data());); } void MainTab::on_tagWidget_textChanged() diff --git a/qt-ui/maintab.h b/qt-ui/maintab.h index d201d2a47..90d3c49ef 100644 --- a/qt-ui/maintab.h +++ b/qt-ui/maintab.h @@ -66,6 +66,10 @@ public: void initialUiSetup(); bool isEditing(); void updateCoordinatesText(qreal lat, qreal lon); + void nextInputField(QKeyEvent *event); +signals: + void addDiveFinished(); + public slots: void addCylinder_clicked(); @@ -81,7 +85,7 @@ slots: void on_notes_textChanged(); void on_airtemp_textChanged(const QString &text); void on_watertemp_textChanged(const QString &text); - void validate_temp_field(QLineEdit *tempField,const QString &text); + void validate_temp_field(QLineEdit *tempField, const QString &text); void on_dateTimeEdit_dateTimeChanged(const QDateTime &datetime); void on_rating_valueChanged(int value); void on_visibility_valueChanged(int value); diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp index 709693c30..19a16a886 100644 --- a/qt-ui/mainwindow.cpp +++ b/qt-ui/mainwindow.cpp @@ -43,6 +43,7 @@ #include "printdialog.h" #endif #include "divelogimportdialog.h" +#include "divelogexportdialog.h" #ifndef NO_USERMANUAL #include "usermanual.h" #endif @@ -67,13 +68,13 @@ MainWindow::MainWindow() : QMainWindow(), connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), ui.ListWidget, SLOT(update())); connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), ui.ListWidget, SLOT(reloadHeaderActions())); connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), ui.InfoWidget, SLOT(updateDiveInfo())); - connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), ui.divePlanner, SLOT(settingsChanged())); connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), ui.divePlannerWidget, SLOT(settingsChanged())); connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), TankInfoModel::instance(), SLOT(update())); connect(ui.actionRecent1, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool))); connect(ui.actionRecent2, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool))); connect(ui.actionRecent3, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool))); connect(ui.actionRecent4, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool))); + connect(information(), SIGNAL(addDiveFinished()), ui.newProfile, SLOT(setProfileState())); ui.mainErrorMessage->hide(); initialUiSetup(); @@ -84,10 +85,8 @@ MainWindow::MainWindow() : QMainWindow(), ui.globe->reload(); ui.ListWidget->expand(ui.ListWidget->model()->index(0, 0)); ui.ListWidget->scrollTo(ui.ListWidget->model()->index(0, 0), QAbstractItemView::PositionAtCenter); - ui.divePlanner->settingsChanged(); ui.divePlannerWidget->settingsChanged(); - #ifndef ENABLE_PLANNER ui.menuLog->removeAction(ui.actionDivePlanner); #endif @@ -124,14 +123,14 @@ MainWindow *MainWindow::instance() } // this gets called after we download dives from a divecomputer -void MainWindow::refreshDisplay(bool recreateDiveList) +void MainWindow::refreshDisplay(bool doRecreateDiveList) { showError(get_error_string()); ui.InfoWidget->reload(); TankInfoModel::instance()->update(); ui.globe->reload(); - if (recreateDiveList) - ui.ListWidget->reload(DiveTripModel::CURRENT); + if (doRecreateDiveList) + recreateDiveList(); ui.ListWidget->setFocus(); WSInfoModel::instance()->updateInfo(); // refresh the yearly stats if the window has an instance @@ -143,6 +142,11 @@ void MainWindow::refreshDisplay(bool recreateDiveList) } } +void MainWindow::recreateDiveList() +{ + ui.ListWidget->reload(DiveTripModel::CURRENT); +} + void MainWindow::current_dive_changed(int divenr) { if (divenr >= 0) { @@ -189,7 +193,7 @@ void MainWindow::on_actionSaveAs_triggered() file_save_as(); } -ProfileWidget2* MainWindow::graphics() const +ProfileWidget2 *MainWindow::graphics() const { return ui.newProfile; } @@ -273,34 +277,6 @@ void MainWindow::updateLastUsedDir(const QString &dir) s.setValue("LastDir", dir); } -void MainWindow::on_actionExportUDDF_triggered() -{ - QFileInfo fi(system_default_filename()); - QString filename = QFileDialog::getSaveFileName(this, tr("Export UDDF File as"), fi.absolutePath(), - tr("UDDF files (*.uddf *.UDDF)")); - if (!filename.isNull() && !filename.isEmpty()) - export_dives_xslt(filename.toUtf8(), false, "uddf-export.xslt"); -} - -void MainWindow::on_actionExport_CSV_triggered() -{ - QFileInfo fi(system_default_filename()); - QString filename = QFileDialog::getSaveFileName(this, tr("Export CSV File as"), fi.absolutePath(), - tr("CSV files (*.csv *.CSV)")); - - if (!filename.isNull() && !filename.isEmpty()) - export_dives_xslt(filename.toUtf8(), false, "xml2csv.xslt"); -} - -void MainWindow::on_actionExportHTMLworldmap_triggered() -{ - QFileInfo fi(system_default_filename()); - QString filename = QFileDialog::getSaveFileName(this, tr("Export World Map"), fi.absolutePath(), - tr("HTML files (*.html)")); - if (!filename.isNull() && !filename.isEmpty()) - export_worldmap_HTML(filename.toUtf8().data()); -} - void MainWindow::on_actionPrint_triggered() { #ifndef NO_PRINTING @@ -335,21 +311,23 @@ void MainWindow::on_actionDivePlanner_triggered() DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN); DivePlannerPointsModel::instance()->clear(); CylindersModel::instance()->clear(); - for_each_dive(i,dive) { - if(dive->selected){ + for_each_dive (i, dive) { + if (dive->selected) { DivePlannerPointsModel::instance()->copyCylindersFrom(dive); CylindersModel::instance()->copyFromDive(dive); break; } } - ui.stackedWidget->setCurrentIndex(PLANNERPROFILE); ui.infoPane->setCurrentIndex(PLANNERWIDGET); } void MainWindow::showProfile() { enableDcShortcuts(); - ui.stackedWidget->setCurrentIndex(PROFILE); + //TODO: I BROKE THIS BY COMMENTING THE LINE BELOW + // and I'm sleepy now, so I think I should not try to fix right away. + // we don't setCurrentIndex anymore, we ->setPlanState() or ->setAddState() on the ProfileView. + //ui.stackedWidget->setCurrentIndex(PROFILE); ui.infoPane->setCurrentIndex(MAINTAB); } @@ -430,8 +408,9 @@ void MainWindow::on_actionAddDive_triggered() ui.InfoWidget->setCurrentIndex(0); ui.InfoWidget->updateDiveInfo(selected_dive); ui.InfoWidget->addDiveStarted(); - ui.stackedWidget->setCurrentIndex(PLANNERPROFILE); // Planner. ui.infoPane->setCurrentIndex(MAINTAB); + + ui.newProfile->setAddState(); DivePlannerPointsModel::instance()->clear(); DivePlannerPointsModel::instance()->createSimpleDive(); ui.ListWidget->reload(DiveTripModel::CURRENT); @@ -439,6 +418,7 @@ void MainWindow::on_actionAddDive_triggered() void MainWindow::on_actionRenumber_triggered() { + RenumberDialog::instance()->renumberOnlySelected(false); RenumberDialog::instance()->show(); } @@ -462,11 +442,11 @@ void MainWindow::on_actionYearlyStatistics_triggered() yearlyStats->setMinimumWidth(600); yearlyStats->setWindowTitle(tr("Yearly Statistics")); yearlyStats->setWindowIcon(QIcon(":subsurface-icon")); - QShortcut* closeKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), yearlyStats); + QShortcut *closeKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), yearlyStats); connect(closeKey, SIGNAL(activated()), yearlyStats, SLOT(close())); closeKey = new QShortcut(QKeySequence(Qt::Key_Escape), yearlyStats); connect(closeKey, SIGNAL(activated()), yearlyStats, SLOT(close())); - QShortcut* quitKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), yearlyStats); + QShortcut *quitKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), yearlyStats); connect(quitKey, SIGNAL(activated()), this, SLOT(close())); } /* problem here is that without more MainWindow variables or a separate YearlyStatistics @@ -873,7 +853,7 @@ void MainWindow::addRecentFile(const QStringList &newFiles) } } - foreach(const QString & file, newFiles) { + foreach (const QString &file, newFiles) { int index = files.indexOf(file); if (index >= 0) { @@ -881,7 +861,7 @@ void MainWindow::addRecentFile(const QStringList &newFiles) } } - foreach(const QString & file, newFiles) { + foreach (const QString &file, newFiles) { if (QFile::exists(file)) { files.prepend(file); } @@ -929,7 +909,7 @@ void MainWindow::removeRecentFile(QStringList failedFiles) } } - foreach(QString file, failedFiles) + foreach (QString file, failedFiles) files.removeAll(file); for (int c = 1; c <= 4; c++) { @@ -965,12 +945,7 @@ void MainWindow::recentFileTriggered(bool checked) int MainWindow::file_save_as(void) { QString filename; - const char *default_filename; - - if (existing_filename) - default_filename = existing_filename; - else - default_filename = prefs.default_filename; + const char *default_filename = existing_filename; filename = QFileDialog::getSaveFileName(this, tr("Save File as"), default_filename, tr("Subsurface XML files (*.ssrf *.xml *.XML)")); if (filename.isNull() || filename.isEmpty()) @@ -1128,14 +1103,20 @@ void MainWindow::editCurrentDive() if (defaultDC == "manually added dive") { disableDcShortcuts(); DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD); - ui.stackedWidget->setCurrentIndex(PLANNERPROFILE); // Planner. + //TODO: I BROKE THIS BY COMMENTING THE LINE BELOW + // and I'm sleepy now, so I think I should not try to fix right away. + // we don't setCurrentIndex anymore, we ->setPlanState() or ->setAddState() on the ProfileView. + //ui.stackedWidget->setCurrentIndex(PLANNERPROFILE); // Planner. ui.infoPane->setCurrentIndex(MAINTAB); DivePlannerPointsModel::instance()->loadFromDive(d); ui.InfoWidget->enableEdition(MainTab::MANUALLY_ADDED_DIVE); } else if (defaultDC == "planned dive") { disableDcShortcuts(); DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN); - ui.stackedWidget->setCurrentIndex(PLANNERPROFILE); // Planner. + //TODO: I BROKE THIS BY COMMENTING THE LINE BELOW + // and I'm sleepy now, so I think I should not try to fix right away. + // we don't setCurrentIndex anymore, we ->setPlanState() or ->setAddState() on the ProfileView. + //ui.stackedWidget->setCurrentIndex(PLANNERPROFILE); // Planner. ui.infoPane->setCurrentIndex(PLANNERWIDGET); DivePlannerPointsModel::instance()->loadFromDive(d); ui.InfoWidget->enableEdition(MainTab::MANUALLY_ADDED_DIVE); @@ -1221,3 +1202,9 @@ void MainWindow::on_profScaled_clicked(bool triggered) } #undef TOOLBOX_PREF_PROFILE + +void MainWindow::on_actionExport_triggered() +{ + DiveLogExportDialog *diveLogExport = new DiveLogExportDialog(this); + diveLogExport->show(); +} diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h index 60081e957..a658fe3cc 100644 --- a/qt-ui/mainwindow.h +++ b/qt-ui/mainwindow.h @@ -42,10 +42,6 @@ public: COLLAPSED, EXPANDED }; - enum StackWidgetIndexes { - PROFILE, - PLANNERPROFILE - }; enum InfoWidgetIndexes { MAINTAB, PLANNERWIDGET @@ -90,9 +86,6 @@ slots: void on_actionSave_triggered(); void on_actionSaveAs_triggered(); void on_actionClose_triggered(); - void on_actionExportUDDF_triggered(); - void on_actionExport_CSV_triggered(); - void on_actionExportHTMLworldmap_triggered(); void on_actionPrint_triggered(); void on_actionPreferences_triggered(); void on_actionQuit_triggered(); @@ -146,13 +139,16 @@ slots: void on_profSAC_clicked(bool triggered); void on_profScaled_clicked(bool triggered); + void on_actionExport_triggered(); + protected: void closeEvent(QCloseEvent *); public slots: void readSettings(); - void refreshDisplay(bool recreateDiveList = true); + void refreshDisplay(bool doRecreateDiveList = true); + void recreateDiveList(); void showProfile(); void editCurrentDive(); @@ -178,6 +174,4 @@ private: UpdateManager *updateManager; }; -MainWindow *mainWindow(); - #endif // MAINWINDOW_H diff --git a/qt-ui/mainwindow.ui b/qt-ui/mainwindow.ui index 072d321fc..1fd0fa775 100644 --- a/qt-ui/mainwindow.ui +++ b/qt-ui/mainwindow.ui @@ -85,12 +85,8 @@ </layout> </widget> </widget> - <widget class="QStackedWidget" name="stackedWidget"> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="page_5"> - <layout class="QGridLayout" name="gridLayout"> + <widget class="QWidget" name="ProfileWidget"> + <layout class="QGridLayout" name="gridLayout"> <property name="leftMargin"> <number>0</number> </property> @@ -493,29 +489,6 @@ </spacer> </item> </layout> - </widget> - <widget class="QWidget" name="page_6"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="DivePlannerGraphics" name="divePlanner"/> - </item> - </layout> - </widget> </widget> </widget> <widget class="QSplitter" name="listGlobeSplitter"> @@ -563,7 +536,7 @@ <x>0</x> <y>0</y> <width>1418</width> - <height>25</height> + <height>20</height> </rect> </property> <widget class="QMenu" name="menuFile"> @@ -576,9 +549,7 @@ <addaction name="actionSaveAs"/> <addaction name="separator"/> <addaction name="actionClose"/> - <addaction name="actionExportUDDF"/> - <addaction name="actionExport_CSV"/> - <addaction name="actionExportHTMLworldmap"/> + <addaction name="actionExport"/> <addaction name="actionPrint"/> <addaction name="actionPreferences"/> <addaction name="separator"/> @@ -702,22 +673,6 @@ <string>Ctrl+W</string> </property> </action> - <action name="actionExportUDDF"> - <property name="text"> - <string>Export &UDDF</string> - </property> - <property name="shortcut"> - <string>Ctrl+U</string> - </property> - </action> - <action name="actionExportHTMLworldmap"> - <property name="text"> - <string>Export HTML World Map</string> - </property> - <property name="shortcut"> - <string>Ctrl+H</string> - </property> - </action> <action name="actionPrint"> <property name="text"> <string>&Print</string> @@ -946,9 +901,15 @@ <string>&Check for Updates</string> </property> </action> - <action name="actionExport_CSV"> + <action name="actionExport"> <property name="text"> - <string>Export CSV</string> + <string>Export</string> + </property> + <property name="toolTip"> + <string>Export Dive Logs</string> + </property> + <property name="shortcut"> + <string>Ctrl+E</string> </property> </action> </widget> diff --git a/qt-ui/modeldelegates.cpp b/qt-ui/modeldelegates.cpp index 9073ac158..d06c6621f 100644 --- a/qt-ui/modeldelegates.cpp +++ b/qt-ui/modeldelegates.cpp @@ -171,7 +171,7 @@ bool ComboBoxDelegate::eventFilter(QObject *object, QEvent *event) QKeyEvent *ev = static_cast<QKeyEvent *>(event); if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) { currCombo.ignoreSelection = true; - if (!currCombo.comboEditor->completer()->popup()->isVisible()){ + if (!currCombo.comboEditor->completer()->popup()->isVisible()) { currCombo.comboEditor->showPopup(); return true; } diff --git a/qt-ui/models.cpp b/qt-ui/models.cpp index 68603e735..2bc690eb9 100644 --- a/qt-ui/models.cpp +++ b/qt-ui/models.cpp @@ -68,7 +68,7 @@ CylindersModel::CylindersModel(QObject *parent) : current(0), rows(0) // enum {REMOVE, TYPE, SIZE, WORKINGPRESS, START, END, O2, HE, DEPTH}; setHeaderDataStrings(QStringList() << "" << tr("Type") << tr("Size") << tr("WorkPress") << tr("StartPress") << tr("EndPress") << trUtf8("O" UTF8_SUBSCRIPT_2 "%") << tr("He%") #ifdef ENABLE_PLANNER - << tr("Switch at") + << tr("Switch at") #endif ); } @@ -253,11 +253,9 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in case O2: if (CHANGED()) { cyl->gasmix.o2 = string_to_fraction(vString.toUtf8().data()); - if (!cyl->gasmix.o2.permille) { - cyl->gasmix.o2.permille = 210; - cyl->gasmix.he.permille = 0; - } - cyl->depth.mm = 1600 * 1000 / cyl->gasmix.o2.permille * 10 - 10000; + pressure_t modppO2; + modppO2.mbar = 1600; + cyl->depth = gas_mod(&cyl->gasmix, modppO2); changed = true; } break; @@ -368,11 +366,10 @@ void CylindersModel::remove(const QModelIndex &index) cylinder_t *cyl = ¤t->cylinder[index.row()]; if ((DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING && DivePlannerPointsModel::instance()->tankInUse(cyl->gasmix.o2.permille, cyl->gasmix.he.permille)) || - (DivePlannerPointsModel::instance()->currentMode() == DivePlannerPointsModel::NOTHING && cyl->used)) - { + (DivePlannerPointsModel::instance()->currentMode() == DivePlannerPointsModel::NOTHING && cyl->used)) { QMessageBox::warning(MainWindow::instance(), TITLE_OR_TEXT( - tr("Cylinder cannot be removed"), - tr("This gas in use. Only cylinders that are not used in the dive can be removed.")), + tr("Cylinder cannot be removed"), + tr("This gas in use. Only cylinders that are not used in the dive can be removed.")), QMessageBox::Ok); return; } @@ -1060,7 +1057,7 @@ static int nitrox_sort_value(struct dive *dive) QVariant DiveItem::data(int column, int role) const { QVariant retVal; - struct dive *dive = get_dive_by_diveid(diveId); + struct dive *dive = get_dive_by_uniq_id(diveId); switch (role) { case Qt::TextAlignmentRole: @@ -1203,11 +1200,11 @@ bool DiveItem::setData(const QModelIndex &index, const QVariant &value, int role int i; struct dive *d; - for_each_dive(i, d) { + for_each_dive (i, d) { if (d->number == v) return false; } - d = get_dive_by_diveid(diveId); + d = get_dive_by_uniq_id(diveId); d->number = value.toInt(); mark_divelist_changed(true); return true; @@ -1215,7 +1212,7 @@ bool DiveItem::setData(const QModelIndex &index, const QVariant &value, int role QString DiveItem::displayDate() const { - struct dive *dive = get_dive_by_diveid(diveId); + struct dive *dive = get_dive_by_uniq_id(diveId); return get_dive_date_string(dive->when); } @@ -1223,7 +1220,7 @@ QString DiveItem::displayDepth() const { QString fract, str; const int scale = 1000; - struct dive *dive = get_dive_by_diveid(diveId); + struct dive *dive = get_dive_by_uniq_id(diveId); if (get_units()->length == units::METERS) { fract = QString::number((unsigned)(dive->maxdepth.mm % scale) / 100); str = QString("%1.%2").arg((unsigned)(dive->maxdepth.mm / scale)).arg(fract, 1, QChar('0')); @@ -1237,7 +1234,7 @@ QString DiveItem::displayDepth() const QString DiveItem::displayDuration() const { int hrs, mins, secs; - struct dive *dive = get_dive_by_diveid(diveId); + struct dive *dive = get_dive_by_uniq_id(diveId); secs = dive->duration.seconds % 60; mins = dive->duration.seconds / 60; hrs = mins / 60; @@ -1255,7 +1252,7 @@ QString DiveItem::displayDuration() const QString DiveItem::displayTemperature() const { QString str; - struct dive *dive = get_dive_by_diveid(diveId); + struct dive *dive = get_dive_by_uniq_id(diveId); if (!dive->watertemp.mkelvin) return str; if (get_units()->temperature == units::CELSIUS) @@ -1268,7 +1265,7 @@ QString DiveItem::displayTemperature() const QString DiveItem::displaySac() const { QString str; - struct dive *dive = get_dive_by_diveid(diveId); + struct dive *dive = get_dive_by_uniq_id(diveId); if (get_units()->volume == units::LITER) str = QString::number(dive->sac / 1000.0, 'f', 1).append(tr(" l/min")); else @@ -1284,7 +1281,7 @@ QString DiveItem::displayWeight() const int DiveItem::weight() const { - struct dive *dive = get_dive_by_diveid(diveId); + struct dive *dive = get_dive_by_uniq_id(diveId); weight_t tw = { total_weight(dive) }; return tw.grams; } @@ -1904,7 +1901,7 @@ QVariant ProfilePrintModel::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: { - struct dive *dive = get_dive_by_diveid(diveId); + struct dive *dive = get_dive_by_uniq_id(diveId); struct DiveItem di; di.diveId = diveId; @@ -2060,7 +2057,7 @@ LanguageModel::LanguageModel(QObject *parent) : QAbstractListModel(parent) QSettings s; QDir d(getSubsurfaceDataPath("translations")); QStringList result = d.entryList(); - Q_FOREACH(const QString & s, result) { + Q_FOREACH (const QString &s, result) { if (s.startsWith("subsurface_") && s.endsWith(".qm")) { languages.push_back((s == "subsurface_source.qm") ? "English" : s); } diff --git a/qt-ui/preferences.cpp b/qt-ui/preferences.cpp index 47f8541db..768275d26 100644 --- a/qt-ui/preferences.cpp +++ b/qt-ui/preferences.cpp @@ -236,7 +236,7 @@ void PreferencesDialog::syncSettings() // Animation s.beginGroup("Animations"); - s.setValue("animation_speed",ui.velocitySlider->value()); + s.setValue("animation_speed", ui.velocitySlider->value()); s.endGroup(); loadSettings(); diff --git a/qt-ui/printlayout.cpp b/qt-ui/printlayout.cpp index c30ff9cd1..159b51822 100644 --- a/qt-ui/printlayout.cpp +++ b/qt-ui/printlayout.cpp @@ -98,7 +98,7 @@ int PrintLayout::estimateTotalDives() const { int total = 0, i = 0; struct dive *dive; - for_each_dive(i, dive) { + for_each_dive (i, dive) { if (!dive->selected && printOptions->print_selected) continue; total++; @@ -168,7 +168,7 @@ void PrintLayout::printProfileDives(int divesPerRow, int divesPerColumn) yOffsetTable = scaledH - tableH; // plot the dives at specific rows and columns on the page - for_each_dive(i, dive) { + for_each_dive (i, dive) { if (!dive->selected && printOptions->print_selected) continue; if (col == divesPerColumn) { @@ -183,7 +183,7 @@ void PrintLayout::printProfileDives(int divesPerRow, int divesPerColumn) // draw a profile painter.translate((scaledW + padW) * col, (scaledH + padH) * row + yOffsetProfile); - profile->plotDives(QList<struct dive*>() << dive); + profile->plotDives(QList<struct dive *>() << dive); profile->render(&painter, QRect(0, 0, scaledW, scaledH - tableH - padPT)); painter.setTransform(origTransform); @@ -202,7 +202,7 @@ void PrintLayout::printProfileDives(int divesPerRow, int divesPerColumn) profile->setFrameStyle(profileFrameStyle); profile->setPrintMode(false); profile->resize(originalSize); - profile->plotDives(QList<struct dive*>() << current_dive); + profile->plotDives(QList<struct dive *>() << current_dive); } /* we create a table that has a fixed height, but can stretch to fit certain width */ @@ -309,7 +309,7 @@ void PrintLayout::printTable() addTablePrintHeadingRow(&model, row); // add one heading row row++; progress = 0; - for_each_dive(i, dive) { + for_each_dive (i, dive) { if (!dive->selected && printOptions->print_selected) continue; addTablePrintDataRow(&model, row, dive); diff --git a/qt-ui/profile/animationfunctions.cpp b/qt-ui/profile/animationfunctions.cpp index 05e437cf0..bd08a22ee 100644 --- a/qt-ui/profile/animationfunctions.cpp +++ b/qt-ui/profile/animationfunctions.cpp @@ -4,8 +4,7 @@ #include <QPropertyAnimation> #include <QPointF> -namespace Animations -{ +namespace Animations { void hide(QObject *obj) { @@ -26,15 +25,14 @@ namespace Animations void moveTo(QObject *obj, qreal x, qreal y) { - if (prefs.animation != 0){ + if (prefs.animation != 0) { QPropertyAnimation *animation = new QPropertyAnimation(obj, "pos"); animation->setDuration(prefs.animation); animation->setStartValue(obj->property("pos").toPointF()); animation->setEndValue(QPointF(x, y)); animation->start(QAbstractAnimation::DeleteWhenStopped); - } - else{ - obj->setProperty("pos", QPointF(x,y)); + } else { + obj->setProperty("pos", QPointF(x, y)); } } diff --git a/qt-ui/profile/animationfunctions.h b/qt-ui/profile/animationfunctions.h index e0338393e..9269e6dd3 100644 --- a/qt-ui/profile/animationfunctions.h +++ b/qt-ui/profile/animationfunctions.h @@ -6,8 +6,7 @@ class QObject; -namespace Animations -{ +namespace Animations { void hide(QObject *obj); void moveTo(QObject *obj, qreal x, qreal y); void moveTo(QObject *obj, const QPointF &pos); diff --git a/qt-ui/profile/divecartesianaxis.cpp b/qt-ui/profile/divecartesianaxis.cpp index c1e93faa7..353f9880c 100644 --- a/qt-ui/profile/divecartesianaxis.cpp +++ b/qt-ui/profile/divecartesianaxis.cpp @@ -97,7 +97,7 @@ void DiveCartesianAxis::setTextVisible(bool arg1) return; } textVisibility = arg1; - Q_FOREACH(DiveTextItem * item, labels) { + Q_FOREACH (DiveTextItem *item, labels) { item->setVisible(textVisibility); } } @@ -108,7 +108,7 @@ void DiveCartesianAxis::setLinesVisible(bool arg1) return; } lineVisibility = arg1; - Q_FOREACH(DiveLineItem * item, lines) { + Q_FOREACH (DiveLineItem *item, lines) { item->setVisible(lineVisibility); } } @@ -161,8 +161,8 @@ void DiveCartesianAxis::updateTicks(color_indice_t color) for (int i = 0, count = labels.size(); i < count; i++, currValueText += interval) { qreal childPos = (orientation == TopToBottom || orientation == LeftToRight) ? - begin + i * stepSize : - begin - i * stepSize; + begin + i * stepSize : + begin - i * stepSize; labels[i]->setText(textForValue(currValueText)); if (orientation == LeftToRight || orientation == RightToLeft) { @@ -174,8 +174,8 @@ void DiveCartesianAxis::updateTicks(color_indice_t color) for (int i = 0, count = lines.size(); i < count; i++, currValueLine += interval) { qreal childPos = (orientation == TopToBottom || orientation == LeftToRight) ? - begin + i * stepSize : - begin - i * stepSize; + begin + i * stepSize : + begin - i * stepSize; if (orientation == LeftToRight || orientation == RightToLeft) { lines[i]->animateMoveTo(childPos, m.y1()); @@ -237,9 +237,9 @@ void DiveCartesianAxis::updateTicks(color_indice_t color) } } - Q_FOREACH(DiveTextItem * item, labels) + Q_FOREACH (DiveTextItem *item, labels) item->setVisible(textVisibility); - Q_FOREACH(DiveLineItem * item, lines) + Q_FOREACH (DiveLineItem *item, lines) item->setVisible(lineVisibility); } @@ -272,8 +272,8 @@ qreal DiveCartesianAxis::valueAt(const QPointF &p) const relativePosition -= pos(); // normalize p based on the axis' offset on screen double retValue = (orientation == LeftToRight || orientation == RightToLeft) ? - max * (relativePosition.x() - m.x1()) / (m.x2() - m.x1()) : - max * (relativePosition.y() - m.y1()) / (m.y2() - m.y1()); + max * (relativePosition.x() - m.x1()) / (m.x2() - m.x1()) : + max * (relativePosition.y() - m.y1()) / (m.y2() - m.y1()); return retValue; } @@ -289,8 +289,8 @@ qreal DiveCartesianAxis::posAtValue(qreal value) double realSize = orientation == LeftToRight || orientation == RightToLeft ? - m.x2() - m.x1() : - m.y2() - m.y1(); + m.x2() - m.x1() : + m.y2() - m.y1(); // Inverted axis, just invert the percentage. if (orientation == RightToLeft || orientation == BottomToTop) @@ -298,10 +298,10 @@ qreal DiveCartesianAxis::posAtValue(qreal value) double retValue = realSize * percent; double adjusted = - orientation == LeftToRight ? retValue + m.x1() + p.x() : - orientation == RightToLeft ? retValue + m.x1() + p.x() : - orientation == TopToBottom ? retValue + m.y1() + p.y() : - /* entation == BottomToTop */ retValue + m.y1() + p.y(); + orientation == LeftToRight ? retValue + m.x1() + p.x() : + orientation == RightToLeft ? retValue + m.x1() + p.x() : + orientation == TopToBottom ? retValue + m.y1() + p.y() : + /* entation == BottomToTop */ retValue + m.y1() + p.y(); return adjusted; } @@ -411,17 +411,17 @@ QString TemperatureAxis::textForValue(double value) PartialGasPressureAxis::PartialGasPressureAxis() { - connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(preferencesChanged())); + connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); } void PartialGasPressureAxis::setModel(DivePlotDataModel *m) { model = m; - connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(preferencesChanged())); - preferencesChanged(); + connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(settingsChanged())); + settingsChanged(); } -void PartialGasPressureAxis::preferencesChanged() +void PartialGasPressureAxis::settingsChanged() { bool showPhe = prefs.pp_graphs.phe; bool showPn2 = prefs.pp_graphs.pn2; diff --git a/qt-ui/profile/divecartesianaxis.h b/qt-ui/profile/divecartesianaxis.h index e5b9b7b0e..34089e614 100644 --- a/qt-ui/profile/divecartesianaxis.h +++ b/qt-ui/profile/divecartesianaxis.h @@ -110,7 +110,7 @@ public: void setModel(DivePlotDataModel *model); public slots: - void preferencesChanged(); + void settingsChanged(); private: DivePlotDataModel *model; diff --git a/qt-ui/profile/diveplotdatamodel.cpp b/qt-ui/profile/diveplotdatamodel.cpp index 990564fbb..2fe636a4b 100644 --- a/qt-ui/profile/diveplotdatamodel.cpp +++ b/qt-ui/profile/diveplotdatamodel.cpp @@ -178,7 +178,7 @@ void DivePlotDataModel::emitDataChanged() void DivePlotDataModel::calculateDecompression() { - struct dive *d = get_dive_by_diveid(id()); + struct dive *d = get_dive_by_uniq_id(id()); struct divecomputer *dc = select_dc(d); init_decompression(d); calculate_deco_information(d, dc, &pInfo, false); diff --git a/qt-ui/profile/diveprofileitem.cpp b/qt-ui/profile/diveprofileitem.cpp index 1615be87f..2a6d5ac2f 100644 --- a/qt-ui/profile/diveprofileitem.cpp +++ b/qt-ui/profile/diveprofileitem.cpp @@ -18,10 +18,10 @@ AbstractProfilePolygonItem::AbstractProfilePolygonItem() : QObject(), QGraphicsPolygonItem(), hAxis(NULL), vAxis(NULL), dataModel(NULL), hDataColumn(-1), vDataColumn(-1) { - connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(preferencesChanged())); + connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); } -void AbstractProfilePolygonItem::preferencesChanged() +void AbstractProfilePolygonItem::settingsChanged() { } @@ -156,10 +156,8 @@ void DiveProfileItem::modelDataChanged(const QModelIndex &topLeft, const QModelI if (!entry->in_deco) { /* not in deco implies this is a safety stop, no ceiling */ p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(0))); - } else if (entry->stopdepth < entry->depth) { - p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->stopdepth))); } else { - p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->depth))); + p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(qMin(entry->stopdepth, entry->depth)))); } } setPolygon(p); @@ -194,7 +192,7 @@ void DiveProfileItem::modelDataChanged(const QModelIndex &topLeft, const QModelI } } -void DiveProfileItem::preferencesChanged() +void DiveProfileItem::settingsChanged() { //TODO: Only modelDataChanged() here if we need to rebuild the graph ( for instance, // if the prefs.dcceiling are enabled, but prefs.redceiling is disabled @@ -298,7 +296,7 @@ void DiveHeartrateItem::paint(QPainter *painter, const QStyleOptionGraphicsItem painter->drawPolyline(polygon()); } -void DiveHeartrateItem::preferencesChanged() +void DiveHeartrateItem::settingsChanged() { QSettings s; s.beginGroup("TecDetails"); @@ -427,7 +425,7 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo int last_pressure[MAX_CYLINDERS] = { 0, }; int last_time[MAX_CYLINDERS] = { 0, }; struct plot_data *entry; - struct dive *dive = get_dive_by_diveid(dataModel->id()); + struct dive *dive = get_dive_by_uniq_id(dataModel->id()); cyl = -1; for (int i = 0, count = dataModel->rowCount(); i < count; i++) { @@ -489,9 +487,9 @@ void DiveGasPressureItem::paint(QPainter *painter, const QStyleOptionGraphicsIte QPen pen; pen.setCosmetic(true); pen.setWidth(2); - struct dive *d = get_dive_by_diveid(dataModel->id()); + struct dive *d = get_dive_by_uniq_id(dataModel->id()); struct plot_data *entry = dataModel->data().entry; - Q_FOREACH(const QPolygonF & poly, polygons) { + Q_FOREACH (const QPolygonF &poly, polygons) { for (int i = 1, count = poly.count(); i < count; i++, entry++) { pen.setBrush(getSacColor(entry->sac, d->sac)); painter->setPen(pen); @@ -505,7 +503,7 @@ DiveCalculatedCeiling::DiveCalculatedCeiling() : is3mIncrement(false), gradientF gradientFactor->setY(0); gradientFactor->setBrush(getColor(PRESSURE_TEXT)); gradientFactor->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); - preferencesChanged(); + settingsChanged(); } void DiveCalculatedCeiling::modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) @@ -544,10 +542,10 @@ void DiveCalculatedCeiling::paint(QPainter *painter, const QStyleOptionGraphicsI DiveCalculatedTissue::DiveCalculatedTissue() { - preferencesChanged(); + settingsChanged(); } -void DiveCalculatedTissue::preferencesChanged() +void DiveCalculatedTissue::settingsChanged() { setVisible(prefs.calcalltissues && prefs.calcceiling); } @@ -562,11 +560,7 @@ void DiveReportedCeiling::modelDataChanged(const QModelIndex &topLeft, const QMo plot_data *entry = dataModel->data().entry; for (int i = 0, count = dataModel->rowCount(); i < count; i++, entry++) { if (entry->in_deco && entry->stopdepth) { - if (entry->stopdepth < entry->depth) { - p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->stopdepth))); - } else { - p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->depth))); - } + p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(qMin(entry->stopdepth, entry->depth)))); } else { p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(0))); } @@ -585,7 +579,7 @@ void DiveReportedCeiling::modelDataChanged(const QModelIndex &topLeft, const QMo setBrush(pat); } -void DiveCalculatedCeiling::preferencesChanged() +void DiveCalculatedCeiling::settingsChanged() { if (dataModel && is3mIncrement != prefs.calcceiling3m) { // recalculate that part. @@ -595,7 +589,7 @@ void DiveCalculatedCeiling::preferencesChanged() setVisible(prefs.calcceiling); } -void DiveReportedCeiling::preferencesChanged() +void DiveReportedCeiling::settingsChanged() { setVisible(prefs.dcceiling); } @@ -688,9 +682,8 @@ void PartialPressureGasItem::paint(QPainter *painter, const QStyleOptionGraphics QPolygonF poly; painter->setPen(QPen(alertColor, pWidth)); - Q_FOREACH(const QPolygonF & poly, alertPolygons) + Q_FOREACH (const QPolygonF &poly, alertPolygons) painter->drawPolyline(poly); - } void PartialPressureGasItem::setThreshouldSettingsKey(const QString &threshouldSettingsKey) @@ -702,7 +695,7 @@ PartialPressureGasItem::PartialPressureGasItem() { } -void PartialPressureGasItem::preferencesChanged() +void PartialPressureGasItem::settingsChanged() { QSettings s; s.beginGroup("TecDetails"); diff --git a/qt-ui/profile/diveprofileitem.h b/qt-ui/profile/diveprofileitem.h index c7fa59841..de0c6f0c9 100644 --- a/qt-ui/profile/diveprofileitem.h +++ b/qt-ui/profile/diveprofileitem.h @@ -46,7 +46,7 @@ public: } public slots: - virtual void preferencesChanged(); + virtual void settingsChanged(); virtual void modelDataChanged(const QModelIndex &topLeft = QModelIndex(), const QModelIndex &bottomRight = QModelIndex()); virtual void modelDataRemoved(const QModelIndex &parent, int from, int to); @@ -75,7 +75,7 @@ public: DiveProfileItem(); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); virtual void modelDataChanged(const QModelIndex &topLeft = QModelIndex(), const QModelIndex &bottomRight = QModelIndex()); - virtual void preferencesChanged(); + virtual void settingsChanged(); void plot_depth_sample(struct plot_data *entry, QFlags<Qt::AlignmentFlag> flags, const QColor &color); private: @@ -100,7 +100,7 @@ public: DiveHeartrateItem(); virtual void modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - virtual void preferencesChanged(); + virtual void settingsChanged(); void setVisibilitySettingsKey(const QString &setVisibilitySettingsKey); bool isVisible(); @@ -130,7 +130,7 @@ public: DiveCalculatedCeiling(); virtual void modelDataChanged(const QModelIndex &topLeft = QModelIndex(), const QModelIndex &bottomRight = QModelIndex()); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - virtual void preferencesChanged(); + virtual void settingsChanged(); private: bool is3mIncrement; @@ -143,14 +143,14 @@ class DiveReportedCeiling : public AbstractProfilePolygonItem { public: virtual void modelDataChanged(const QModelIndex &topLeft = QModelIndex(), const QModelIndex &bottomRight = QModelIndex()); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - virtual void preferencesChanged(); + virtual void settingsChanged(); }; class DiveCalculatedTissue : public DiveCalculatedCeiling { Q_OBJECT public: DiveCalculatedTissue(); - virtual void preferencesChanged(); + virtual void settingsChanged(); }; class MeanDepthLine : public DiveLineItem { @@ -176,7 +176,7 @@ public: PartialPressureGasItem(); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); virtual void modelDataChanged(const QModelIndex &topLeft = QModelIndex(), const QModelIndex &bottomRight = QModelIndex()); - virtual void preferencesChanged(); + virtual void settingsChanged(); void setThreshouldSettingsKey(const QString &threshouldSettingsKey); void setVisibilitySettingsKey(const QString &setVisibilitySettingsKey); void setColors(const QColor &normalColor, const QColor &alertColor); diff --git a/qt-ui/profile/divetooltipitem.cpp b/qt-ui/profile/divetooltipitem.cpp index 0e68685b9..032daf6ee 100644 --- a/qt-ui/profile/divetooltipitem.cpp +++ b/qt-ui/profile/divetooltipitem.cpp @@ -1,5 +1,6 @@ #include "divetooltipitem.h" #include "divecartesianaxis.h" +#include "profilewidget2.h" #include "profile.h" #include "dive.h" #include "membuffer.h" @@ -21,7 +22,7 @@ void ToolTipItem::addToolTip(const QString &toolTip, const QIcon &icon) { QGraphicsPixmapItem *iconItem = 0; double yValue = title->boundingRect().height() + SPACING; - Q_FOREACH(ToolTip t, toolTips) { + Q_FOREACH (ToolTip t, toolTips) { yValue += t.second->boundingRect().height(); } if (!icon.isNull()) { @@ -39,7 +40,7 @@ void ToolTipItem::addToolTip(const QString &toolTip, const QIcon &icon) void ToolTipItem::clear() { - Q_FOREACH(ToolTip t, toolTips) { + Q_FOREACH (ToolTip t, toolTips) { delete t.first; delete t.second; } @@ -96,7 +97,7 @@ void ToolTipItem::expand() return; double width = 0, height = title->boundingRect().height() + SPACING; - Q_FOREACH(ToolTip t, toolTips) { + Q_FOREACH (ToolTip t, toolTips) { if (t.second->boundingRect().width() > width) width = t.second->boundingRect().width(); height += t.second->boundingRect().height(); @@ -180,6 +181,9 @@ void ToolTipItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { persistPos(); QGraphicsPathItem::mouseReleaseEvent(event); + Q_FOREACH (QGraphicsItem *item, oldSelection) { + item->setSelected(true); + } } void ToolTipItem::persistPos() @@ -226,8 +230,15 @@ void ToolTipItem::refresh(const QPointF &pos) free_buffer(&mb); QList<QGraphicsItem *> items = scene()->items(pos, Qt::IntersectsItemShape, Qt::DescendingOrder, scene()->views().first()->transform()); - Q_FOREACH(QGraphicsItem * item, items) { + Q_FOREACH (QGraphicsItem *item, items) { if (!item->toolTip().isEmpty()) addToolTip(item->toolTip()); } } + +void ToolTipItem::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + oldSelection = scene()->selectedItems(); + scene()->clearSelection(); + QGraphicsItem::mousePressEvent(event); +} diff --git a/qt-ui/profile/divetooltipitem.h b/qt-ui/profile/divetooltipitem.h index 1f84d0664..c22287b06 100644 --- a/qt-ui/profile/divetooltipitem.h +++ b/qt-ui/profile/divetooltipitem.h @@ -45,6 +45,7 @@ public: bool isExpanded() const; void persistPos(); void readPos(); + void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); void setTimeAxis(DiveCartesianAxis *axis); void setPlotInfo(const plot_info &plot); @@ -64,6 +65,8 @@ private: DiveCartesianAxis *timeAxis; plot_info pInfo; int lastTime; + + QList<QGraphicsItem*> oldSelection; }; #endif // DIVETOOLTIPITEM_H diff --git a/qt-ui/profile/profilewidget2.cpp b/qt-ui/profile/profilewidget2.cpp index d2d01a384..2de64e71f 100644 --- a/qt-ui/profile/profilewidget2.cpp +++ b/qt-ui/profile/profilewidget2.cpp @@ -21,7 +21,6 @@ #include <QMenu> #include <QContextMenuEvent> #include <QDebug> -#include <QSettings> #include <QScrollBar> #include <QtCore/qmath.h> #include <QMessageBox> @@ -100,6 +99,23 @@ ProfileWidget2::ProfileWidget2(QWidget *parent) : QGraphicsView(parent), setEmptyState(); connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); + QAction *action = NULL; +#define ADD_ACTION(SHORTCUT, Slot) \ + action = new QAction(this); \ + action->setShortcut(SHORTCUT); \ + action->setShortcutContext(Qt::WindowShortcut); \ + addAction(action); \ + connect(action, SIGNAL(triggered(bool)), this, SLOT(Slot)); \ + actionsForKeys[SHORTCUT] = action; + + ADD_ACTION(Qt::Key_Escape, keyEscAction()); + ADD_ACTION(Qt::Key_Delete, keyDeleteAction()); + ADD_ACTION(Qt::Key_Up, keyUpAction()); + ADD_ACTION(Qt::Key_Down, keyDownAction()); + ADD_ACTION(Qt::Key_Left, keyLeftAction()); + ADD_ACTION(Qt::Key_Right, keyRightAction()); +#undef ADD_ACTION + #ifndef QT_NO_DEBUG QTableView *diveDepthTableView = new QTableView(); diveDepthTableView->setModel(dataModel); @@ -107,6 +123,9 @@ ProfileWidget2::ProfileWidget2(QWidget *parent) : QGraphicsView(parent), #endif } +#define SUBSURFACE_OBJ_DATA 1 +#define SUBSURFACE_OBJ_DC_TEXT 0x42 + void ProfileWidget2::addItemsToScene() { scene()->addItem(background); @@ -120,6 +139,11 @@ void ProfileWidget2::addItemsToScene() scene()->addItem(temperatureItem); scene()->addItem(gasPressureItem); scene()->addItem(meanDepth); + // I cannot seem to figure out if an object that I find with itemAt() on the scene + // is the object I am looking for - my guess is there's a simple way in Qt to do that + // but nothing I tried worked. + // so instead this adds a special magic key/value pair to the object to mark it + diveComputerText->setData(SUBSURFACE_OBJ_DATA, SUBSURFACE_OBJ_DC_TEXT); scene()->addItem(diveComputerText); scene()->addItem(diveCeiling); scene()->addItem(reportedCeiling); @@ -131,7 +155,7 @@ void ProfileWidget2::addItemsToScene() scene()->addItem(rulerItem); scene()->addItem(rulerItem->sourceNode()); scene()->addItem(rulerItem->destNode()); - Q_FOREACH(DiveCalculatedTissue * tissue, allTissues) { + Q_FOREACH (DiveCalculatedTissue *tissue, allTissues) { scene()->addItem(tissue); } } @@ -196,7 +220,7 @@ void ProfileWidget2::setupItemOnScene() setupItem(temperatureItem, timeAxis, temperatureAxis, dataModel, DivePlotDataModel::TEMPERATURE, DivePlotDataModel::TIME, 1); setupItem(heartBeatItem, timeAxis, heartBeatAxis, dataModel, DivePlotDataModel::HEARTBEAT, DivePlotDataModel::TIME, 1); heartBeatItem->setVisibilitySettingsKey("hrgraph"); - heartBeatItem->preferencesChanged(); + heartBeatItem->settingsChanged(); setupItem(diveProfileItem, timeAxis, profileYAxis, dataModel, DivePlotDataModel::DEPTH, DivePlotDataModel::TIME, 0); #define CREATE_PP_GAS(ITEM, VERTICAL_COLUMN, COLOR, COLOR_ALERT, THRESHOULD_SETTINGS, VISIBILITY_SETTINGS) \ @@ -204,7 +228,7 @@ void ProfileWidget2::setupItemOnScene() ITEM->setThreshouldSettingsKey(THRESHOULD_SETTINGS); \ ITEM->setVisibilitySettingsKey(VISIBILITY_SETTINGS); \ ITEM->setColors(getColor(COLOR, isGrayscale), getColor(COLOR_ALERT, isGrayscale)); \ - ITEM->preferencesChanged(); \ + ITEM->settingsChanged(); \ ITEM->setZValue(99); CREATE_PP_GAS(pn2GasItem, PN2, PN2, PN2_ALERT, "pn2threshold", "pn2graph"); @@ -227,7 +251,7 @@ void ProfileWidget2::replot() { int diveId = dataModel->id(); dataModel->clear(); - plotDives(QList<dive *>() << get_dive_by_diveid(diveId)); + plotDives(QList<dive *>() << get_dive_by_uniq_id(diveId)); } void ProfileWidget2::setupItemSizes() @@ -336,6 +360,19 @@ void ProfileWidget2::plotDives(QList<dive *> dives) if (!d) return; + //TODO: This is a temporary hack to help me understand the Planner. + // It seems that each time the 'createTemporaryPlan' runs, a new + // dive is created, and thus, we can plot that. hm... + if (currentState == ADD) { + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + plannerModel->createTemporaryPlan(); + if (!plannerModel->getDiveplan().dp) { + plannerModel->deleteTemporaryPlan(); + return; + } + } + //END + int animSpeedBackup = -1; if (firstCall && MainWindow::instance()->filesFromCommandLine()) { animSpeedBackup = prefs.animation; @@ -352,12 +389,7 @@ void ProfileWidget2::plotDives(QList<dive *> dives) // reset some item visibility on printMode changes toolTipItem->setVisible(!printMode); - QSettings s; - s.beginGroup("TecDetails"); - const bool rulerVisible = s.value("rulergraph", false).toBool() && !printMode; - rulerItem->setVisible(rulerVisible); - rulerItem->sourceNode()->setVisible(rulerVisible); - rulerItem->destNode()->setVisible(rulerVisible); + rulerItem->setVisible(prefs.rulergraph && !printMode); // No need to do this again if we are already showing the same dive // computer of the same dive, so we check the unique id of the dive @@ -368,7 +400,8 @@ void ProfileWidget2::plotDives(QList<dive *> dives) if (d->id == dataModel->id() && dc_number == dataModel->dcShown()) return; - setProfileState(); + if (currentState == EMPTY) + setProfileState(); // next get the dive computer structure - if there are no samples // let's create a fake profile that's somewhat reasonable for the @@ -463,14 +496,24 @@ void ProfileWidget2::plotDives(QList<dive *> dives) event = event->next; } // Only set visible the events that should be visible - Q_FOREACH(DiveEventItem * event, eventItems) { + Q_FOREACH (DiveEventItem *event, eventItems) { event->setVisible(!event->shouldBeHidden()); // qDebug() << event->getEvent()->name << "@" << event->getEvent()->time.seconds << "is hidden:" << event->isHidden(); } - diveComputerText->setText(currentdc->model); + QString dcText = currentdc->model; + int nr; + if ((nr = number_of_computers(current_dive)) > 1) + dcText += tr(" (#%1 of %2)").arg(dc_number + 1).arg(nr); + diveComputerText->setText(dcText); if (MainWindow::instance()->filesFromCommandLine() && animSpeedBackup != -1) { prefs.animation = animSpeedBackup; } + + if (currentState == ADD) { // TODO: figure a way to move this from here. + repositionDiveHandlers(); + DivePlannerPointsModel *model = DivePlannerPointsModel::instance(); + model->deleteTemporaryPlan(); + } } void ProfileWidget2::settingsChanged() @@ -492,16 +535,6 @@ void ProfileWidget2::settingsChanged() needReplot = true; } - if (currentState == PROFILE) { - rulerItem->setVisible(prefs.rulergraph); - rulerItem->destNode()->setVisible(prefs.rulergraph); - rulerItem->sourceNode()->setVisible(prefs.rulergraph); - needReplot = true; - } else { - rulerItem->setVisible(false); - rulerItem->destNode()->setVisible(false); - rulerItem->sourceNode()->setVisible(false); - } if (needReplot) replot(); } @@ -543,6 +576,30 @@ void ProfileWidget2::wheelEvent(QWheelEvent *event) toolTipItem->setPos(mapToScene(toolTipPos)); } +void ProfileWidget2::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (currentState == PLAN || currentState == ADD) { + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + QPointF mappedPos = mapToScene(event->pos()); + if (isPointOutOfBoundaries(mappedPos)) + return; + + int minutes = rint(timeAxis->valueAt(mappedPos) / 60); + int milimeters = rint(profileYAxis->valueAt(mappedPos) / M_OR_FT(1, 1)) * M_OR_FT(1, 1); + plannerModel->addStop(milimeters, minutes * 60, -1, 0, 0, true); + } +} + +bool ProfileWidget2::isPointOutOfBoundaries(const QPointF &point) const +{ + double xpos = timeAxis->valueAt(point); + double ypos = profileYAxis->valueAt(point); + return (xpos > timeAxis->maximum() || + xpos < timeAxis->minimum() || + ypos > profileYAxis->maximum() || + ypos < profileYAxis->minimum()); +} + void ProfileWidget2::scrollViewTo(const QPoint &pos) { /* since we cannot use translate() directly on the scene we hack on @@ -585,6 +642,8 @@ void ProfileWidget2::setEmptyState() if (currentState == EMPTY) return; + disconnectTemporaryConnections(); + setBackgroundBrush(getColor(::BACKGROUND, isGrayscale)); dataModel->clear(); currentState = EMPTY; MainWindow::instance()->setToolButtonsEnabled(false); @@ -604,15 +663,13 @@ void ProfileWidget2::setEmptyState() diveCeiling->setVisible(false); reportedCeiling->setVisible(false); rulerItem->setVisible(false); - rulerItem->destNode()->setVisible(false); - rulerItem->sourceNode()->setVisible(false); pn2GasItem->setVisible(false); po2GasItem->setVisible(false); pheGasItem->setVisible(false); - Q_FOREACH(DiveCalculatedTissue * tissue, allTissues) { + Q_FOREACH (DiveCalculatedTissue *tissue, allTissues) { tissue->setVisible(false); } - Q_FOREACH(DiveEventItem * event, eventItems) { + Q_FOREACH (DiveEventItem *event, eventItems) { event->setVisible(false); } } @@ -623,6 +680,10 @@ void ProfileWidget2::setProfileState() if (currentState == PROFILE) return; + disconnectTemporaryConnections(); + //TODO: Move the DC handling to another method. + MainWindow::instance()->enableDcShortcuts(); + currentState = PROFILE; MainWindow::instance()->setToolButtonsEnabled(true); toolTipItem->readPos(); @@ -670,16 +731,50 @@ void ProfileWidget2::setProfileState() reportedCeiling->setVisible(prefs.dcceiling); if (prefs.calcalltissues) { - Q_FOREACH(DiveCalculatedTissue * tissue, allTissues) { + Q_FOREACH (DiveCalculatedTissue *tissue, allTissues) { tissue->setVisible(true); } } - QSettings s; - s.beginGroup("TecDetails"); - bool rulerVisible = s.value("rulergraph", false).toBool(); - rulerItem->setVisible(rulerVisible); - rulerItem->destNode()->setVisible(rulerVisible); - rulerItem->sourceNode()->setVisible(rulerVisible); + rulerItem->setVisible(prefs.rulergraph); +} + +void ProfileWidget2::setAddState() +{ + if (currentState == ADD) + return; + + setProfileState(); + disconnectTemporaryConnections(); + //TODO: Move this method to another place, shouldn't be on mainwindow. + MainWindow::instance()->disableDcShortcuts(); + actionsForKeys[Qt::Key_Left]->setShortcut(Qt::Key_Left); + actionsForKeys[Qt::Key_Right]->setShortcut(Qt::Key_Right); + actionsForKeys[Qt::Key_Up]->setShortcut(Qt::Key_Up); + actionsForKeys[Qt::Key_Down]->setShortcut(Qt::Key_Down); + actionsForKeys[Qt::Key_Escape]->setShortcut(Qt::Key_Escape); + actionsForKeys[Qt::Key_Delete]->setShortcut(Qt::Key_Delete); + + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + connect(plannerModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(replot())); + connect(plannerModel, SIGNAL(cylinderModelEdited()), this, SLOT(replot())); + connect(plannerModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(pointInserted(const QModelIndex &, int, int))); + connect(plannerModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(pointsRemoved(const QModelIndex &, int, int))); + /* show the same stuff that the profile shows. */ + currentState = ADD; /* enable the add state. */ + setBackgroundBrush(QColor(Qt::blue).light()); +} + +void ProfileWidget2::setPlanState() +{ + if (currentState == PLAN) + return; + setProfileState(); + disconnectTemporaryConnections(); + /* show the same stuff that the profile shows. */ + currentState = PLAN; /* enable the add state. */ + setBackgroundBrush(QColor(Qt::green).light()); } extern struct ev_select *ev_namelist; @@ -688,9 +783,36 @@ extern int evn_used; void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event) { - if (selected_dive == -1) + if (currentState == ADD || currentState == PLAN) { + QGraphicsView::contextMenuEvent(event); return; + } QMenu m; + bool isDCName = false; + if (selected_dive == -1) + return; + // figure out if we are ontop of the dive computer name in the profile + QGraphicsItem *sceneItem = itemAt(mapFromGlobal(event->globalPos())); + if (sceneItem) { + QGraphicsItem *parentItem = sceneItem; + while (parentItem) { + if (parentItem->data(SUBSURFACE_OBJ_DATA) == SUBSURFACE_OBJ_DC_TEXT) { + isDCName = true; + break; + } + parentItem = parentItem->parentItem(); + } + if (isDCName) { + if (dc_number == 0) + return; + // create menu to show when right clicking on dive computer name + m.addAction(tr("Make first divecomputer"), this, SLOT(makeFirstDC())); + m.exec(event->globalPos()); + // don't show the regular profile context menu + return; + } + } + // create the profile context menu QMenu *gasChange = m.addMenu(tr("Add Gas Change")); GasSelectionModel *model = GasSelectionModel::instance(); model->repopulate(); @@ -704,7 +826,6 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event) } QAction *action = m.addAction(tr("Add Bookmark"), this, SLOT(addBookmark())); action->setData(event->globalPos()); - QGraphicsItem *sceneItem = itemAt(mapFromGlobal(event->globalPos())); if (DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem)) { action = new QAction(&m); action->setText(tr("Remove Event")); @@ -738,6 +859,18 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event) m.exec(event->globalPos()); } +void ProfileWidget2::makeFirstDC() +{ + make_first_dc(); + mark_divelist_changed(true); + // this is now the first DC, so we need to redraw the profile and refresh the dive list + // (and no, it's not just enough to rewrite the text - the first DC is special so values in the + // dive list may change). + // As a side benefit, this returns focus to the dive list. + dc_number = 0; + MainWindow::instance()->refreshDisplay(); +} + void ProfileWidget2::hideEvents() { QAction *action = qobject_cast<QAction *>(sender()); @@ -749,14 +882,18 @@ void ProfileWidget2::hideEvents() QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { if (event->name) { for (int i = 0; i < evn_used; i++) { - if (!strcmp(event->name, ev_namelist[i].ev_name)) { + if (same_string(event->name, ev_namelist[i].ev_name)) { ev_namelist[i].plot_ev = false; break; } } + Q_FOREACH (DiveEventItem *evItem, eventItems) { + if (same_string(evItem->getEvent()->name, event->name)) + evItem->hide(); + } + } else { + item->hide(); } - item->hide(); - replot(); } } @@ -765,7 +902,8 @@ void ProfileWidget2::unhideEvents() for (int i = 0; i < evn_used; i++) { ev_namelist[i].plot_ev = true; } - replot(); + Q_FOREACH (DiveEventItem *item, eventItems) + item->show(); } void ProfileWidget2::removeEvent() @@ -775,16 +913,10 @@ void ProfileWidget2::removeEvent() struct event *event = item->getEvent(); if (QMessageBox::question(MainWindow::instance(), TITLE_OR_TEXT( - tr("Remove the selected event?"), - tr("%1 @ %2:%3").arg(event->name).arg(event->time.seconds / 60).arg(event->time.seconds % 60, 2, 10, QChar('0'))), + tr("Remove the selected event?"), + tr("%1 @ %2:%3").arg(event->name).arg(event->time.seconds / 60).arg(event->time.seconds % 60, 2, 10, QChar('0'))), QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { - struct event **ep = ¤t_dc->events; - while (ep && *ep != event) - ep = &(*ep)->next; - if (ep) { - *ep = event->next; - free(event); - } + remove_event(event); mark_divelist_changed(true); replot(); } @@ -808,7 +940,7 @@ void ProfileWidget2::changeGas() int diveId = dataModel->id(); int o2, he; int seconds = timeAxis->valueAt(scenePos); - struct dive *d = get_dive_by_diveid(diveId); + struct dive *d = get_dive_by_uniq_id(diveId); validate_gas(gas.toUtf8().constData(), &o2, &he); add_gas_switch_event(d, get_dive_dc(d, diveComputer), seconds, get_gasidx(d, o2, he)); @@ -846,3 +978,248 @@ void ProfileWidget2::editName() } replot(); } + +void ProfileWidget2::disconnectTemporaryConnections() +{ + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + disconnect(plannerModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(replot())); + disconnect(plannerModel, SIGNAL(cylinderModelEdited()), this, SLOT(replot())); + + disconnect(plannerModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(pointInserted(const QModelIndex &, int, int))); + disconnect(plannerModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(pointsRemoved(const QModelIndex &, int, int))); + + + Q_FOREACH (QAction *action, actionsForKeys.values()) { + action->setShortcut(QKeySequence()); + } +} + +void ProfileWidget2::pointInserted(const QModelIndex &parent, int start, int end) +{ + DiveHandler *item = new DiveHandler(); + scene()->addItem(item); + handles << item; + + connect(item, SIGNAL(moved()), this, SLOT(recreatePlannedDive())); + QGraphicsSimpleTextItem *gasChooseBtn = new QGraphicsSimpleTextItem(); + scene()->addItem(gasChooseBtn); + gasChooseBtn->setZValue(10); + gasChooseBtn->setFlag(QGraphicsItem::ItemIgnoresTransformations); + gases << gasChooseBtn; + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + if (plannerModel->recalcQ()) + replot(); +} + +void ProfileWidget2::pointsRemoved(const QModelIndex &, int start, int end) +{ // start and end are inclusive. + int num = (end - start) + 1; + for (int i = num; i != 0; i--) { + delete handles.back(); + handles.pop_back(); + delete gases.back(); + gases.pop_back(); + } + scene()->clearSelection(); + replot(); +} + +void ProfileWidget2::repositionDiveHandlers() +{ + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + // Re-position the user generated dive handlers + int last = 0; + for (int i = 0; i < plannerModel->rowCount(); i++) { + struct divedatapoint datapoint = plannerModel->at(i); + if (datapoint.time == 0) // those are the magic entries for tanks + continue; + DiveHandler *h = handles.at(i); + h->setPos(timeAxis->posAtValue(datapoint.time), profileYAxis->posAtValue(datapoint.depth)); + QPointF p1 = (last == i) ? QPointF(timeAxis->posAtValue(0), profileYAxis->posAtValue(0)) : handles[last]->pos(); + QPointF p2 = handles[i]->pos(); + QLineF line(p1, p2); + QPointF pos = line.pointAt(0.5); + gases[i]->setPos(pos); + gases[i]->setText(dpGasToStr(plannerModel->at(i))); + last = i; + } +} + +int ProfileWidget2::fixHandlerIndex(DiveHandler *activeHandler) +{ + int index = handles.indexOf(activeHandler); + if (index > 0 && index < handles.count() - 1) { + DiveHandler *before = handles[index - 1]; + if (before->pos().x() > activeHandler->pos().x()) { + handles.swap(index, index - 1); + return index - 1; + } + DiveHandler *after = handles[index + 1]; + if (after->pos().x() < activeHandler->pos().x()) { + handles.swap(index, index + 1); + return index + 1; + } + } + return index; +} + +void ProfileWidget2::recreatePlannedDive() +{ + DiveHandler *activeHandler = qobject_cast<DiveHandler *>(sender()); + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + int index = fixHandlerIndex(activeHandler); + int mintime = 0, maxtime = (timeAxis->maximum() + 10) * 60; + if (index > 0) + mintime = plannerModel->at(index - 1).time; + if (index < plannerModel->size() - 1) + maxtime = plannerModel->at(index + 1).time; + + int minutes = rint(timeAxis->valueAt(activeHandler->pos()) / 60); + if (minutes * 60 <= mintime || minutes * 60 >= maxtime) + return; + + divedatapoint data = plannerModel->at(index); + data.depth = rint(profileYAxis->valueAt(activeHandler->pos()) / M_OR_FT(1, 1)) * M_OR_FT(1, 1); + data.time = rint(timeAxis->valueAt(activeHandler->pos())); + + plannerModel->editStop(index, data); +} + +void ProfileWidget2::keyDownAction() +{ + if (currentState != ADD && currentState != PLAN) + return; + + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { + if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { + int row = handles.indexOf(handler); + divedatapoint dp = plannerModel->at(row); + if (dp.depth >= profileYAxis->maximum()) + continue; + + dp.depth += M_OR_FT(1, 5); + plannerModel->editStop(row, dp); + } + } +} + +void ProfileWidget2::keyUpAction() +{ + if (currentState != ADD && currentState != PLAN) + return; + + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { + if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { + int row = handles.indexOf(handler); + divedatapoint dp = plannerModel->at(row); + + if (dp.depth <= 0) + continue; + + dp.depth -= M_OR_FT(1, 5); + plannerModel->editStop(row, dp); + } + } +} + +void ProfileWidget2::keyLeftAction() +{ + if (currentState != ADD && currentState != PLAN) + return; + + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { + if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { + int row = handles.indexOf(handler); + divedatapoint dp = plannerModel->at(row); + + if (dp.time / 60 <= 0) + continue; + + // don't overlap positions. + // maybe this is a good place for a 'goto'? + double xpos = timeAxis->posAtValue((dp.time - 60) / 60); + bool nextStep = false; + Q_FOREACH (DiveHandler *h, handles) { + if (IS_FP_SAME(h->pos().x(), xpos)) { + nextStep = true; + break; + } + } + if (nextStep) + continue; + + dp.time -= 60; + plannerModel->editStop(row, dp); + } + } +} + +void ProfileWidget2::keyRightAction() +{ + if (currentState != ADD && currentState != PLAN) + return; + + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { + if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { + int row = handles.indexOf(handler); + divedatapoint dp = plannerModel->at(row); + if (dp.time / 60 >= timeAxis->maximum()) + continue; + + // don't overlap positions. + // maybe this is a good place for a 'goto'? + double xpos = timeAxis->posAtValue((dp.time + 60) / 60); + bool nextStep = false; + Q_FOREACH (DiveHandler *h, handles) { + if (IS_FP_SAME(h->pos().x(), xpos)) { + nextStep = true; + break; + } + } + if (nextStep) + continue; + + dp.time += 60; + plannerModel->editStop(row, dp); + } + } +} + +void ProfileWidget2::keyDeleteAction() +{ + if (currentState != ADD && currentState != PLAN) + return; + + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + int selCount = scene()->selectedItems().count(); + if (selCount) { + QVector<int> selectedIndexes; + Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { + if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { + selectedIndexes.push_back(handles.indexOf(handler)); + } + } + plannerModel->removeSelectedPoints(selectedIndexes); + } +} + +void ProfileWidget2::keyEscAction() +{ + if (currentState != ADD && currentState != PLAN) + return; + + if (scene()->selectedItems().count()) { + scene()->clearSelection(); + return; + } + + DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + if (plannerModel->isPlanner()) + plannerModel->cancelPlan(); +} diff --git a/qt-ui/profile/profilewidget2.h b/qt-ui/profile/profilewidget2.h index d00cb26c1..3c3d86d01 100644 --- a/qt-ui/profile/profilewidget2.h +++ b/qt-ui/profile/profilewidget2.h @@ -40,6 +40,9 @@ class DiveCalculatedTissue; class PartialPressureGasItem; class PartialGasPressureAxis; class AbstractProfilePolygonItem; +class DiveHandler; +class QGraphicsSimpleTextItem; +class QModelIndex; class ProfileWidget2 : public QGraphicsView { Q_OBJECT @@ -64,28 +67,47 @@ public: ProfileWidget2(QWidget *parent = 0); void plotDives(QList<dive *> dives); - void replot(); virtual bool eventFilter(QObject *, QEvent *); void setupItem(AbstractProfilePolygonItem *item, DiveCartesianAxis *hAxis, DiveCartesianAxis *vAxis, DivePlotDataModel *model, int vData, int hData, int zValue); void setPrintMode(bool mode, bool grayscale = false); + bool isPointOutOfBoundaries(const QPointF &point) const; + State currentState; public slots: // Necessary to call from QAction's signals. void settingsChanged(); void setEmptyState(); void setProfileState(); + void setPlanState(); + void setAddState(); void changeGas(); void addBookmark(); void hideEvents(); void unhideEvents(); void removeEvent(); void editName(); + void makeFirstDC(); + void pointInserted(const QModelIndex &parent, int start, int end); + void pointsRemoved(const QModelIndex &, int start, int end); + void replot(); + + /* this is called for every move on the handlers. maybe we can speed up this a bit? */ + void recreatePlannedDive(); + + /* key press handlers */ + void keyEscAction(); + void keyDeleteAction(); + void keyUpAction(); + void keyDownAction(); + void keyLeftAction(); + void keyRightAction(); protected: virtual void resizeEvent(QResizeEvent *event); virtual void wheelEvent(QWheelEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); virtual void contextMenuEvent(QContextMenuEvent *event); + virtual void mouseDoubleClickEvent(QMouseEvent *event); private: /*methods*/ void fixBackgroundPos(); @@ -94,10 +116,10 @@ private: /*methods*/ void setupItemSizes(); void addItemsToScene(); void setupItemOnScene(); + void disconnectTemporaryConnections(); private: DivePlotDataModel *dataModel; - State currentState; int zoomLevel; qreal zoomFactor; DivePixmapItem *background; @@ -130,6 +152,14 @@ private: RulerItem2 *rulerItem; bool isGrayscale; bool printMode; + + //specifics for ADD and PLAN + QList<DiveHandler *> handles; + QList<QGraphicsSimpleTextItem *> gases; + void repositionDiveHandlers(); + int fixHandlerIndex(DiveHandler *activeHandler); + friend class DiveHandler; + QHash<Qt::Key, QAction *> actionsForKeys; }; #endif // PROFILEWIDGET2_H diff --git a/qt-ui/profile/ruleritem.cpp b/qt-ui/profile/ruleritem.cpp index 768d912e9..0f2a24a80 100644 --- a/qt-ui/profile/ruleritem.cpp +++ b/qt-ui/profile/ruleritem.cpp @@ -1,5 +1,7 @@ #include "ruleritem.h" #include "divetextitem.h" +#include "profilewidget2.h" +#include "../preferences.h" #include <QFont> #include <QFontMetrics> @@ -24,7 +26,7 @@ RulerNodeItem2::RulerNodeItem2() : entry(NULL), ruler(NULL) setFlag(ItemIgnoresTransformations); } -void RulerNodeItem2::setPlotInfo(plot_info& info) +void RulerNodeItem2::setPlotInfo(plot_info &info) { pInfo = info; entry = pInfo.entry; @@ -79,6 +81,15 @@ RulerItem2::RulerItem2() : source(new RulerNodeItem2()), textItemBack->setPen(QColor(Qt::white)); textItemBack->setFlag(QGraphicsItem::ItemIgnoresTransformations); setPen(QPen(QColor(Qt::black), 0.0)); + connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); +} + +void RulerItem2::settingsChanged() +{ + ProfileWidget2 *profWidget = NULL; + if (scene() && scene()->views().count()) + profWidget = qobject_cast<ProfileWidget2 *>(scene()->views().first()); + setVisible(profWidget->currentState == ProfileWidget2::PROFILE ? prefs.rulergraph : false); } void RulerItem2::recalculate() @@ -157,3 +168,10 @@ void RulerItem2::setAxis(DiveCartesianAxis *time, DiveCartesianAxis *depth) source->timeAxis = time; recalculate(); } + +void RulerItem2::setVisible(bool visible) +{ + QGraphicsLineItem::setVisible(visible); + source->setVisible(visible); + dest->setVisible(visible); +} diff --git a/qt-ui/profile/ruleritem.h b/qt-ui/profile/ruleritem.h index 7bfc63eee..3eda33225 100644 --- a/qt-ui/profile/ruleritem.h +++ b/qt-ui/profile/ruleritem.h @@ -17,7 +17,7 @@ class RulerNodeItem2 : public QObject, public QGraphicsEllipseItem { public: explicit RulerNodeItem2(); void setRuler(RulerItem2 *r); - void setPlotInfo(struct plot_info& info); + void setPlotInfo(struct plot_info &info); void recalculate(); protected: @@ -31,7 +31,8 @@ private: DiveCartesianAxis *depthAxis; }; -class RulerItem2 : public QGraphicsLineItem { +class RulerItem2 : public QObject, public QGraphicsLineItem { + Q_OBJECT public: explicit RulerItem2(); void recalculate(); @@ -40,6 +41,11 @@ public: RulerNodeItem2 *sourceNode() const; RulerNodeItem2 *destNode() const; void setAxis(DiveCartesianAxis *time, DiveCartesianAxis *depth); + void setVisible(bool visible); + +public +slots: + void settingsChanged(); private: struct plot_info pInfo; diff --git a/qt-ui/simplewidgets.cpp b/qt-ui/simplewidgets.cpp index 8932baf15..99e0ba362 100644 --- a/qt-ui/simplewidgets.cpp +++ b/qt-ui/simplewidgets.cpp @@ -16,8 +16,9 @@ #include <QDateTime> #include <QShortcut> #include "exif.h" -#include "../dive.h" -#include "../file.h" +#include "dive.h" +#include "file.h" +#include "display.h" #include "mainwindow.h" #include "helpers.h" @@ -117,15 +118,24 @@ RenumberDialog *RenumberDialog::instance() return self; } +void RenumberDialog::renumberOnlySelected(bool selected) +{ + if (selected && amount_selected == 1) + ui.groupBox->setTitle(tr("New number")); + else + ui.groupBox->setTitle(tr("New starting number")); + selectedOnly = selected; +} + void RenumberDialog::buttonClicked(QAbstractButton *button) { if (ui.buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) { qDebug() << "Renumbering."; - renumber_dives(ui.spinBox->value()); + renumber_dives(ui.spinBox->value(), selectedOnly); } } -RenumberDialog::RenumberDialog(QWidget *parent) : QDialog(parent) +RenumberDialog::RenumberDialog(QWidget *parent) : QDialog(parent), selectedOnly(false) { ui.setupUi(this); connect(ui.buttonBox, SIGNAL(clicked(QAbstractButton *)), this, SLOT(buttonClicked(QAbstractButton *))); @@ -161,10 +171,10 @@ void ShiftTimesDialog::buttonClicked(QAbstractButton *button) } } -void ShiftTimesDialog::showEvent(QShowEvent * event) +void ShiftTimesDialog::showEvent(QShowEvent *event) { ui.timeEdit->setTime(QTime(0, 0, 0, 0)); - when = get_times();//get time of first selected dive + when = get_times(); //get time of first selected dive ui.currentTime->setText(get_dive_date_string(when)); ui.shiftedTime->setText(get_dive_date_string(when)); } @@ -177,7 +187,7 @@ void ShiftTimesDialog::changeTime() if (ui.backwards->isChecked()) amount *= -1; - ui.shiftedTime->setText (get_dive_date_string(amount+when)); + ui.shiftedTime->setText(get_dive_date_string(amount + when)); } ShiftTimesDialog::ShiftTimesDialog(QWidget *parent) : QDialog(parent) diff --git a/qt-ui/simplewidgets.h b/qt-ui/simplewidgets.h index d43d2bbcc..cecb52815 100644 --- a/qt-ui/simplewidgets.h +++ b/qt-ui/simplewidgets.h @@ -40,6 +40,7 @@ class RenumberDialog : public QDialog { Q_OBJECT public: static RenumberDialog *instance(); + void renumberOnlySelected(bool selected = true); private slots: void buttonClicked(QAbstractButton *button); @@ -47,17 +48,18 @@ slots: private: explicit RenumberDialog(QWidget *parent); Ui::RenumberDialog ui; + bool selectedOnly; }; class ShiftTimesDialog : public QDialog { Q_OBJECT public: static ShiftTimesDialog *instance(); - void showEvent ( QShowEvent * event ); + void showEvent(QShowEvent *event); private slots: void buttonClicked(QAbstractButton *button); - void changeTime (); + void changeTime(); private: explicit ShiftTimesDialog(QWidget *parent); diff --git a/qt-ui/subsurfacewebservices.cpp b/qt-ui/subsurfacewebservices.cpp index 5170b3a40..c430deec6 100644 --- a/qt-ui/subsurfacewebservices.cpp +++ b/qt-ui/subsurfacewebservices.cpp @@ -49,7 +49,7 @@ static bool merge_locations_into_dives(void) sort_table(&gps_location_table); - for_each_gps_location(i, gpsfix) { + for_each_gps_location (i, gpsfix) { if (is_automatic_fix(gpsfix)) { dive = find_dive_including(gpsfix->when); if (dive && !dive_has_gps_location(dive)) { @@ -133,7 +133,9 @@ bool DivelogsDeWebServices::prepare_dives_for_divelogs(const QString &tempfile, } /* walk the dive list in chronological order */ - for (int i = 0; i < dive_table.nr; i++) { + int i; + struct dive *dive; + for_each_dive (i, dive) { FILE *f; char filename[PATH_MAX]; int streamsize; @@ -145,9 +147,6 @@ bool DivelogsDeWebServices::prepare_dives_for_divelogs(const QString &tempfile, * 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(); @@ -527,8 +526,8 @@ static DiveListResult parseDiveLogsDeDiveList(const QByteArray &xmlData) if (reader.readNextStartElement() && reader.name() != "DiveDateReader") { result.errorCondition = invalidXmlError; result.errorDetails = - DivelogsDeWebServices::tr("Expected XML tag 'DiveDateReader', got instead '%1") - .arg(reader.name().toString()); + DivelogsDeWebServices::tr("Expected XML tag 'DiveDateReader', got instead '%1") + .arg(reader.name().toString()); goto out; } @@ -581,8 +580,8 @@ out: // if there was an XML error, overwrite the result or other error conditions result.errorCondition = invalidXmlError; result.errorDetails = DivelogsDeWebServices::tr("Malformed XML response. Line %1: %2") - .arg(reader.lineNumber()) - .arg(reader.errorString()); + .arg(reader.lineNumber()) + .arg(reader.errorString()); } return result; } @@ -602,11 +601,11 @@ void DivelogsDeWebServices::downloadDives() exec(); } -void DivelogsDeWebServices::prepareDivesForUpload() +void DivelogsDeWebServices::prepareDivesForUpload(bool selected) { /* generate a random filename and create/open that file with zip_open */ QString filename = QDir::tempPath() + "/import-" + QString::number(qrand() % 99999999) + ".dld"; - if (prepare_dives_for_divelogs(filename, true)) { + if (prepare_dives_for_divelogs(filename, selected)) { QFile f(filename); if (f.open(QIODevice::ReadOnly)) { uploadDives((QIODevice *)&f); diff --git a/qt-ui/subsurfacewebservices.h b/qt-ui/subsurfacewebservices.h index 4419b1c6b..a9a67de46 100644 --- a/qt-ui/subsurfacewebservices.h +++ b/qt-ui/subsurfacewebservices.h @@ -71,7 +71,7 @@ class DivelogsDeWebServices : public WebServices { public: static DivelogsDeWebServices *instance(); void downloadDives(); - void prepareDivesForUpload(); + void prepareDivesForUpload(bool selected); private slots: diff --git a/qt-ui/tagwidget.cpp b/qt-ui/tagwidget.cpp index dfeeac537..8c45dceec 100644 --- a/qt-ui/tagwidget.cpp +++ b/qt-ui/tagwidget.cpp @@ -4,8 +4,9 @@ #include <QAbstractItemView> #include <QSettings> #include <QFont> +#include "mainwindow.h" -TagWidget::TagWidget(QWidget *parent) : GroupedLineEdit(parent), m_completer(NULL) +TagWidget::TagWidget(QWidget *parent) : GroupedLineEdit(parent), m_completer(NULL), lastFinishedTag(false) { connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(reparse())); connect(this, SIGNAL(textChanged()), this, SLOT(reparse())); @@ -137,13 +138,13 @@ void TagWidget::reparse() } } -void TagWidget::completionSelected(const QString& completion) +void TagWidget::completionSelected(const QString &completion) { completionHighlighted(completion); emit textChanged(); } -void TagWidget::completionHighlighted(const QString& completion) +void TagWidget::completionHighlighted(const QString &completion) { QPair<int, int> pos = getCursorTagPosition(); setText(text().remove(pos.first, pos.second - pos.first).insert(pos.first, completion)); @@ -157,7 +158,7 @@ void TagWidget::setCursorPosition(int position) blockSignals(false); } -void TagWidget::setText(const QString& text) +void TagWidget::setText(const QString &text) { blockSignals(true); GroupedLineEdit::setText(text); @@ -176,6 +177,7 @@ void TagWidget::keyPressEvent(QKeyEvent *e) { QPair<int, int> pos; QAbstractItemView *popup; + bool finishedTag = false; switch (e->key()) { case Qt::Key_Escape: pos = getCursorTagPosition(); @@ -183,7 +185,7 @@ void TagWidget::keyPressEvent(QKeyEvent *e) setText(text().remove(pos.first, pos.second - pos.first)); setCursorPosition(pos.first); } - popup= m_completer->popup(); + popup = m_completer->popup(); if (popup) popup->hide(); return; @@ -199,13 +201,17 @@ void TagWidget::keyPressEvent(QKeyEvent *e) if (popup) popup->hide(); } + finishedTag = true; } - if (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Return) { // let's pretend this is a comma instead + if (e->key() == Qt::Key_Tab && lastFinishedTag) { // if we already end in comma, go to next/prev field + MainWindow::instance()->information()->nextInputField(e); // by sending the key event to the MainTab widget + } else if (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Return) { // otherwise let's pretend this is a comma instead QKeyEvent fakeEvent(e->type(), Qt::Key_Comma, e->modifiers(), QString(",")); GroupedLineEdit::keyPressEvent(&fakeEvent); } else { GroupedLineEdit::keyPressEvent(e); } + lastFinishedTag = finishedTag; } void TagWidget::wheelEvent(QWheelEvent *event) diff --git a/qt-ui/tagwidget.h b/qt-ui/tagwidget.h index 62fa36f30..08984f712 100644 --- a/qt-ui/tagwidget.h +++ b/qt-ui/tagwidget.h @@ -12,21 +12,22 @@ public: void setCompleter(QCompleter *completer); QPair<int, int> getCursorTagPosition(); void highlight(); - void setText(const QString& text); + void setText(const QString &text); void clear(); void setCursorPosition(int position); void wheelEvent(QWheelEvent *event); public slots: void reparse(); - void completionSelected(const QString& text); - void completionHighlighted(const QString& text); + void completionSelected(const QString &text); + void completionHighlighted(const QString &text); protected: void keyPressEvent(QKeyEvent *e); private: QCompleter *m_completer; + bool lastFinishedTag; }; #endif // TAGWIDGET_H diff --git a/qt-ui/updatemanager.cpp b/qt-ui/updatemanager.cpp index bcf58088d..75f454795 100644 --- a/qt-ui/updatemanager.cpp +++ b/qt-ui/updatemanager.cpp @@ -4,11 +4,10 @@ #include "subsurfacewebservices.h" #include "ssrf-version.h" -UpdateManager::UpdateManager(QObject *parent) : - QObject(parent) +UpdateManager::UpdateManager(QObject *parent) : QObject(parent) { manager = SubsurfaceWebServices::manager(); - connect (manager, SIGNAL(finished(QNetworkReply*)), SLOT(requestReceived(QNetworkReply*))); + connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(requestReceived(QNetworkReply *))); } void UpdateManager::checkForUpdates() diff --git a/qt-ui/updatemanager.h b/qt-ui/updatemanager.h index 18b47cfde..561c53d0b 100644 --- a/qt-ui/updatemanager.h +++ b/qt-ui/updatemanager.h @@ -6,16 +6,17 @@ class QNetworkAccessManager; class QNetworkReply; -class UpdateManager : public QObject -{ +class UpdateManager : public QObject { Q_OBJECT public: explicit UpdateManager(QObject *parent = 0); void checkForUpdates(); + private: QNetworkAccessManager *manager; -public slots: - void requestReceived(QNetworkReply* reply); +public +slots: + void requestReceived(QNetworkReply *reply); }; #endif // UPDATEMANAGER_H diff --git a/qt-ui/usermanual.cpp b/qt-ui/usermanual.cpp index 0dd39af33..60c94382f 100644 --- a/qt-ui/usermanual.cpp +++ b/qt-ui/usermanual.cpp @@ -11,9 +11,9 @@ UserManual::UserManual(QWidget *parent) : QMainWindow(parent), { ui->setupUi(this); - QShortcut* closeKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this); + QShortcut *closeKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this); connect(closeKey, SIGNAL(activated()), this, SLOT(close())); - QShortcut* quitKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this); + QShortcut *quitKey = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this); connect(quitKey, SIGNAL(activated()), parent, SLOT(close())); QAction *actionShowSearch = new QAction(this); diff --git a/qt-ui/usermanual.h b/qt-ui/usermanual.h index 7692a1143..de8770eba 100644 --- a/qt-ui/usermanual.h +++ b/qt-ui/usermanual.h @@ -4,8 +4,7 @@ #include <QMainWindow> #include <QWebPage> -namespace Ui -{ +namespace Ui { class UserManual; } diff --git a/qthelper.cpp b/qthelper.cpp index 101530dba..bcf78b5d1 100644 --- a/qthelper.cpp +++ b/qthelper.cpp @@ -6,12 +6,10 @@ #include <QDebug> #include <QSettings> #include <libxslt/documents.h> -#include "mainwindow.h" #define tr(_arg) QObject::tr(_arg) - QString weight_string(int weight_in_grams) { QString str; @@ -88,39 +86,39 @@ bool parseGpsText(const QString &gps_text, double *latitude, double *longitude) gpsStyle = ISO6709D; regExp = QString("(\\d+)[" UTF8_DEGREE "\\s](\\d+)[\'\\s](\\d+)([,\\.](\\d+))?[\"\\s]([NS%1%2])" "\\s*(\\d+)[" UTF8_DEGREE "\\s](\\d+)[\'\\s](\\d+)([,\\.](\\d+))?[\"\\s]([EW%3%4])") - .arg(trHemisphere[0]) - .arg(trHemisphere[1]) - .arg(trHemisphere[2]) - .arg(trHemisphere[3]); + .arg(trHemisphere[0]) + .arg(trHemisphere[1]) + .arg(trHemisphere[2]) + .arg(trHemisphere[3]); } else if (gps_text.count(QChar('"')) == 2) { gpsStyle = SECONDS; regExp = QString("\\s*([NS%1%2])\\s*(\\d+)[" UTF8_DEGREE "\\s]+(\\d+)[\'\\s]+(\\d+)([,\\.](\\d+))?[^EW%3%4]*" "([EW%5%6])\\s*(\\d+)[" UTF8_DEGREE "\\s]+(\\d+)[\'\\s]+(\\d+)([,\\.](\\d+))?") - .arg(trHemisphere[0]) - .arg(trHemisphere[1]) - .arg(trHemisphere[2]) - .arg(trHemisphere[3]) - .arg(trHemisphere[2]) - .arg(trHemisphere[3]); + .arg(trHemisphere[0]) + .arg(trHemisphere[1]) + .arg(trHemisphere[2]) + .arg(trHemisphere[3]) + .arg(trHemisphere[2]) + .arg(trHemisphere[3]); } else if (gps_text.count(QChar('\'')) == 2) { gpsStyle = MINUTES; regExp = QString("\\s*([NS%1%2])\\s*(\\d+)[" UTF8_DEGREE "\\s]+(\\d+)([,\\.](\\d+))?[^EW%3%4]*" "([EW%5%6])\\s*(\\d+)[" UTF8_DEGREE "\\s]+(\\d+)([,\\.](\\d+))?") - .arg(trHemisphere[0]) - .arg(trHemisphere[1]) - .arg(trHemisphere[2]) - .arg(trHemisphere[3]) - .arg(trHemisphere[2]) - .arg(trHemisphere[3]); + .arg(trHemisphere[0]) + .arg(trHemisphere[1]) + .arg(trHemisphere[2]) + .arg(trHemisphere[3]) + .arg(trHemisphere[2]) + .arg(trHemisphere[3]); } else { gpsStyle = DECIMAL; regExp = QString("\\s*([-NS%1%2]?)\\s*(\\d+)[,\\.](\\d+)[^-EW%3%4\\d]*([-EW%5%6]?)\\s*(\\d+)[,\\.](\\d+)") - .arg(trHemisphere[0]) - .arg(trHemisphere[1]) - .arg(trHemisphere[2]) - .arg(trHemisphere[3]) - .arg(trHemisphere[2]) - .arg(trHemisphere[3]); + .arg(trHemisphere[0]) + .arg(trHemisphere[1]) + .arg(trHemisphere[2]) + .arg(trHemisphere[3]) + .arg(trHemisphere[2]) + .arg(trHemisphere[3]); } QRegExp r(regExp); if (r.indexIn(gps_text) != -1) { diff --git a/save-git.c b/save-git.c index 3fd8807c6..6abba601a 100644 --- a/save-git.c +++ b/save-git.c @@ -845,14 +845,23 @@ static void create_commit_message(struct membuffer *msg) if (dive) { dive_trip_t *trip = dive->divetrip; const char *location = dive->location ? : "no location"; + struct divecomputer *dc = &dive->dc; + const char *sep = "\n"; if (dive->number) nr = dive->number; put_format(msg, "dive %d: %s", nr, location); - if (trip->location && *trip->location && strcmp(trip->location, location)) + if (trip && trip->location && *trip->location && strcmp(trip->location, location)) put_format(msg, " (%s)", trip->location); - put_format(msg, "\n\n"); + put_format(msg, "\n"); + do { + if (dc->model && *dc->model) { + put_format(msg, "%s%s", sep, dc->model); + sep = ", "; + } + } while ((dc = dc->next) != NULL); + put_format(msg, "\n"); } put_format(msg, "Created by subsurface %s\n", VERSION_STRING); } diff --git a/save-xml.c b/save-xml.c index ddaa8cd2a..e52cfdffd 100644 --- a/save-xml.c +++ b/save-xml.c @@ -392,12 +392,8 @@ void save_one_dive(struct membuffer *b, struct dive *dive) save_weightsystem_info(b, dive); save_dive_temperature(b, dive); /* Save the dive computer data */ - dc = &dive->dc; - do { + for_each_dc(dive, dc) save_dc(b, dive, dc); - dc = dc->next; - } while (dc); - put_format(b, "</dive>\n"); } diff --git a/scripts/whitespace.pl b/scripts/whitespace.pl index cc7c6511b..3131d22d4 100755 --- a/scripts/whitespace.pl +++ b/scripts/whitespace.pl @@ -3,17 +3,23 @@ my $input = $ARGV[0]; my $source = `clang-format $input`; # for_each_dive (...) and Q_FOREACH and friends... -$source =~ s/^(.*each.*\(.*\).*)\n\s*{\s*$/$1 {/img; +$source =~ s/(?:\G|^)(.*each.*\(.*) \* (\S.*\))$/$1 *$2/img; # if a variable is declared in the argument, '*' is an indicator for a pointer, not arithmatic +$source =~ s/(?:\G|^)(.*each.*\(.*) \& (\S.*\))$/$1 &$2/img; # if a variable is declared in the argument, '&' is an indicator for a reference, not bit logic +$source =~ s/(?:\G|^)(.*each[^\s(]*)\s*(\(.*)$/$1 $2/img; # we want exactly one space between keyword and opening parenthesis '(' +$source =~ s/(?:\G|^)(.*each.*\(.*\).*)\n\s*{\s*$/$1 {/img; # we want the opening curly brace on the same line, separated by a space $source =~ s/(?:\G|^)(\s+[^#\/*].*each.*\(.*\))\n(\s*)([^{}\s])/$1\n\t$2$3/img; +# don't have '{' in the next line when declaring data types $source =~ s/^(\s*struct[^()\n]*)\n\s*{\s*$/$1 {/img; $source =~ s/^(\s*static\s+struct[^()\n]*)\n\s*{\s*$/$1 {/img; $source =~ s/^(\s*union[^()\n]*)\n\s*{\s*$/$1 {/img; $source =~ s/^(\s*static\s+union[^()\n]*)\n\s*{\s*$/$1 {/img; $source =~ s/^(\s*class.*)\n\s*{\s*$/$1 {/img; +# a namespace shouldn't look like a function +$source =~ s/(?:\G|^)(namespace.*)\n{/$1 {/img; # colon goes at the end of a line $source =~ s/^(\S*::\S*.*)\n\s*: /$1 : /img; -# odd indentations from flang-format: +# odd indentations from clang-format: # six spaces or four spaces after tabs (for continuation strings) $source =~ s/(?:\G|^)[ ]{6}/\t/mg; $source =~ s/(?:\G|^)(\t*)[ ]{4}"/$1\t"/mg; @@ -23,15 +29,16 @@ $source =~ s/(?:\G|^)(\t*)[ ]{4}"/$1\t"/mg; # from? # I couldn't figure out how to make it apply to an arbitrary number of # intermediate lines, so I hardcoded 0 through 5 lines between the #define -# or #id defined statements and the end of the multi line statement +# or #if defined statements and the end of the multi line statement $source =~ s/^(#(?:if |)define.*)\n +([^*].*)$/$1\n\t$2/mg; $source =~ s/^(#(?:if |)define.*)((?:\\\n.*){1})\n +([^*].*)$/$1$2\n\t$3/mg; $source =~ s/^(#(?:if |)define.*)((?:\\\n.*){2})\n +([^*].*)$/$1$2\n\t$3/mg; $source =~ s/^(#(?:if |)define.*)((?:\\\n.*){3})\n +([^*].*)$/$1$2\n\t$3/mg; $source =~ s/^(#(?:if |)define.*)((?:\\\n.*){4})\n +([^*].*)$/$1$2\n\t$3/mg; $source =~ s/^(#(?:if |)define.*)((?:\\\n.*){5})\n +([^*].*)$/$1$2\n\t$3/mg; -# don't put line break before the last single term argument of a -# calculation +# don't put line break before the last single term argument of a calculation $source =~ s/(?:\G|^)(.*[+-])\n\s*(\S*\;)$/$1 $2/mg; -open (DIFF, "| diff -u $input -"); +$quotedinput = $input; +$quotedinput =~ s|/|\\/|g; +open (DIFF, "| diff -u $input - | sed -e 's/--- $quotedinput/--- $quotedinput.old/' | sed -e 's/+++ -/+++ $quotedinput/'"); print DIFF $source ; diff --git a/statistics.c b/statistics.c index 2a96efb81..71150159c 100644 --- a/statistics.c +++ b/statistics.c @@ -131,8 +131,7 @@ void process_all_dives(struct dive *dive, struct dive **prev_dive) /* this relies on the fact that the dives in the dive_table * are in chronological order */ - for (idx = 0; idx < dive_table.nr; idx++) { - dp = dive_table.dives[idx]; + for_each_dive (idx, dp) { if (dive && dp->when == dive->when) { /* that's the one we are showing */ if (idx > 0) @@ -230,10 +229,10 @@ static void get_ranges(char *buffer, int size) { int i, len; int first = -1, last = -1; + struct dive *dive; snprintf(buffer, size, "%s", translate("gettextFromC", "for dives #")); - for (i = 0; i < dive_table.nr; i++) { - struct dive *dive = get_dive(i); + for_each_dive (i, dive) { if (!dive->selected) continue; if (dive->number < 1) { @@ -295,12 +294,12 @@ void get_selected_dives_text(char *buffer, int size) static bool is_gas_used(struct dive *dive, int idx) { - struct divecomputer *dc = &dive->dc; + struct divecomputer *dc; bool firstGasExplicit = false; if (cylinder_none(&dive->cylinder[idx])) return false; - while (dc) { + for_each_dc(dive, dc) { struct event *event = get_next_event(dc->events, "gaschange"); while (event) { if (event->time.seconds < 30) @@ -309,7 +308,6 @@ static bool is_gas_used(struct dive *dive, int idx) return true; event = get_next_event(event->next, "gaschange"); } - dc = dc->next; } if (idx == 0 && !firstGasExplicit) return true; diff --git a/subsurface.pro b/subsurface.pro index 7762318c5..83dea66a4 100644 --- a/subsurface.pro +++ b/subsurface.pro @@ -83,7 +83,8 @@ HEADERS = \ qt-ui/profile/diveeventitem.h \ qt-ui/profile/divetooltipitem.h \ qt-ui/profile/ruleritem.h \ - qt-ui/updatemanager.h + qt-ui/updatemanager.h \ + qt-ui/divelogexportdialog.h android: HEADERS -= \ qt-ui/usermanual.h \ @@ -157,7 +158,8 @@ SOURCES = \ qt-ui/profile/diveeventitem.cpp \ qt-ui/profile/divetooltipitem.cpp \ qt-ui/profile/ruleritem.cpp \ - qt-ui/updatemanager.cpp + qt-ui/updatemanager.cpp \ + qt-ui/divelogexportdialog.cpp android: SOURCES += android.cpp else: linux*: SOURCES += linux.c @@ -185,7 +187,8 @@ FORMS = \ qt-ui/webservices.ui \ qt-ui/tableview.ui \ qt-ui/divelogimportdialog.ui \ - qt-ui/usermanual.ui + qt-ui/usermanual.ui \ + qt-ui/divelogexportdialog.ui # Nether usermanual or printing is supported on android right now android: FORMS -= qt-ui/usermanual.ui qt-ui/printoptions.ui diff --git a/subsurfacestartup.c b/subsurfacestartup.c index 471fea64e..4ae426d1c 100644 --- a/subsurfacestartup.c +++ b/subsurfacestartup.c @@ -149,13 +149,14 @@ void parse_argument(const char *arg) } while (*++p); } -void renumber_dives(int nr) +void renumber_dives(int start_nr, bool selected_only) { - int i; + int i, nr = start_nr; + struct dive *dive; - for (i = 0; i < dive_table.nr; i++) { - struct dive *dive = dive_table.dives[i]; - dive->number = nr + i; + for_each_dive (i, dive) { + if (dive->selected) + dive->number = nr++; } mark_divelist_changed(true); } diff --git a/uemis-downloader.c b/uemis-downloader.c index d0c3de13e..5d8b07c01 100644 --- a/uemis-downloader.c +++ b/uemis-downloader.c @@ -793,14 +793,14 @@ static char *uemis_get_divenr(char *deviceidstr) char divenr[10]; deviceid = atoi(deviceidstr); - for (i = 0; i < dive_table.nr; i++) { - struct divecomputer *dc = &dive_table.dives[i]->dc; - while (dc) { + struct dive *d; + for_each_dive (i, d) { + struct divecomputer *dc; + for_each_dc(d, dc) { if (dc->model && !strcmp(dc->model, "Uemis Zurich") && (dc->deviceid == 0 || dc->deviceid == 0x7fffffff || dc->deviceid == deviceid) && dc->diveid > maxdiveid) maxdiveid = dc->diveid; - dc = dc->next; } } snprintf(divenr, 10, "%d", maxdiveid); @@ -1,6 +1,8 @@ #ifndef UNITS_H #define UNITS_H +#include <math.h> + #ifdef __cplusplus extern "C" { #endif @@ -36,56 +36,91 @@ const char *system_default_filename(void) return buffer; } -int enumerate_devices(device_callback_t callback, void *userdata) +int enumerate_devices(device_callback_t callback, void *userdata, int dc_type) { - // Open the registry key. - HKEY hKey; int index = -1; - LONG rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey); - if (rc != ERROR_SUCCESS) { - return -1; - } - - // Get the number of values. - DWORD count = 0; - rc = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL); - if (rc != ERROR_SUCCESS) { - RegCloseKey(hKey); - return -1; - } DWORD i; - for (i = 0; i < count; ++i) { - // Get the value name, data and type. - char name[512], data[512]; - DWORD name_len = sizeof(name); - DWORD data_len = sizeof(data); - DWORD type = 0; - rc = RegEnumValue(hKey, i, name, &name_len, NULL, &type, (LPBYTE)data, &data_len); + if (dc_type != DC_TYPE_UEMIS) { + // Open the registry key. + HKEY hKey; + LONG rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey); if (rc != ERROR_SUCCESS) { - RegCloseKey(hKey); return -1; } - // Ignore non-string values. - if (type != REG_SZ) - continue; - - // Prevent a possible buffer overflow. - if (data_len >= sizeof(data)) { + // Get the number of values. + DWORD count = 0; + rc = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL); + if (rc != ERROR_SUCCESS) { RegCloseKey(hKey); return -1; } + for (i = 0; i < count; ++i) { + // Get the value name, data and type. + char name[512], data[512]; + DWORD name_len = sizeof(name); + DWORD data_len = sizeof(data); + DWORD type = 0; + rc = RegEnumValue(hKey, i, name, &name_len, NULL, &type, (LPBYTE)data, &data_len); + if (rc != ERROR_SUCCESS) { + RegCloseKey(hKey); + return -1; + } - // Null terminate the string. - data[data_len] = 0; + // Ignore non-string values. + if (type != REG_SZ) + continue; - callback(data, userdata); - index++; - if (is_default_dive_computer_device(name)) - index = i; + // Prevent a possible buffer overflow. + if (data_len >= sizeof(data)) { + RegCloseKey(hKey); + return -1; + } + + // Null terminate the string. + data[data_len] = 0; + + callback(data, userdata); + index++; + if (is_default_dive_computer_device(name)) + index = i; + } + + RegCloseKey(hKey); } + if (dc_type != DC_TYPE_SERIAL) { + int i; + int count_drives = 0; + const int bufdef = 512; + const char *dlabels[] = {"UEMISSDA", NULL}; + char bufname[bufdef], bufval[bufdef], *p; + DWORD bufname_len; + + /* add drive letters that match labels */ + memset(bufname, 0, bufdef); + bufname_len = bufdef; + if (GetLogicalDriveStringsA(bufname_len, bufname)) { + p = bufname; - RegCloseKey(hKey); + while (*p) { + memset(bufval, 0, bufdef); + if (GetVolumeInformationA(p, bufval, bufdef, NULL, NULL, NULL, NULL, 0)) { + for (i = 0; dlabels[i] != NULL; i++) + if (!strcmp(bufval, dlabels[i])) { + char data[512]; + snprintf(data, sizeof(data), "%s (%s)", p, dlabels[i]); + callback(data, userdata); + if (is_default_dive_computer_device(p)) + index = count_drives; + count_drives++; + } + } + p = &p[strlen(p) + 1]; + } + if (count_drives == 1) /* we found exactly one Uemis "drive" */ + index = 0; /* make it the selected "device" */ + } + } return index; } diff --git a/worldmap-options.h b/worldmap-options.h index 6e7e8728b..177443563 100644 --- a/worldmap-options.h +++ b/worldmap-options.h @@ -1,7 +1,7 @@ #ifndef WORLDMAP_OPTIONS_H #define WORLDMAP_OPTIONS_H -const char* map_options = "center: new google.maps.LatLng(0,0),\n\tzoom: 3,\n\tminZoom: 2,\n\tmapTypeId: google.maps.MapTypeId.SATELLITE\n\t"; -const char* css = "\n\thtml { height: 100% }\n\tbody { height: 100%; margin: 0; padding: 0 }\n\t#map-canvas { height: 100% }\n"; +const char *map_options = "center: new google.maps.LatLng(0,0),\n\tzoom: 3,\n\tminZoom: 2,\n\tmapTypeId: google.maps.MapTypeId.SATELLITE\n\t"; +const char *css = "\n\thtml { height: 100% }\n\tbody { height: 100%; margin: 0; padding: 0 }\n\t#map-canvas { height: 100% }\n"; -#endif// WORLDMAP-OPTIONS_H +#endif // WORLDMAP-OPTIONS_H diff --git a/worldmap-save.c b/worldmap-save.c index e867846f5..b82ccd3eb 100644 --- a/worldmap-save.c +++ b/worldmap-save.c @@ -6,6 +6,7 @@ #include "membuffer.h" #include "worldmap-save.h" #include "worldmap-options.h" +#include "gettext.h" char *getGoogleApi() { @@ -17,14 +18,20 @@ void put_HTML_date(struct membuffer *b, struct dive *dive) { struct tm tm; utc_mkdate(dive->when, &tm); - put_format(b, "<p>date=%04u-%02u-%02u</p>", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - put_format(b, "<p>time=%02u:%02u:%02u</p>", tm.tm_hour, tm.tm_min, tm.tm_sec); + put_format(b, "<p>%s: %04u-%02u-%02u</p>", translate("gettextFromC", "Date"), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + put_format(b, "<p>%s: %02u:%02u:%02u</p>", translate("gettextFromC", "Time"), tm.tm_hour, tm.tm_min, tm.tm_sec); } void put_HTML_temp(struct membuffer *b, struct dive *dive) { - put_temperature(b, dive->airtemp, "<p>Air Temp: ", " C\\'</p>"); - put_temperature(b, dive->watertemp, "<p>Water Temp: ", " C\\'</p>"); + const char *unit; + double value; + + value = get_temp_units(dive->airtemp.mkelvin, &unit); + put_format(b, "<p>%s: %.1f %s</p>", translate("gettextFromC", "Air Temp"), value, unit); + + value = get_temp_units(dive->watertemp.mkelvin, &unit); + put_format(b, "<p>%s: %.1f %s</p>", translate("gettextFromC", "Water Temp"), value, unit); } char *replace_char(char *str, char replace, char *replace_by) @@ -78,27 +85,31 @@ void put_HTML_notes(struct membuffer *b, struct dive *dive) { if (dive->notes) { char *notes = quote(dive->notes); - put_format(b, "<p>Notes : %s </p>", notes); + put_format(b, "<p>%s: %s </p>", translate("gettextFromC", "Notes"), notes); free(notes); } } -void writeMarkers(struct membuffer *b) +void writeMarkers(struct membuffer *b, const bool selected_only) { int i, dive_no = 0; struct dive *dive; for_each_dive(i, dive) { - /*export selected dives only ?*/ - + if (selected_only) { + if (!dive->selected) + continue; + } if (dive->latitude.udeg == 0 && dive->longitude.udeg == 0) continue; put_degrees(b, dive->latitude, "temp = new google.maps.Marker({position: new google.maps.LatLng(", ""); put_degrees(b, dive->longitude, ",", ")});\n"); put_string(b, "markers.push(temp);\ntempinfowindow = new google.maps.InfoWindow({content: '<div id=\"content\">'+'<div id=\"siteNotice\">'+'</div>'+'<div id=\"bodyContent\">"); + put_format(b, "<p><b>%s</b></p>", quote(dive->location)); put_HTML_date(b, dive); - put_duration(b, dive->duration, "<p>duration=", " min</p>"); + put_duration(b, dive->duration, translate("gettextFromC", "<p>Duration: "), translate("gettextFromC", " min</p>")); + put_depth(b, dive->maxdepth, translate("gettextFromC", "<p>Max Depth: "), translate("gettextFromC", " m</p>")); put_HTML_temp(b, dive); put_HTML_notes(b, dive); put_string(b, "</p>'+'</div>'+'</div>'});\ninfowindows.push(tempinfowindow);\n"); @@ -120,7 +131,7 @@ void insert_css(struct membuffer *b) put_format(b, "<style type=\"text/css\">%s</style>\n", css); } -void insert_javascript(struct membuffer *b) +void insert_javascript(struct membuffer *b, const bool selected_only) { put_string(b, "<script type=\"text/javascript\" src=\""); put_string(b, getGoogleApi()); @@ -129,25 +140,25 @@ void insert_javascript(struct membuffer *b) put_string(b, "rotateControl: false,\n\tstreetViewControl: false,\n\tmapTypeControl: false\n};\n"); put_string(b, "map = new google.maps.Map(document.getElementById(\"map-canvas\"),mapOptions);\nvar markers = new Array();"); put_string(b, "\nvar infowindows = new Array();\nvar temp;\nvar tempinfowindow;\n"); - writeMarkers(b); + writeMarkers(b, selected_only); put_string(b, "\nfor(var i=0;i<markers.length;i++)\n\tmarkers[i].setMap(map);\n}\n"); put_string(b, "google.maps.event.addDomListener(window, 'load', initialize);</script>\n"); } -void export(struct membuffer *b) +void export(struct membuffer *b, const bool selected_only) { insert_html_header(b); insert_css(b); - insert_javascript(b); + insert_javascript(b, selected_only); put_string(b, "\t</head>\n<body>\n<div id=\"map-canvas\"></div>\n</body>\n</html>"); } -void export_worldmap_HTML(const char *file_name) +void export_worldmap_HTML(const char *file_name, const bool selected_only) { FILE *f; struct membuffer buf = { 0 }; - export(&buf); + export(&buf, selected_only); f = fopen(file_name, "w+"); if (!f) diff --git a/worldmap-save.h b/worldmap-save.h index 72363e482..102ea40e5 100644 --- a/worldmap-save.h +++ b/worldmap-save.h @@ -5,7 +5,7 @@ extern "C" { #endif -extern void export_worldmap_HTML(const char* x); +extern void export_worldmap_HTML(const char *file_name, const bool selected_only); #ifdef __cplusplus |